8000 new method is_static_gain() for state space and transfer function sys… · python-control/python-control@351e0f7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 351e0f7

Browse files
sawyerbfullerbnavigator
authored andcommitted
new method is_static_gain() for state space and transfer function systems, refactored __init__ on both to use it
1 parent 3b2ab18 commit 351e0f7

File tree

2 files changed

+59
-49
lines changed

2 files changed

+59
-49
lines changed

control/statesp.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class StateSpace(LTI):
170170
__array_priority__ = 11 # override ndarray and matrix types
171171

172172

173-
def __init__(self, *args, **kw):
173+
def __init__(self, *args, **kwargs):
174174
"""
175175
StateSpace(A, B, C, D[, dt])
176176
@@ -183,16 +183,13 @@ def __init__(self, *args, **kw):
183183
call StateSpace(sys), where sys is a StateSpace object.
184184
185185
"""
186+
# first get A, B, C, D matrices
186187
if len(args) == 4:
187188
# The user provided A, B, C, and D matrices.
188189
(A, B, C, D) = args
189-
if _isstaticgain(A, B, C, D):
190-
dt = None
191-
else:
192-
dt = config.defaults['control.default_dt']
193190
elif len(args) == 5:
194191
# Discrete time system
195-
(A, B, C, D, dt) = args
192+
(A, B, C, D, _) = args
196193
elif len(args) == 1:
197194
# Use the copy constructor.
198195
if not isinstance(args[0], StateSpace):
@@ -202,19 +199,12 @@ def __init__(self, *args, **kw):
202199
B = args[0].B
203200
C = args[0].C
204201
D = args[0].D
205-
try:
206-
dt = args[0].dt
207-
except NameError:
208-
if _isstaticgain(A, B, C, D):
209-
dt = None
210-
else:
211-
dt = config.defaults['control.default_dt']
212202
else:
213203
raise ValueError("Expected 1, 4, or 5 arguments; received %i." % len(args))
214204

215205
# Process keyword arguments
216-
remove_useless = kw.get('remove_useless',
217-
config.defaults['statesp.remove_useless_states'])
206+
remove_useless = kwargs.get('remove_useless',
207+
config.defaults['statesp.remove_useless_states'])
218208

219209
# Convert all matrices to standard form
220210
A = _ssmatrix(A)
@@ -233,12 +223,33 @@ def __init__(self, *args, **kw):
233223
D = _ssmatrix(D)
234224

235225
# TODO: use super here?
236-
LTI.__init__(self, inputs=D.shape[1], outputs=D.shape[0], dt=dt)
226+
LTI.__init__(self, inputs=D.shape[1], outputs=D.shape[0])
237227
self.A = A
238228
self.B = B
239229
self.C = C
240230
self.D = D
241231

232+
# now set dt
233+
if len(args) == 4:
234+
if 'dt' in kwargs:
235+
dt = kwargs['dt']
236+
elif self.is_static_gain():
237+
dt = None
238+
else:
239+
dt = config.defaults['control.default_dt']
240+
elif len(args) == 5:
241+
dt = args[4]
242+
if 'dt' in kwargs:
243+
warn('received multiple dt arguments, using positional arg'%dt)
244+
elif len(args) == 1:
245+
try:
246+
dt = args[0].dt
247+
except NameError:
248+
if self.is_static_gain():
249+
dt = None
250+
else:
251+
dt = config.defaults['control.default_dt']
252+
self.dt = dt
242253
self.states = A.shape[1]
243254

244255
if 0 == self.states:
@@ -953,6 +964,12 @@ def dcgain(self):
953964
gain = np.tile(np.nan, (self.outputs, self.inputs))
954965
return np.squeeze(gain)
955966

967+
def is_static_gain(self):
968+
"""True if and only if the system has no dynamics, that is,
969+
if A and B are zero. """
970+
return not np.any(self.A) and not np.any(self.B)
971+
972+
956973
def is_static_gain(self):
957974
"""True if and only if the system has no dynamics, that is,
958975
if A and B are zero. """
@@ -1273,12 +1290,6 @@ def _mimo2simo(sys, input, warn_conversion=False):
12731290

12741291
return sys
12751292

1276-
def _isstaticgain(A, B, C, D):
1277-
"""returns True if and only if the system has no dynamics, that is,
1278-
if A and B are zero. """
1279-
return not np.any(np.matrix(A, dtype=float)) \
1280-
and not np.any(np.matrix(B, dtype=float))
1281-
12821293
def ss(*args):
12831294
"""ss(A, B, C, D[, dt])
12841295

control/xferfcn.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class TransferFunction(LTI):
114114
>>> G = (s + 1)/(s**2 + 2*s + 1)
115115
"""
116116

117-
def __init__(self, *args):
117+
def __init__(self, *args, **kwargs):
118118
"""TransferFunction(num, den[, dt])
119119
120120
Construct a transfer function.
@@ -132,10 +132,6 @@ def __init__(self, *args):
132132
if len(args) == 2:
133133
# The user provided a numerator and a denominator.
134134
(num, den) = args
135-
if _isstaticgain(num, den):
136-
dt = None
137-
else:
138-
dt = config.defaults['control.default_dt']
139135
elif len(args) == 3:
140136
# Discrete time transfer function
141137
(num, den, dt) = args
@@ -147,14 +143,6 @@ def __init__(self, *args):
147143
% type(args[0]))
148144
num = args[0].num
149145
den = args[0].den
150-
# TODO: not sure this can ever happen since dt is always present
151-
try:
152-
dt = args[0].dt
153-
except NameError: # pragma: no coverage
154-
if _isstaticgain(num, den):
155-
dt = None
156-
else:
157-
dt = config.defaults['control.default_dt']
158146
else:
159147
raise ValueError("Needs 1, 2 or 3 arguments; received %i."
160148
% len(args))
@@ -212,12 +200,36 @@ def __init__(self, *args):
212200
if zeronum:
213201
den[i][j] = ones(1)
214202

215-
LTI.__init__(self, inputs, outputs, dt)
203+
LTI.__init__(self, inputs, outputs)
216204
self.num = num
217205
self.den = den
218206

219207
self._truncatecoeff()
220208

209+
# get dt
210+
if len(args) == 2:
211+
# no dt given in positional arguments
212+
if 'dt' in kwargs:
213+
dt = kwargs['dt']
214+
elif self.is_static_gain():
215+
dt = None
216+
else:
217+
dt = config.defaults['control.default_dt']
218+
elif len(args) == 3:
219+
# Discrete time transfer function
220+
if 'dt' in kwargs:
221+
warn('received multiple dt arguments, using positional arg'%dt)
222+
elif len(args) == 1:
223+
# TODO: not sure this can ever happen since dt is always present
224+
try:
225+
dt = args[0].dt
226+
except NameError: # pragma: no coverage
227+
if self.is_static_gain():
228+
dt = None
229+
else:
230+
dt = config.defaults['control.default_dt']
231+
self.dt = dt
232+
221233
def __call__(self, s):
222234
"""Evaluate the system's transfer function for a complex variable
223235
@@ -1572,19 +1584,6 @@ def _clean_part(data):
15721584

15731585
return data
15741586

1575-
def _isstaticgain(num, den):
1576-
"""returns True if and only if all of the numerator and denominator
1577-
polynomials of the (possibly MIMO) transfer funnction are zeroth order,
1578-
that is, if the system has no dynamics. """
1579-
num, den = _clean_part(num), _clean_part(den)
1580-
for list_of_polys in num, den:
1581-
for row in list_of_polys:
1582-
for poly in row:
1583-
poly_trimmed = np.trim_zeros(poly, 'f') # trim leading zeros
1584-
if len(poly_trimmed) > 1:
1585-
return False
1586-
return True
1587-
15881587
# Define constants to represent differentiation, unit delay
15891588
TransferFunction.s = TransferFunction([1, 0], [1], 0)
15901589
TransferFunction.z = TransferFunction([1, 0], [1], True)

0 commit comments

Comments
 (0)
0