11"""
2- Wrappers for the Matlab compatibility module
2+ Wrappers for the MATLAB compatibility module
33"""
44
55import numpy as np
66from ..statesp import ss
77from ..xferfcn import tf
8+ from ..ctrlutil import issys
9+ from ..exception import ControlArgument
810from scipy .signal import zpk2tf
11+ from warnings import warn
912
10- __all__ = ['bode' , 'ngrid' , 'dcgain' ]
13+ __all__ = ['bode' , 'nyquist' , ' ngrid' , 'dcgain' ]
1114
12- def bode (* args , ** keywords ):
15+ def bode (* args , ** kwargs ):
1316 """bode(syslist[, omega, dB, Hz, deg, ...])
1417
1518 Bode plot of the frequency response
@@ -36,7 +39,7 @@ def bode(*args, **keywords):
3639 If True, plot frequency in Hz (omega must be provided in rad/sec)
3740 deg : boolean
3841 If True, return phase in degrees (else radians)
39- Plot : boolean
42+ plot : boolean
4043 If True, plot magnitude and phase
4144
4245 Examples
@@ -53,19 +56,65 @@ def bode(*args, **keywords):
5356 * >>> bode(sys1, sys2, ..., sysN, w)
5457 * >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN')
5558 """
59+ from ..freqplot import bode_plot
5660
57- # If the first argument is a list, then assume python-control calling format
58- from ..freqplot import bode as bode_orig
61+ # If first argument is a list, assume python-control calling format
5962 if (getattr (args [0 ], '__iter__' , False )):
60- return bode_orig (* args , ** keywords )
63+ return bode_plot (* args , ** kwargs )
6164
62- # Otherwise, run through the arguments and collect up arguments
63- syslist = []; plotstyle = []; omega = None ;
65+ # Parse input arguments
66+ syslist , omega , args , other = _parse_freqplot_args (* args )
67+ kwargs .update (other )
68+
69+ # Call the bode command
70+ return bode_plot (syslist , omega , * args , ** kwargs )
71+
72+
73+ def nyquist (* args , ** kwargs ):
74+ """nyquist(syslist[, omega])
75+
76+ Nyquist plot of the frequency response
77+
78+ Plots a Nyquist plot for the system over a (optional) frequency range.
79+
80+ Parameters
81+ ----------
82+ sys1, ..., sysn : list of LTI
83+ List of linear input/output systems (single system is OK).
84+ omega : array_like
85+ Set of frequencies to be evaluated, in rad/sec.
86+
87+ Returns
88+ -------
89+ real : ndarray (or list of ndarray if len(syslist) > 1))
90+ real part of the frequency response array
91+ imag : ndarray (or list of ndarray if len(syslist) > 1))
92+ imaginary part of the frequency response array
93+ omega : ndarray (or list of ndarray if len(syslist) > 1))
94+ frequencies in rad/s
95+
96+ """
97+ from ..freqplot import nyquist_plot
98+
99+ # If first argument is a list, assume python-control calling format
100+ if (getattr (args [0 ], '__iter__' , False )):
101+ return nyquist_plot (* args , ** kwargs )
102+
103+ # Parse arguments
104+ syslist , omega , args , other = _parse_freqplot_args (* args )
105+ kwargs .update (other )
106+
107+ # Call the nyquist command
108+ return nyquist_plot (syslist , omega , * args , ** kwargs )
109+
110+
111+ def _parse_freqplot_args (* args ):
112+ """Parse arguments to frequency plot routines (bode, nyquist)"""
113+ syslist , plotstyle , omega , other = [], [], None , {}
64114 i = 0 ;
65115 while i < len (args ):
66116 # Check to see if this is a system of some sort
67- from ..ctrlutil import issys
68- if (issys (args [i ])):
117+ if issys (args [i ]):
69118 # Append the system to our list of systems
70119 syslist .append (args [i ])
71120 i += 1
@@ -79,11 +128,16 @@ def bode(*args, **keywords):
79128 continue
80129
81130 # See if this is a frequency list
82- elif ( isinstance (args [i ], (list , np .ndarray ) )):
131+ elif isinstance (args [i ], (list , np .ndarray )):
83132 omega = args [i ]
84133 i += 1
85134 break
86135
136+ # See if this is a frequency range
137+ elif isinstance (args [i ], tuple ) and len (args [i ]) == 2 :
138+ other ['omega_limits' ] = args [i ]
139+ i += 1
140+
87141 else :
88142 raise ControlArgument ("unrecognized argument type" )
89143
@@ -93,22 +147,30 @@ def bode(*args, **keywords):
93147
94148 # Check to make sure we got the same number of plotstyles as systems
95149 if (len (plotstyle ) != 0 and len (syslist ) != len (plotstyle )):
96- raise ControlArgument ("number of systems and plotstyles should be equal" )
150+ raise ControlArgument (
151+ "number of systems and plotstyles should be equal" )
97152
98153 # Warn about unimplemented plotstyles
99154 #! TODO: remove this when plot styles are implemented in bode()
100155 #! TODO: uncomment unit test code that tests this out
101156 if (len (plotstyle ) != 0 ):
102- print ("Warning (matlab.bode): plot styles not implemented" );
157+ warn ("Warning (matlab.bode): plot styles not implemented" );
158+
159+ if len (syslist ) == 0 :
160+ raise ControlArgument ("no systems specified" )
161+ elif len (syslist ) == 1 :
162+ # If only one system given, retun just that system (not a list)
163+ syslist = syslist [0 ]
164+
165+ return syslist , omega , plotstyle , other
103166
104- # Call the bode command
105- return bode_orig (syslist , omega , ** keywords )
106167
107168from ..nichols import nichols_grid
108169def ngrid ():
109170 return nichols_grid ()
110171ngrid .__doc__ = nichols_grid .__doc__
111172
173+
112174def dcgain (* args ):
113175 '''
114176 Compute the gain of the system in steady state.
0 commit comments