def test_evalfr(self, dt, omega, resp): """Evaluate the frequency response at single frequencies""" A = [[-2, 0.5], [0.5, -0.3]] B = [[0.3, -1.3], [0.1, 0.]] C = [[0., 0.1], [-0.3, -0.2]] D = [[0., -0.8], [-0.3, 0.]] sys = StateSpace(A, B, C, D) if dt: sys = sample_system(sys, dt) s = np.exp(omega * 1j * dt) else: s = omega * 1j # Correct version of the call np.testing.assert_allclose(evalfr(sys, s), resp, atol=1e-3) # Deprecated version of the call (should generate warning) with pytest.deprecated_call(): np.testing.assert_allclose(sys.evalfr(omega), resp, atol=1e-3) # call above nyquist frequency if dt: with pytest.warns(UserWarning): np.testing.assert_allclose(sys._evalfr(omega + 2 * np.pi / dt), resp, atol=1e-3)
def test_sample_system(self): # Make sure we can convert various types of systems for sysc in (self.siso_tf1, self.siso_tf1c, self.siso_ss1, self.siso_ss1c, self.mimo_ss1, self.mimo_ss1c): for method in ("zoh", "bilinear", "euler", "backward_diff"): sysd = sample_system(sysc, 1, method=method) self.assertEqual(sysd.dt, 1) # Check "matched", defined only for SISO transfer functions for sysc in (self.siso_tf1, self.siso_tf1c): sysd = sample_system(sysc, 1, method="matched") self.assertEqual(sysd.dt, 1) # Check errors self.assertRaises(ValueError, sample_system, self.siso_ss1d, 1) self.assertRaises(ValueError, sample_system, self.siso_ss1, 1, 'unknown')
def test_printing(self): """Print SISO""" sys = ss2tf(rss(4, 1, 1)) assert isinstance(str(sys), str) assert isinstance(sys._repr_latex_(), str) # SISO, discrete time sys = sample_system(sys, 1) assert isinstance(str(sys), str) assert isinstance(sys._repr_latex_(), str)
def test_printing(self): # SISO, continuous time sys = ss2tf(rss(4, 1, 1)) self.assertTrue(isinstance(str(sys), str)) self.assertTrue(isinstance(sys._repr_latex_(), str)) # SISO, discrete time sys = sample_system(sys, 1) self.assertTrue(isinstance(str(sys), str)) self.assertTrue(isinstance(sys._repr_latex_(), str))
def test_sample_tf(self): # double integrator sys = TransferFunction(1, [1,0,0]) for h in (0.1, 0.5, 1, 2): numd_expected = 0.5 * h**2 * np.array([1.,1.]) dend_expected = np.array([1.,-2.,1.]) sysd = sample_system(sys, h, method='zoh') self.assertEqual(sysd.dt, h) numd = sysd.num[0][0] dend = sysd.den[0][0] np.testing.assert_array_almost_equal(numd, numd_expected) np.testing.assert_array_almost_equal(dend, dend_expected)
def test_sample_tf(self): # double integrator sys = TransferFunction(1, [1, 0, 0]) for h in (0.1, 0.5, 1, 2): numd_expected = 0.5 * h**2 * np.array([1., 1.]) dend_expected = np.array([1., -2., 1.]) sysd = sample_system(sys, h, method='zoh') self.assertEqual(sysd.dt, h) numd = sysd.num[0][0] dend = sysd.den[0][0] np.testing.assert_array_almost_equal(numd, numd_expected) np.testing.assert_array_almost_equal(dend, dend_expected)
def test_copy_constructor_nodt(self, sys322): """Test the copy constructor when an object without dt is passed""" sysin = sample_system(sys322, 1.) del sysin.dt # this is a nonsensical thing to do sys = StateSpace(sysin) assert sys.dt == defaults['control.default_dt'] # test for static gain sysin = StateSpace([], [], [], [[1, 2], [3, 4]], 1.) del sysin.dt # this is a nonsensical thing to do sys = StateSpace(sysin) assert sys.dt is None
def test_sample_ss(self): # double integrators, two different ways sys1 = StateSpace([[0.,1.],[0.,0.]], [[0.],[1.]], [[1.,0.]], 0.) sys2 = StateSpace([[0.,0.],[1.,0.]], [[1.],[0.]], [[0.,1.]], 0.) I = np.eye(2) for sys in (sys1, sys2): for h in (0.1, 0.5, 1, 2): Ad = I + h * sys.A Bd = h * sys.B + 0.5 * h**2 * (sys.A * sys.B) sysd = sample_system(sys, h, method='zoh') np.testing.assert_array_almost_equal(sysd.A, Ad) np.testing.assert_array_almost_equal(sysd.B, Bd) np.testing.assert_array_almost_equal(sysd.C, sys.C) np.testing.assert_array_almost_equal(sysd.D, sys.D) self.assertEqual(sysd.dt, h)
def test_sample_ss(self): # double integrators, two different ways sys1 = StateSpace([[0., 1.], [0., 0.]], [[0.], [1.]], [[1., 0.]], 0.) sys2 = StateSpace([[0., 0.], [1., 0.]], [[1.], [0.]], [[0., 1.]], 0.) I = np.eye(2) for sys in (sys1, sys2): for h in (0.1, 0.5, 1, 2): Ad = I + h * sys.A Bd = h * sys.B + 0.5 * h**2 * (sys.A * sys.B) sysd = sample_system(sys, h, method='zoh') np.testing.assert_array_almost_equal(sysd.A, Ad) np.testing.assert_array_almost_equal(sysd.B, Bd) np.testing.assert_array_almost_equal(sysd.C, sys.C) np.testing.assert_array_almost_equal(sysd.D, sys.D) self.assertEqual(sysd.dt, h)
def test_call_siso(self, dt, omega, resp): """Evaluate the frequency response of a SISO system at one frequency.""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) if dt: sys = sample_system(sys, dt) s = np.exp(omega * 1j * dt) else: s = omega * 1j # Correct versions of the call np.testing.assert_allclose(evalfr(sys, s), resp, atol=1e-3) np.testing.assert_allclose(sys(s), resp, atol=1e-3) # Deprecated version of the call (should generate exception) with pytest.raises(AttributeError): np.testing.assert_allclose(sys.evalfr(omega), resp, atol=1e-3)
def test_div(self): # Make sure that sampling times work correctly sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], True) sys3 = sys1 / sys2 self.assertEqual(sys3.dt, True) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], 0.5) sys3 = sys1 / sys2 self.assertEqual(sys3.dt, 0.5) sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1], 0.1) self.assertRaises(ValueError, TransferFunction.__truediv__, sys1, sys2) sys1 = sample_system(rss(4, 1, 1), 0.5) sys3 = TransferFunction.__rtruediv__(sys2, sys1) self.assertEqual(sys3.dt, 0.5)
def test_div(self): # Make sure that sampling times work correctly sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1], None) sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], True) sys3 = sys1 / sys2 assert sys3.dt is True sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]], 0.5) sys3 = sys1 / sys2 assert sys3.dt == 0.5 sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1], 0.1) with pytest.raises(ValueError): TransferFunction.__truediv__(sys1, sys2) sys1 = sample_system(rss(4, 1, 1), 0.5) sys3 = TransferFunction.__rtruediv__(sys2, sys1) assert sys3.dt == 0.5
def test_call(self, dt, omega, resp): """Evaluate the frequency response at single frequencies""" A = [[-2, 0.5], [0.5, -0.3]] B = [[0.3, -1.3], [0.1, 0.]] C = [[0., 0.1], [-0.3, -0.2]] D = [[0., -0.8], [-0.3, 0.]] sys = StateSpace(A, B, C, D) if dt: sys = sample_system(sys, dt) s = np.exp(omega * 1j * dt) else: s = omega * 1j # Correct versions of the call np.testing.assert_allclose(evalfr(sys, s), resp, atol=1e-3) np.testing.assert_allclose(sys(s), resp, atol=1e-3) # Deprecated name of the call (should generate error) with pytest.raises(AttributeError): sys.evalfr(omega)
def test_evalfr_siso(self, dt, omega, resp): """Evaluate the frequency response at single frequencies""" sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) if dt: sys = sample_system(sys, dt) s = np.exp(omega * 1j * dt) else: s = omega * 1j # Correct versions of the call np.testing.assert_allclose(evalfr(sys, s), resp, atol=1e-3) np.testing.assert_allclose(sys(s), resp, atol=1e-3) # Deprecated version of the call (should generate warning) with pytest.deprecated_call(): np.testing.assert_allclose(sys.evalfr(omega), resp, atol=1e-3) # call above nyquist frequency if dt: with pytest.warns(UserWarning): np.testing.assert_allclose(sys._evalfr(omega + 2 * np.pi / dt), resp, atol=1e-3)
def c2d(sysc, Ts, method): # TODO: add docstring # Call the sample_system() function to do the work return sample_system(sysc, Ts, method)