8000 discard zero imaginary part for sys.dcgain() · juanodecc/python-control@8c9e807 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8c9e807

Browse files
committed
discard zero imaginary part for sys.dcgain()
1 parent b41574f commit 8c9e807

File tree

6 files changed

+48
-24
lines changed

6 files changed

+48
-24
lines changed

control/lti.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@ def dcgain(self):
208208
raise NotImplementedError("dcgain not implemented for %s objects" %
209209
str(self.__class__))
210210

211+
def _dcgain(self, warn_infinite):
212+
zeroresp = self(0 if self.isctime() else 1,
213+
warn_infinite=warn_infinite)
214+
if np.all(np.logical_or(np.isreal(zeroresp), np.isnan(zeroresp.imag))):
215+
return zeroresp.real
216+
else:
217+
return zeroresp
211218

212219
# Test to see if a system is SISO
213220
def issiso(sys, strict=False):

control/statesp.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,16 +1216,27 @@ def dcgain(self, warn_infinite=False):
12161216
12171217
.. math: G(1) = C (I - A)^{-1} B + D
12181218
1219+
Parameters
1220+
----------
1221+
warn_infinite : bool, optional
1222+
By default, don't issue a warning message if the zero-frequency
1223+
gain is infinite. Setting `warn_infinite` to generate the warning
1224+
message.
1225+
12191226
Returns
12201227
-------
1221-
gain : ndarray
1222-
An array of shape (outputs,inputs); the array will either be the
1223-
zero-frequency (or DC) gain, or, if the frequency response is
1224-
singular, the array will be filled with (inf + nanj).
1225-
1228+
gain : (outputs, inputs) ndarray or scalar
1229+
Array or scalar value for SISO systems, depending on
1230+
config.defaults['control.squeeze_frequency_response'].
1231+
The value of the array elements or the scalar is either the
1232+
zero-frequency (or DC) gain, or `inf`, if the frequency response
1233+
is singular.
1234+
1235+
For real valued systems, the empty imaginary part of the
1236+
complex zero-frequency response is discarded and a real array or
1237+
scalar is returned.
12261238
"""
1227-
return self(0, warn_infinite=warn_infinite) if self.isctime() \
1228-
else self(1, warn_infinite=warn_infinite)
1239+
return self._dcgain(warn_infinite)
12291240

12301241
def _isstatic(self):
12311242
"""True if and only if the system has no dynamics, that is,

control/tests/freqresp_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ def test_dcgain_consistency():
423423
sys_ss = ctrl.tf2ss(sys_tf)
424424
assert 0 in sys_ss.pole()
425425

426-
# Finite (real) numerator over 0 denominator => inf + nanj
426+
# Finite (real) numerator over 0 denominator => inf
427427
np.testing.assert_equal(
428428
sys_tf(0, warn_infinite=False), complex(np.inf, np.nan))
429429
np.testing.assert_equal(
@@ -433,9 +433,9 @@ def test_dcgain_consistency():
433433
np.testing.assert_equal(
434434
sys_ss(0j, warn_infinite=False), complex(np.inf, np.nan))
435435
np.testing.assert_equal(
436-
sys_tf.dcgain(warn_infinite=False), complex(np.inf, np.nan))
436+
sys_tf.dcgain(warn_infinite=False), np.inf)
437437
np.testing.assert_equal(
438-
sys_ss.dcgain(warn_infinite=False), complex(np.inf, np.nan))
438+
sys_ss.dcgain(warn_infinite=False), np.inf)
439439

440440
# Set up transfer function with pole, zero at the origin
441441
sys_tf = ctrl.tf([1, 0], [1, 0])
@@ -448,7 +448,7 @@ def test_dcgain_consistency():
448448
np.testing.assert_equal(
449449
sys_tf(0j, warn_infinite=False), complex(np.nan, np.nan))
450450
np.testing.assert_equal(
451-
sys_tf.dcgain(warn_infinite=False), complex(np.nan, np.nan))
451+
sys_tf.dcgain(warn_infinite=False), np.nan)
452452

