-
Notifications
You must be signed in to change notification settings - Fork 458
Expand file tree
/
Copy pathwrappers.py
More file actions
229 lines (183 loc) · 6.85 KB
/
Copy pathwrappers.py
File metadata and controls
229 lines (183 loc) · 6.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
"""
Wrappers for the MATLAB compatibility module
"""
import numpy as np
from ..iosys import ss
from ..xferfcn import tf
from ..ctrlutil import issys
from ..exception import ControlArgument
from scipy.signal import zpk2tf
from warnings import warn
__all__ = ['bode', 'nyquist', 'ngrid', 'dcgain']
def bode(*args, **kwargs):
"""bode(syslist[, omega, dB, Hz, deg, ...])
Bode plot of the frequency response
Plots a bode gain and phase diagram
Parameters
----------
sys : LTI, or list of LTI
System for which the Bode response is plotted and give. Optionally
a list of systems can be entered, or several systems can be
specified (i.e. several parameters). The sys arguments may also be
interspersed with format strings. A frequency argument (array_like)
may also be added, some examples:
* >>> bode(sys, w) # one system, freq vector
* >>> bode(sys1, sys2, ..., sysN) # several systems
* >>> bode(sys1, sys2, ..., sysN, w)
* >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN') # + plot formats
omega: freq_range
Range of frequencies in rad/s
dB : boolean
If True, plot result in dB
Hz : boolean
If True, plot frequency in Hz (omega must be provided in rad/sec)
deg : boolean
If True, return phase in degrees (else radians)
plot : boolean
If True, plot magnitude and phase
Examples
--------
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = bode(sys)
.. todo::
Document these use cases
* >>> bode(sys, w)
* >>> bode(sys1, sys2, ..., sysN)
* >>> bode(sys1, sys2, ..., sysN, w)
* >>> bode(sys1, 'plotstyle1', ..., sysN, 'plotstyleN')
"""
from ..freqplot import bode_plot
# If first argument is a list, assume python-control calling format
if hasattr(args[0], '__iter__'):
return bode_plot(*args, **kwargs)
# Parse input arguments
syslist, omega, args, other = _parse_freqplot_args(*args)
kwargs.update(other)
# Call the bode command
return bode_plot(syslist, omega, *args, **kwargs)
def nyquist(*args, **kwargs):
"""nyquist(syslist[, omega])
Nyquist plot of the frequency response
Plots a Nyquist plot for the system over a (optional) frequency range.
Parameters
----------
sys1, ..., sysn : list of LTI
List of linear input/output systems (single system is OK).
omega : array_like
Set of frequencies to be evaluated, in rad/sec.
Returns
-------
real : ndarray (or list of ndarray if len(syslist) > 1))
real part of the frequency response array
imag : ndarray (or list of ndarray if len(syslist) > 1))
imaginary part of the frequency response array
omega : ndarray (or list of ndarray if len(syslist) > 1))
frequencies in rad/s
"""
from ..freqplot import nyquist_plot
# If first argument is a list, assume python-control calling format
if hasattr(args[0], '__iter__'):
return nyquist_plot(*args, **kwargs)
# Parse arguments
syslist, omega, args, other = _parse_freqplot_args(*args)
kwargs.update(other)
# Call the nyquist command
kwargs['return_contour'] = True
_, contour = nyquist_plot(syslist, omega, *args, **kwargs)
# Create the MATLAB output arguments
freqresp = syslist(contour)
real, imag = freqresp.real, freqresp.imag
return real, imag, contour.imag
def _parse_freqplot_args(*args):
"""Parse arguments to frequency plot routines (bode, nyquist)"""
syslist, plotstyle, omega, other = [], [], None, {}
i = 0;
while i < len(args):
# Check to see if this is a system of some sort
if issys(args[i]):
# Append the system to our list of systems
syslist.append(args[i])
i += 1
# See if the next object is a plotsytle (string)
if (i < len(args) and isinstance(args[i], str)):
plotstyle.append(args[i])
i += 1
# Go on to the next argument
continue
# See if this is a frequency list
elif isinstance(args[i], (list, np.ndarray)):
omega = args[i]
i += 1
break
# See if this is a frequency range
elif isinstance(args[i], tuple) and len(args[i]) == 2:
other['omega_limits'] = args[i]
i += 1
else:
raise ControlArgument("unrecognized argument type")
# Check to make sure that we processed all arguments
if (i < len(args)):
raise ControlArgument("not all arguments processed")
# Check to make sure we got the same number of plotstyles as systems
if (len(plotstyle) != 0 and len(syslist) != len(plotstyle)):
raise ControlArgument(
"number of systems and plotstyles should be equal")
# Warn about unimplemented plotstyles
#! TODO: remove this when plot styles are implemented in bode()
#! TODO: uncomment unit test code that tests this out
if (len(plotstyle) != 0):
warn("Warning (matlab.bode): plot styles not implemented");
if len(syslist) == 0:
raise ControlArgument("no systems specified")
elif len(syslist) == 1:
# If only one system given, retun just that system (not a list)
syslist = syslist[0]
return syslist, omega, plotstyle, other
from ..nichols import nichols_grid
def ngrid():
return nichols_grid()
ngrid.__doc__ = nichols_grid.__doc__
def dcgain(*args):
'''
Compute the gain of the system in steady state.
The function takes either 1, 2, 3, or 4 parameters:
Parameters
----------
A, B, C, D: array-like
A linear system in state space form.
Z, P, k: array-like, array-like, number
A linear system in zero, pole, gain form.
num, den: array-like
A linear system in transfer function form.
sys: LTI (StateSpace or TransferFunction)
A linear system object.
Returns
-------
gain: ndarray
The gain of each output versus each input:
:math:`y = gain \\cdot u`
Notes
-----
This function is only useful for systems with invertible system
matrix ``A``.
All systems are first converted to state space form. The function then
computes:
.. math:: gain = - C \\cdot A^{-1} \\cdot B + D
'''
#Convert the parameters to state space form
if len(args) == 4:
A, B, C, D = args
return ss(A, B, C, D).dcgain()
elif len(args) == 3:
Z, P, k = args
num, den = zpk2tf(Z, P, k)
return tf(num, den).dcgain()
elif len(args) == 2:
num, den = args
return tf(num, den).dcgain()
elif len(args) == 1:
sys, = args
return sys.dcgain()
else:
raise ValueError("Function ``dcgain`` needs either 1, 2, 3 or 4 "
"arguments.")