10BC0 change infinite gain value to inf (from nan/inf) · python-control/python-control@b67eb7d · GitHub
[go: up one dir, main page]

Skip to content

Commit b67eb7d

Browse files
committed
change infinite gain value to inf (from nan/inf)
1 parent eb62d80 commit b67eb7d

File tree

3 files changed

+30
-17
lines changed

3 files changed

+30
-17
lines changed

control/statesp.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ def __rdiv__(self, other):
668668
raise NotImplementedError(
669669
"StateSpace.__rdiv__ is not implemented yet.")
670670

671-
def __call__(self, x, squeeze=None):
671+
def __call__(self, x, squeeze=None, warn_infinite=True):
672672
"""Evaluate system's transfer function at complex frequency.
673673
674674
Returns the complex frequency response `sys(x)` where `x` is `s` for
@@ -689,6 +689,8 @@ def __call__(self, x, squeeze=None):
689689
keep all indices (output, input and, if omega is array_like,
690690
frequency) even if the system is SISO. The default value can be
691691
set using config.defaults['control.squeeze_frequency_response'].
692+
warn_infinite : bool, optional
693+
If set to `False`, don't warn if frequency response is infinite.
692694
693695
Returns
694696
-------
@@ -702,7 +704,7 @@ def __call__(self, x, squeeze=None):
702704
703705
"""
704706
# Use Slycot if available
705-
out = self.horner(x)
707+
out = self.horner(x, warn_infinite=warn_infinite)
706708
return _process_frequency_response(self, x, out, squeeze=squeeze)
707709

708710
def slycot_laub(self, x):
@@ -758,7 +760,7 @@ def slycot_laub(self, x):
758760
out[:, :, kk+1] = result[0] + self.D
759761
return out
760762

761-
def horner(self, x):
763+
def horner(self, x, warn_infinite=True):
762764
"""Evaluate system's transfer function at complex frequency
763765
using Laub's or Horner's method.
764766
@@ -795,14 +797,22 @@ def horner(self, x):
795797
raise ValueError("input list must be 1D")
796798

797799
# Preallocate
798-
out = empty((self.noutputs, self.ninputs, len(x_arr)), dtype=complex)
800+
out = empty((self.noutputs, self.ninputs, len(x_arr)),
801+
dtype=complex)
799802

800803
#TODO: can this be vectorized?
801804
for idx, x_idx in enumerate(x_arr):
802-
out[:,:,idx] = \
803-
np.dot(self.C,
805+
try:
806+
out[:,:,idx] = np.dot(
807+
self.C,
804808
solve(x_idx * eye(self.nstates) - self.A, self.B)) \
805-
+ self.D
809+
+ self.D
810+
except LinAlgError:
811+
if warn_infinite:
812+
warn("frequency response is not finite",
813+
RuntimeWarning)
814+
# TODO: check for nan cases
815+
out[:,:,idx] = np.inf
806816
return out
807817

808818
def freqresp(self, omega):
@@ -1200,7 +1210,7 @@ def dcgain(self):
12001210
gain : ndarray
12011211
An array of shape (outputs,inputs); the array will either
12021212
be the zero-frequency (or DC) gain, or, if the frequency
1203-
response is singular, the array will be filled with np.nan.
1213+
response is singular, the array will be filled with np.inf.
12041214
"""
12051215
try:
12061216
if self.isctime():
@@ -1210,7 +1220,7 @@ def dcgain(self):
12101220
gain = np.squeeze(self.horner(1))
12111221
except LinAlgError:
12121222
# eigenvalue at DC
1213-
gain = np.tile(np.nan, (self.noutputs, self.ninputs))
1223+
gain = np.tile(np.inf, (self.noutputs, self.ninputs))
12141224
return np.squeeze(gain)
12151225

12161226
def _isstatic(self):

control/tests/statesp_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ def test_dc_gain_cont(self):
498498
np.testing.assert_allclose(sys2.dcgain(), expected)
499499

500500
sys3 = StateSpace(0., 1., 1., 0.)
501-
np.testing.assert_equal(sys3.dcgain(), np.nan)
501+
np.testing.assert_equal(sys3.dcgain(), np.inf)
502502

503503
def test_dc_gain_discr(self):
504504
"""Test DC gain for discrete-time state-space systems."""
@@ -516,7 +516,7 @@ def test_dc_gain_discr(self):
516516

517517
# summer
518518
sys = StateSpace(1, 1, 1, 0, True)
519-
np.testing.assert_equal(sys.dcgain(), np.nan)
519+
np.testing.assert_equal(sys.dcgain(), np.inf)
520520

521521
@pytest.mark.parametrize("outputs", range(1, 6))
522522
@pytest.mark.parametrize("inputs", range(1, 6))
@@ -539,7 +539,7 @@ def test_dc_gain_integrator(self, outputs, inputs, dt):
539539
c = np.eye(max(outputs, states))[:outputs, :states]
540540
d = np.zeros((outputs, inputs))
541541
sys = StateSpace(a, b, c, d, dt)
542-
dc = np.squeeze(np.full_like(d, np.nan))
542+
dc = np.squeeze(np.full_like(d, np.inf))
543543
np.testing.assert_array_equal(dc, sys.dcgain())
544544

545545
def test_scalar_static_gain(self):

control/xferfcn.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def __init__(self, *args, **kwargs):
234234
dt = config.defaults['control.default_dt']
235235
self.dt = dt
236236

237-
def __call__(self, x, squeeze=None):
237+
def __call__(self, x, squeeze=None, warn_infinite=True):
238238
"""Evaluate system's transfer function at complex frequencies.
239239
240240
Returns the complex frequency response `sys(x)` where `x` is `s` for
@@ -262,6 +262,8 @@ def __call__(self, x, squeeze=None):
262262
If True and the system is single-input single-output (SISO),
263263
return a 1D array rather than a 3D array. Default value (True)
264264
set by config.defaults['control.squeeze_frequency_response'].
265+
warn_infinite : bool, optional
266+
If set to `False`, turn off divide by zero warning.
265267
266268
Returns
267269
-------
@@ -274,10 +276,10 @@ def __call__(self, x, squeeze=None):
274276
then single-dimensional axes are removed.
275277
276278
"""
277-
out = self.horner(x)
279+
out = self.horner(x, warn_infinite=warn_infinite)
278280
return _process_frequency_response(self, x, out, squeeze=squeeze)
279281

280-
def horner(self, x):
282+
def horner(self, x, warn_infinite=True):
281283
"""Evaluate system's transfer function at complex frequency
282284
using Horner's method.
283285
@@ -307,8 +309,9 @@ def horner(self, x):
307309
out = empty((self.noutputs, self.ninputs, len(x_arr)), dtype=complex)
308310
for i in range(self.noutputs):
309311
for j in range(self.ninputs):
310-
out[i][j] = (polyval(self.num[i][j], x) /
311-
polyval(self.den[i][j], x))
312+
with np.errstate(divide='warn' if warn_infinite else 'ignore'):
313+
out[i][j] = (polyval(self.num[i][j], x) /
314+
polyval(self.den[i][j], x))
312315
return out
313316

314317
def _truncatecoeff(self):

0 commit comments

Comments
 (0)
0