453453
# Set up state space version
454454
sys_ss = ctrl.tf2ss(ctrl.tf([1, 0], [1, 1])) * \
@@ -462,15 +462,15 @@ def test_dcgain_consistency():
462462
np.testing.assert_equal(
463463
sys_ss(0j, warn_infinite=False), complex(np.nan, np.nan))
464464
np.testing.assert_equal(
465-
sys_ss.dcgain(warn_infinite=False), complex(np.nan, np.nan))
465+
sys_ss.dcgain(warn_infinite=False), np.nan)
466466
elif 0 in sys_ss.pole():
467467
# Pole at the origin, but zero elsewhere => should get (inf + nanj)
468468
np.testing.assert_equal(
469469
sys_ss(0, warn_infinite=False), complex(np.inf, np.nan))
470470
np.testing.assert_equal(
471471
sys_ss(0j, warn_infinite=False), complex(np.inf, np.nan))
472472
np.testing.assert_equal(
473-
sys_ss.dcgain(warn_infinite=False), complex(np.inf, np.nan))
473+
sys_ss.dcgain(warn_infinite=False), np.inf)
474474
else:
475475
# Near pole/zero cancellation => nothing sensible to check
476476
pass

control/tests/statesp_test.py

Lines changed: 3 additions & 4 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(), complex(np.inf, 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(), complex(np.inf, 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.full_like(d, complex(np.inf, np.nan), dtype=complex)
542+
dc = np.full_like(d, np.inf, dtype=float)
543543
if sys.issiso():
544544
dc = dc.squeeze()
545545

@@ -953,4 +953,3 @@ def test_xferfcn_ndarray_precedence(op, tf, arr):
953953
ss = ct.tf2ss(tf)
954954
result = op(arr, ss)
955955
assert isinstance(result, ct.StateSpace)
956-

control/tests/xferfcn_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ def test_dcgain_cont(self):
807807
np.testing.assert_equal(sys2.dcgain(), 2)
808808

809809
sys3 = TransferFunction(6, [1, 0])
810-
np.testing.assert_equal(sys3.dcgain(), complex(np.inf, np.nan))
810+
np.testing.assert_equal(sys3.dcgain(), np.inf)
811811

812812
num = [[[15], [21], [33]], [[10], [14], [22]]]
813813
den = [[[1, 3], [2, 3], [3, 3]], [[1, 5], [2, 7], [3, 11]]]
@@ -827,13 +827,13 @@ def test_dcgain_discr(self):
827827

828828
# differencer
829829
sys = TransferFunction(1, [1, -1], True)
830-
np.testing.assert_equal(sys.dcgain(), complex(np.inf, np.nan))
830+
np.testing.assert_equal(sys.dcgain(), np.inf)
831831

832832
# differencer, with warning
833833
sys = TransferFunction(1, [1, -1], True)
834834
with pytest.warns(RuntimeWarning, match="divide by zero"):
835835
np.testing.assert_equal(
836-
sys.dcgain(warn_infinite=True), complex(np.inf, np.nan))
836+
sys.dcgain(warn_infinite=True), np.inf)
837837

838838
# summer
839839
sys = TransferFunction([1, -1], [1], True)

control/xferfcn.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,12 +1070,19 @@ def dcgain(self, warn_infinite=False):
10701070
10711071
Returns
10721072
-------
1073-
gain : ndarray
1074-
The zero-frequency gain
1073+
gain : (outputs, inputs) ndarray or scalar
1074+
Array or scalar value for SISO systems, depending on
1075+
config.defaults['control.squeeze_frequency_response'].
1076+
The value of the array elements or the scalar is either the
1077+
zero-frequency (or DC) gain, or `inf`, if the frequency response
1078+
is singular.
1079+
1080+
For real valued systems, the empty imaginary part of the
1081+
complex zero-frequency response is discarded and a real array or
1082+
scalar is returned.
10751083
10761084
"""
1077-
return self(0, warn_infinite=warn_infinite) if self.isctime() \
1078-
else self(1, warn_infinite=warn_infinite)
1085+
return self._dcgain(warn_infinite)
10791086

10801087
def _isstatic(self):
10811088
"""returns True if and only if all of the numerator and denominator

0 commit comments

Comments
 (0)
0