diff --git a/control/statesp.py b/control/statesp.py index f5b8534c3..27dbdf934 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -612,11 +612,14 @@ def dcgain(self): at the origin """ try: - gain = np.asarray(self.D - - self.C.dot(np.linalg.solve(self.A, self.B))) + if self.isctime(): + gain = np.asarray(self.D - + self.C.dot(np.linalg.solve(self.A, self.B))) + else: + gain = self.horner(1) except LinAlgError: - # zero eigenvalue: singular matrix - return np.nan + # eigenvalue at DC + gain = np.tile(np.nan,(self.outputs,self.inputs)) return np.squeeze(gain) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 8a6617116..245b396c6 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -228,7 +228,8 @@ def testArrayAccessSS(self): assert sys1.dt == sys1_11.dt - def test_dcgain(self): + def test_dcgain_cont(self): + """Test DC gain for continuous-time state-space systems""" sys = StateSpace(-2.,6.,5.,0) np.testing.assert_equal(sys.dcgain(), 15.) @@ -239,6 +240,43 @@ def test_dcgain(self): sys3 = StateSpace(0., 1., 1., 0.) np.testing.assert_equal(sys3.dcgain(), np.nan) + def test_dcgain_discr(self): + """Test DC gain for discrete-time state-space systems""" + # static gain + sys = StateSpace([], [], [], 2, True) + np.testing.assert_equal(sys.dcgain(), 2) + + # averaging filter + sys = StateSpace(0.5, 0.5, 1, 0, True) + np.testing.assert_almost_equal(sys.dcgain(), 1) + + # differencer + sys = StateSpace(0, 1, -1, 1, True) + np.testing.assert_equal(sys.dcgain(), 0) + + # summer + sys = StateSpace(1, 1, 1, 0, True) + np.testing.assert_equal(sys.dcgain(), np.nan) + + def test_dcgain_integrator(self): + """DC gain when eigenvalue at DC returns appropriately sized array of nan""" + # the SISO case is also tested in test_dc_gain_{cont,discr} + import itertools + # iterate over input and output sizes, and continuous (dt=None) and discrete (dt=True) time + for inputs,outputs,dt in itertools.product(range(1,6),range(1,6),[None,True]): + states = max(inputs,outputs) + + # a matrix that is singular at DC, and has no "useless" states as in _remove_useless_states + a = np.triu(np.tile(2,(states,states))) + # eigenvalues all +2, except for ... + a[0,0] = 0 if dt is None else 1 + b = np.eye(max(inputs,states))[:states,:inputs] + c = np.eye(max(outputs,states))[:outputs,:states] + d = np.zeros((outputs,inputs)) + sys = StateSpace(a,b,c,d,dt) + dc = np.squeeze(np.tile(np.nan,(outputs,inputs))) + np.testing.assert_array_equal(dc, sys.dcgain()) + def test_scalarStaticGain(self): """Regression: can we create a scalar static gain?""" diff --git a/control/tests/xferfcn_test.py b/control/tests/xferfcn_test.py index 2d114fea6..a6c9ae585 100644 --- a/control/tests/xferfcn_test.py +++ b/control/tests/xferfcn_test.py @@ -524,7 +524,8 @@ def testMatrixMult(self): np.testing.assert_array_almost_equal(H.num[1][0], H2.num[0][0]) np.testing.assert_array_almost_equal(H.den[1][0], H2.den[0][0]) - def test_dcgain(self): + def test_dcgain_cont(self): + """Test DC gain for continuous-time transfer functions""" sys = TransferFunction(6, 3) np.testing.assert_equal(sys.dcgain(), 2) @@ -540,6 +541,26 @@ def test_dcgain(self): expected = [[5, 7, 11], [2, 2, 2]] np.testing.assert_array_equal(sys4.dcgain(), expected) + def test_dcgain_discr(self): + """Test DC gain for discrete-time transfer functions""" + # static gain + sys = TransferFunction(6, 3, True) + np.testing.assert_equal(sys.dcgain(), 2) + + # averaging filter + sys = TransferFunction(0.5, [1, -0.5], True) + np.testing.assert_almost_equal(sys.dcgain(), 1) + + # differencer + sys = TransferFunction(1, [1, -1], True) + np.testing.assert_equal(sys.dcgain(), np.inf) + + # summer + # causes a RuntimeWarning due to the divide by zero + sys = TransferFunction([1,-1], [1], True) + np.testing.assert_equal(sys.dcgain(), 0) + + def suite(): return unittest.TestLoader().loadTestsFromTestCase(TestXferFcn) diff --git a/control/xferfcn.py b/control/xferfcn.py index 963329ffb..1559fa047 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -945,13 +945,23 @@ def sample(self, Ts, method='zoh', alpha=None): def dcgain(self): """Return the zero-frequency (or DC) gain - For a transfer function G(s), the DC gain is G(0) + For a continous-time transfer function G(s), the DC gain is G(0) + For a discrete-time transfer function G(z), the DC gain is G(1) Returns ------- gain : ndarray The zero-frequency gain """ + if self.isctime(): + return self._dcgain_cont() + else: + return self(1) + + def _dcgain_cont(self): + """_dcgain_cont() -> DC gain as matrix or scalar + + Special cased evaluation at 0 for continuous-time systems""" gain = np.empty((self.outputs, self.inputs), dtype=float) for i in range(self.outputs): for j in range(self.inputs): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy