From e6f2f60f6061c1cbec9741ced2d2925b4030547d Mon Sep 17 00:00:00 2001 From: lytex Date: Sun, 9 Feb 2020 21:52:35 +0100 Subject: [PATCH 01/11] allow _ssmatrix to accept complex values --- control/statesp.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/control/statesp.py b/control/statesp.py index 85d48882a..623f401f6 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -93,9 +93,15 @@ def _ssmatrix(data, axis=1): # Convert the data into an array or matrix, as configured # If data is passed as a string, use (deprecated?) matrix constructor if config.defaults['statesp.use_numpy_matrix'] or isinstance(data, str): - arr = np.matrix(data, dtype=float) + if np.isrealobj(data): + arr = np.matrix(data, dtype=float) + elif np.iscomplexobj(data): + arr = np.matrix(data, dtype=complex) else: - arr = np.array(data, dtype=float) + if np.isrealobj(data): + arr = np.array(data, dtype=float) + elif np.iscomplexobj(data): + arr = np.array(data, dtype=complex) ndim = arr.ndim shape = arr.shape From 53dbfe410c8dad062b745cae11327f5295e5dd08 Mon Sep 17 00:00:00 2001 From: lytex Date: Sat, 29 Feb 2020 11:02:53 +0100 Subject: [PATCH 02/11] add new tests with complex state matrices --- control/tests/statesp_test.py | 215 ++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 191271da4..a76b13d59 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -63,6 +63,50 @@ def setUp(self): D623 = np.zeros((3, 2)) self.sys623 = StateSpace(A623, B623, C623, D623) + # Systems with complex matrices, sysC322, sysC222, sysC623 + # These systems have the same shape as the previous ones + + A = np.array([[6.0 + 9.0j, 8.0 + 9.0j, -4.0 - 7.0j], + [8.0 - 7.0j, 3.0, 1.0 - 1.0j], + [-7.0 + 9.0j, -8.0 + 6.0j, 9.0 + 8.0j]]) + B = np.array([[6.0 + 3.0j, -9.0 - 2.0j], + [9.0 + 5.0j, 7.0 + 3.0j], + [3.0 + 5.0j, 8.0 - 6.0j]]) + C = np.array([[4.0 + 4.0j, -4.0 + 9.0j, -8.0 - 1.0j], + [-9.0 - 3.0j, -9.0 - 9.0j, 6.0 - 2.0j]]) + D = np.array([[5.0 - 1.0j, -6.0 + 4.0j], + [6.0 + 3.0j, 5.0j]]) + self.sysC322 = StateSpace(A, B, C, D) + + A = np.array([[-4.0 - 7.0j, 3.0 + 9.0j], + [3.0, -6.0 - 3.0j]]) + B = np.array([[2.0, 5.0 + 7.0j], + [-5.0 + 4.0j, -5.0 + 9.0j]]) + C = np.array([[1.0 + 6.0j, -7.0 + 6.0j], + [-7.0 - 5.0j, -5.0 - 5.0j]]) + D = np.array([[8.0 + 2.0j, -6.0 - 3.0j], + [-3.0 - 1.0j, -5.0 + 6.0j]]) + self.sysC222 = StateSpace(A, B, C, D) + + A = np.array( + [[2.0 - 8.0j, -2.0 + 6.0j, 8.0 - 1.0j, -6.0 + 7.0j, -5.0 - 3.0j, -5.0 - 6.0j], + [1.0 - 1.0j, 1.0 + 7.0j, -7.0 + 8.0j, 6.0 + 2.0j, 3.0, 8.0 - 5.0j], + [8.0 - 7.0j, -8.0 - 8.0j, 1.0 - 6.0j, -4.0 + 1.0j, 4.0 - 2.0j, -7.0 - 2.0j], + [-4.0 + 9.0j, -8.0 - 2.0j, -1.0 - 4.0j, 1.0 - 7.0j, 5.0 - 8.0j, 6.0 - 9.0j], + [5.0 - 9.0j, 1.0 - 5.0j, -9.0 - 7.0j, -6.0 + 7.0j, -1.0 - 5.0j, 1.0 + 8.0j], + [5.0 + 5.0j, 5.0 + 6.0j, -3.0 - 7.0j, 2.0 + 2.0j, -8.0 - 7.0j, 9.0 + 8.0j]]) + B = np.array([[6.0j, 5.0 + 3.0j, 8.0 + 4.0j], + [-9.0j, -2.0 - 1.0j, 9.0 - 6.0j], + [-3.0 - 9.0j, -5.0 + 1.0j, 1.0 - 2.0j], + [8.0 - 6.0j, -2.0 - 4.0j, -8.0 + 2.0j], + [-2.0 + 3.0j, -8.0 + 5.0j, -5.0 + 5.0j], + [-7.0 + 4.0j, -7.0 - 6.0j, -3.0 - 8.0j]]) + C = np.array([[8.0 + 6.0j, -3.0j, -1.0 + 7.0j, 2.0j, 6.0 - 6.0j, 3.0 - 1.0j], + [5.0 + 1.0j, -1.0 + 8.0j, -4.0 + 1.0j, 2.0j, 6.0 - 4.0j, -2.0 - 5.0j]]) + D = np.array([[7.0 - 4.0j, -5.0 - 1.0j, -5.0 + 8.0j], + [-6.0 + 8.0j, -6.0 - 6.0j, -1.0 + 9.0j]]) + self.sysC623 = StateSpace(A, B, C, D) + def test_D_broadcast(self): """Test broadcast of D=0 to the right shape""" # Giving D as a scalar 0 should broadcast to the right shape @@ -519,6 +563,177 @@ def test_lft(self): np.testing.assert_allclose(np.array(pk.C).reshape(-1), Cmatlab) np.testing.assert_allclose(np.array(pk.D).reshape(-1), Dmatlab) + def test_pole_complex(self): + """Evaluate the poles of a complex MIMO system.""" + + p = np.sort(self.sysC322.pole()) + true_p = np.sort([21.7521962567499187 +7.8381752267389437j + -6.4620734598457208 +2.8701578198630169j, + 2.7098772030958163 +6.2916669533980274j]) + + np.testing.assert_array_almost_equal(p, true_p) + + + @unittest.skipIf(not slycot_check(), "slycot not installed") + def test_zero_siso_complex(self): + """Evaluate the zeros of a complex SISO system.""" + # extract only first input / first output system of sysC222. This system is denoted sysC111 + # or tfC111 + tfC111 = ss2tf(self.sysC222) + sysC111 = tf2ss(tfC111[0, 0]) + + # compute zeros as root of the characteristic polynomial at the numerator of tfC111 + # this method is simple and assumed as valid in this test + true_z = np.sort(tfC111[0, 0].zero()) + # Compute the zeros through ab08nd, which is tested here + z = np.sort(sysC111.zero()) + + np.testing.assert_almost_equal(true_z, z) + + @unittest.skipIf(not slycot_check(), "slycot not installed") + def test_zero_mimo_sysC322_square_complex(self): + """Evaluate the zeros of a square complex MIMO system.""" + + z = np.sort(self.sysC322.zero()) + true_z = np.sort([36.4937595620286217 +8.0738640861708575j, + -4.7860079612333388 +29.3266582804945379j, + -7.4509692664104161 +5.5262915134608006j]) + np.testing.assert_array_almost_equal(z, true_z) + + @unittest.skipIf(not slycot_check(), "slycot not installed") + def test_zero_mimo_sysC222_square_complex(self): + """Evaluate the zeros of a square complex MIMO system.""" + + z = np.sort(self.sysC222.zero()) + true_z = np.sort([-10.5685005560737366, + 3.3685005560737391]) + np.testing.assert_array_almost_equal(z, true_z) + + @unittest.skipIf(not slycot_check(), "slycot not installed") + def test_zero_mimo_sysC623_non_square_complex(self): + """Evaluate the zeros of a non square complex MIMO system.""" + + z = np.sort(self.sysC623.zero()) + true_z = np.sort([]) # System has no transmission zeros, not sure what slycot returns + np.testing.assert_array_almost_equal(z, true_z) + + def test_add_ss_complex(self): + """Add two complex MIMO systems.""" + + A = np.array([[6.0 +9.0j, 8.0 +9.0j, -4.0 -7.0j, 0.0, 0.0], + [8.0 -7.0j, 3.0, 1.0 -1.0j, 0.0, 0.0], + [-7.0 +9.0j, -8.0 +6.0j, 9.0 +8.0j, 0.0, 0.0], + [0.0, 0.0, 0.0, -4.0 -7.0j, 3.0 +9.0j], + [0.0, 0.0, 0.0, 3.0, -6.0 -3.0j]]) + B = np.array([[6.0 +3.0j, -9.0 -2.0j], + [9.0 +5.0j, 7.0 +3.0j], + [3.0 +5.0j, 8.0 -6.0j], + [2.0, 5.0 +7.0j], + [-5.0 +4.0j, -5.0 +9.0j]]) + C = np.array([[4.0 +4.0j, -4.0 +9.0j, -8.0 -1.0j, 1.0 +6.0j, -7.0 +6.0j], + [-9.0 -3.0j, -9.0 -9.0j, 6.0 -2.0j, -7.0 -5.0j, -5.0 -5.0j]]) + D = np.array([[13.0 +1.0j, -12.0 +1.0j], + [3.0 +2.0j, -5.0 +11.0j]]) + + sys = self.sysC322 + self.sysC222 + + np.testing.assert_array_almost_equal(sys.A, A) + np.testing.assert_array_almost_equal(sys.B, B) + np.testing.assert_array_almost_equal(sys.C, C) + np.testing.assert_array_almost_equal(sys.D, D) + + def test_subtract_ss_complex(self): + """Subtract two complex MIMO systems.""" + + A = np.array([[6.0 +9.0j, 8.0 +9.0j, -4.0 -7.0j, 0.0, 0.0], + [8.0 -7.0j, 3.0, 1.0 -1.0j, 0.0, 0.0], + [-7.0 +9.0j, -8.0 +6.0j, 9.0 +8.0j, 0.0, 0.0], + [0.0, 0.0, 0.0, -4.0 -7.0j, 3.0 +9.0j], + [0.0, 0.0, 0.0, 3.0, -6.0 -3.0j]]) + B = np.array([[6.0 +3.0j, -9.0 -2.0j], + [9.0 +5.0j, 7.0 +3.0j], + [3.0 +5.0j, 8.0 -6.0j], + [2.0, 5.0 +7.0j], + [-5.0 +4.0j, -5.0 +9.0j]]) + C = np.array([[4.0 +4.0j, -4.0 +9.0j, -8.0 -1.0j, -1.0 -6.0j, 7.0 -6.0j], + [-9.0 -3.0j, -9.0 -9.0j, 6.0 -2.0j, 7.0 +5.0j, 5.0 +5.0j]]) + D = np.array([[-3.0 -3.0j, 7.0j], + [9.0 +4.0j, 5.0 -1.0j]]) + + sys = self.sysC322 - self.sysC222 + + np.testing.assert_array_almost_equal(sys.A, A) + np.testing.assert_array_almost_equal(sys.B, B) + np.testing.assert_array_almost_equal(sys.C, C) + np.testing.assert_array_almost_equal(sys.D, D) + + def test_multiply_ss_complex(self): + """Multiply two complex MIMO systems.""" + + A = np.array([[6.0 +9.0j, 8.0 +9.0j, -4.0 -7.0j, 41.0 +98.0j, -25.0 +70.0j], + [8.0 -7.0j, 3.0, 1.0 -1.0j, -55.0 +3.0j, -113.0 -31.0j], + [-7.0 +9.0j, -8.0 +6.0j, 9.0 +8.0j, -113.0 +25.0j, -121.0 -27.0j], + [0.0, 0.0, 0.0, -4.0 -7.0j, 3.0 +9.0j], + [0.0, 0.0, 0.0, 3.0, -6.0 -3.0j]]) + B = np.array([[67.0 +51.0j, 30.0 -80.0j], + [44.0 +42.0j, -92.0 -30.0j], + [-16.0 +56.0j, -7.0 +39.0j], + [2.0, 5.0 +7.0j], + [-5.0 +4.0j, -5.0 +9.0j]]) + C = np.array([[4.0 +4.0j, -4.0 +9.0j, -8.0 -1.0j, 73.0 +31.0j, 21.0 +47.0j], + [-9.0 -3.0j, -9.0 -9.0j, 6.0 -2.0j, 13.0 +4.0j, -35.0 -10.0j]]) + D = np.array([[64.0 -4.0j, -27.0 -65.0j], + [47.0 +21.0j, -57.0 -61.0j]]) + + sys = self.sysC322 * self.sysC222 + + np.testing.assert_array_almost_equal(sys.A, A) + np.testing.assert_array_almost_equal(sys.B, B) + np.testing.assert_array_almost_equal(sys.C, C) + np.testing.assert_array_almost_equal(sys.D, D) + + def test_evalfr(self): + """Evaluate the frequency response at one frequency.""" + + resp = [[4.6799374736968655 -34.9854626345217383j, + -10.8392352552155344 -10.3778031623880267j], + [28.8313352973005479 +17.1145433776227947j, + 5.6628990560933081 +8.8759694583057787j]] + + # Correct versions of the call + np.testing.assert_almost_equal(evalfr(sysC322, 1j), resp) + np.testing.assert_almost_equal(sysC322._evalfr(1.), resp) + + # Deprecated version of the call (should generate warning) + import warnings + with warnings.catch_warnings(record=True) as w: + # Set up warnings filter to only show warnings in control module + warnings.filterwarnings("ignore") + warnings.filterwarnings("always", module="control") + + # Make sure that we get a pending deprecation warning + sys.evalfr(1.) + assert len(w) == 1 + assert issubclass(w[-1].category, PendingDeprecationWarning) + + @unittest.skipIf(not slycot_check(), "slycot not installed") + def test_freq_resp(self): + """Evaluate the frequency response at multiple frequencies.""" + + true_mag = [[15.2721178549527039, 3.9176691825112484, 20.5865790875032246], + [24.5384389050919864, 2.8374330975514015, 18.2268344283306227]] + + true_phase = [[1.0345533469994428, 2.2133291186570987, 2.6715324185062164], + [1.8217663044282106, -2.8266936088743044, 2.2694910839768196]] + true_omega = [0.1, 10, 0.01j, -1j]; + + mag, phase, omega = sysC623.freqresp(true_omega) + + np.testing.assert_almost_equal(mag, true_mag) + np.testing.assert_almost_equal(phase, true_phase) + np.testing.assert_equal(omega, true_omega) + + class TestRss(unittest.TestCase): """These are tests for the proper functionality of statesp.rss.""" From 05d730a17480ae5b33c3a9aa4ab19400e6bd5dde Mon Sep 17 00:00:00 2001 From: lytex Date: Sat, 29 Feb 2020 11:29:32 +0100 Subject: [PATCH 03/11] rename to test_evalfr_complex, use self.sysC332 --- control/tests/statesp_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index a76b13d59..9063b7ff1 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -692,7 +692,7 @@ def test_multiply_ss_complex(self): np.testing.assert_array_almost_equal(sys.C, C) np.testing.assert_array_almost_equal(sys.D, D) - def test_evalfr(self): + def test_evalfr_complex(self): """Evaluate the frequency response at one frequency.""" resp = [[4.6799374736968655 -34.9854626345217383j, @@ -701,8 +701,8 @@ def test_evalfr(self): 5.6628990560933081 +8.8759694583057787j]] # Correct versions of the call - np.testing.assert_almost_equal(evalfr(sysC322, 1j), resp) - np.testing.assert_almost_equal(sysC322._evalfr(1.), resp) + np.testing.assert_almost_equal(evalfr(self.sysC322, 1j), resp) + np.testing.assert_almost_equal(self.sysC322._evalfr(1.), resp) # Deprecated version of the call (should generate warning) import warnings From a55165ae5dea63b7eaf4fd4a29abc37a03b8830c Mon Sep 17 00:00:00 2001 From: lytex Date: Sat, 29 Feb 2020 11:51:08 +0100 Subject: [PATCH 04/11] missed one sys.evalfr in previous commit --- control/tests/statesp_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 9063b7ff1..23fa8ce58 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -712,7 +712,7 @@ def test_evalfr_complex(self): warnings.filterwarnings("always", module="control") # Make sure that we get a pending deprecation warning - sys.evalfr(1.) + self.sysC322.evalfr(1.) assert len(w) == 1 assert issubclass(w[-1].category, PendingDeprecationWarning) From 2d231a83c3ad9ce039d45f2af1817e11f3e87faa Mon Sep 17 00:00:00 2001 From: lytex Date: Sat, 29 Feb 2020 11:51:08 +0100 Subject: [PATCH 05/11] missed one sys.evalfr in previous commit --- control/tests/statesp_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 23fa8ce58..03fa7b5e9 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -727,7 +727,7 @@ def test_freq_resp(self): [1.8217663044282106, -2.8266936088743044, 2.2694910839768196]] true_omega = [0.1, 10, 0.01j, -1j]; - mag, phase, omega = sysC623.freqresp(true_omega) + mag, phase, omega = self.sysC623.freqresp(true_omega) np.testing.assert_almost_equal(mag, true_mag) np.testing.assert_almost_equal(phase, true_phase) From f1c9b9eb2b22f1ab917438fd51a69774e39a1d24 Mon Sep 17 00:00:00 2001 From: lytex Date: Tue, 3 Mar 2020 05:09:14 +0100 Subject: [PATCH 06/11] add complex to test_freq_resp --- control/tests/statesp_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 03fa7b5e9..ac615a12c 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -12,6 +12,8 @@ from control.xferfcn import TransferFunction, ss2tf from control.lti import evalfr from control.exception import slycot_check +import warnings +warnings.filterwarnings("error", category=np.ComplexWarning) class TestStateSpace(unittest.TestCase): @@ -717,7 +719,7 @@ def test_evalfr_complex(self): assert issubclass(w[-1].category, PendingDeprecationWarning) @unittest.skipIf(not slycot_check(), "slycot not installed") - def test_freq_resp(self): + def test_freq_resp_complex(self): """Evaluate the frequency response at multiple frequencies.""" true_mag = [[15.2721178549527039, 3.9176691825112484, 20.5865790875032246], From e7a93ea28917d260bfa0cb5e87f7568185d0bef0 Mon Sep 17 00:00:00 2001 From: lytex Date: Tue, 3 Mar 2020 05:10:13 +0100 Subject: [PATCH 07/11] remove warnings settings for debugging --- control/tests/statesp_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index ac615a12c..f833a440d 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -12,9 +12,6 @@ from control.xferfcn import TransferFunction, ss2tf from control.lti import evalfr from control.exception import slycot_check -import warnings -warnings.filterwarnings("error", category=np.ComplexWarning) - class TestStateSpace(unittest.TestCase): """Tests for the StateSpace class.""" From bb448277144fcf90a61f862f6cf736f2ad812e70 Mon Sep 17 00:00:00 2001 From: lytex Date: Tue, 3 Mar 2020 05:24:25 +0100 Subject: [PATCH 08/11] ease precision of reference values in test --- control/tests/statesp_test.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index f833a440d..78630c876 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -594,9 +594,9 @@ def test_zero_mimo_sysC322_square_complex(self): """Evaluate the zeros of a square complex MIMO system.""" z = np.sort(self.sysC322.zero()) - true_z = np.sort([36.4937595620286217 +8.0738640861708575j, - -4.7860079612333388 +29.3266582804945379j, - -7.4509692664104161 +5.5262915134608006j]) + true_z = np.sort([36.493759 + 8.073864j, + -4.7860079 + 29.3266582j, + -7.4509692 +5.5262915j]) np.testing.assert_array_almost_equal(z, true_z) @unittest.skipIf(not slycot_check(), "slycot not installed") @@ -604,8 +604,8 @@ def test_zero_mimo_sysC222_square_complex(self): """Evaluate the zeros of a square complex MIMO system.""" z = np.sort(self.sysC222.zero()) - true_z = np.sort([-10.5685005560737366, - 3.3685005560737391]) + true_z = np.sort([-10.56850055, + 3.3685005]) np.testing.assert_array_almost_equal(z, true_z) @unittest.skipIf(not slycot_check(), "slycot not installed") @@ -694,10 +694,10 @@ def test_multiply_ss_complex(self): def test_evalfr_complex(self): """Evaluate the frequency response at one frequency.""" - resp = [[4.6799374736968655 -34.9854626345217383j, - -10.8392352552155344 -10.3778031623880267j], - [28.8313352973005479 +17.1145433776227947j, - 5.6628990560933081 +8.8759694583057787j]] + resp = [[4.6799374 - 34.9854626j, + -10.8392352 - 10.3778031j], + [28.8313352 + 17.1145433j, + 5.6628990 + 8.8759694j]] # Correct versions of the call np.testing.assert_almost_equal(evalfr(self.sysC322, 1j), resp) @@ -719,11 +719,11 @@ def test_evalfr_complex(self): def test_freq_resp_complex(self): """Evaluate the frequency response at multiple frequencies.""" - true_mag = [[15.2721178549527039, 3.9176691825112484, 20.5865790875032246], - [24.5384389050919864, 2.8374330975514015, 18.2268344283306227]] + true_mag = [[15.2721178, 3.9176691, 20.5865790], + [24.5384389, 2.8374330, 18.2268344]] - true_phase = [[1.0345533469994428, 2.2133291186570987, 2.6715324185062164], - [1.8217663044282106, -2.8266936088743044, 2.2694910839768196]] + true_phase = [[1.03455334, 2.2133291, 2.6715324], + [1.8217663, -2.8266936, 2.2694910]] true_omega = [0.1, 10, 0.01j, -1j]; mag, phase, omega = self.sysC623.freqresp(true_omega) From 5f587236896b52dfec31a8ddaaff65ac293c0a0e Mon Sep 17 00:00:00 2001 From: lytex Date: Mon, 30 Mar 2020 21:59:05 +0200 Subject: [PATCH 09/11] build an auxiliary system to compare against If we compare sys.A against A we get a IndexError (not sure why), but building a new auxiliary StateSpace seems to do the trick --- control/tests/statesp_test.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index ccb3b36b0..4c2b5cd20 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -684,12 +684,14 @@ def test_multiply_ss_complex(self): D = np.array([[64.0 -4.0j, -27.0 -65.0j], [47.0 +21.0j, -57.0 -61.0j]]) - sys = self.sysC322 * self.sysC222 + sys_aux = StateSpace(A, B, C, D) - np.testing.assert_array_almost_equal(sys.A, A) - np.testing.assert_array_almost_equal(sys.B, B) - np.testing.assert_array_almost_equal(sys.C, C) - np.testing.assert_array_almost_equal(sys.D, D) + sys = series(self.sysC322, self.sysC222) + + np.testing.assert_array_almost_equal(sys.A, sys_aux.A) + np.testing.assert_array_almost_equal(sys.B, sys_aux.B) + np.testing.assert_array_almost_equal(sys.C, sys_aux.C) + np.testing.assert_array_almost_equal(sys.D, sys_aux.D) def test_evalfr_complex(self): """Evaluate the frequency response at one frequency.""" From 1803d38fe5e81b82531a81ea7ec0751704215f63 Mon Sep 17 00:00:00 2001 From: lytex Date: Mon, 30 Mar 2020 21:59:05 +0200 Subject: [PATCH 10/11] build an auxiliary system to compare against If we compare sys.A against A we get a IndexError (not sure why), but building a new auxiliary StateSpace seems to do the trick --- control/tests/statesp_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 4c2b5cd20..8c94e7d76 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -7,7 +7,7 @@ import numpy as np from numpy.linalg import solve from scipy.linalg import eigvals, block_diag -from control import matlab +from control import matlab, series from control.statesp import StateSpace, _convertToStateSpace, tf2ss from control.xferfcn import TransferFunction, ss2tf from control.lti import evalfr From 84bc8ef946386b5530e0d557bb46d9eacbbd3e26 Mon Sep 17 00:00:00 2001 From: lytex Date: Wed, 1 Apr 2020 20:21:04 +0200 Subject: [PATCH 11/11] add code to use slycot complex function ab08nz if any matrix is complex --- control/statesp.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/control/statesp.py b/control/statesp.py index a91a555ec..405cdc62f 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -578,10 +578,15 @@ def zero(self): # Use AB08ND from Slycot if it's available, otherwise use # scipy.lingalg.eigvals(). try: - from slycot import ab08nd - - out = ab08nd(self.A.shape[0], self.B.shape[1], self.C.shape[0], - self.A, self.B, self.C, self.D) + if np.isrealobj(self.A) and np.isrealobj(self.B) and\ + np.isrealobj(self.C) and np.isrealobj(self.D): + from slycot import ab08nd + out = ab08nd(self.A.shape[0], self.B.shape[1], self.C.shape[0], + self.A, self.B, self.C, self.D) + else: + from slycot import ab08nz + out = ab08nz(self.A.shape[0], self.B.shape[1], self.C.shape[0], + self.A, self.B, self.C, self.D) nu = out[0] if nu == 0: return np.array([]) 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