88from numpy .linalg import solve
99from scipy .linalg import eigvals , block_diag
1010from control import matlab
11- from control .statesp import StateSpace , _convertToStateSpace , tf2ss
11+ from control .statesp import StateSpace , _convertToStateSpace , tf2ss , consistent_dimensions
1212from control .xferfcn import TransferFunction , ss2tf
1313from control .lti import evalfr
1414from control .exception import slycot_check
@@ -21,47 +21,47 @@ def setUp(self):
2121 """Set up a MIMO system to test operations on."""
2222
2323 # sys1: 3-states square system (2 inputs x 2 outputs)
24- A322 = [[- 3. , 4. , 2. ],
25- [- 1. , - 3. , 0. ],
26- [2. , 5. , 3. ]]
27- B322 = [[1. , 4. ],
28- [- 3. , - 3. ],
29- [- 2. , 1. ]]
30- C322 = [[4. , 2. , - 3. ],
31- [1. , 4. , 3. ]]
32- D322 = [[- 2. , 4. ],
33- [0. , 1. ]]
34- self .sys322 = StateSpace (A322 , B322 , C322 , D322 )
24+ self . A322 = np . array ( [[- 3. , 4. , 2. ],
25+ [- 1. , - 3. , 0. ],
26+ [2. , 5. , 3. ]])
27+ self . B322 = np . array ( [[1. , 4. ],
28+ [- 3. , - 3. ],
29+ [- 2. , 1. ]])
30+ self . C322 = np . array ( [[4. , 2. , - 3. ],
31+ [1. , 4. , 3. ]])
32+ self . D322 = np . array ( [[- 2. , 4. ],
33+ [0. , 1. ]])
34+ self .sys322 = StateSpace (self . A322 , self . B322 , self . C322 , self . D322 )
3535
3636 # sys1: 2-states square system (2 inputs x 2 outputs)
37- A222 = [[4. , 1. ],
38- [2. , - 3 ]]
39- B222 = [[5. , 2. ],
40- [- 3. , - 3. ]]
41- C222 = [[2. , - 4 ],
42- [0. , 1. ]]
43- D222 = [[3. , 2. ],
44- [1. , - 1. ]]
45- self .sys222 = StateSpace (A222 , B222 , C222 , D222 )
37+ self . A222 = np . array ( [[4. , 1. ],
38+ [2. , - 3 ]])
39+ self . B222 = np . array ( [[5. , 2. ],
40+ [- 3. , - 3. ]])
41+ self . C222 = np . array ( [[2. , - 4 ],
42+ [0. , 1. ]])
43+ self . D222 = np . array ( [[3. , 2. ],
44+ [1. , - 1. ]])
45+ self .sys222 = StateSpace (self . A222 , self . B222 , self . C222 , self . D222 )
4646
4747 # sys3: 6 states non square system (2 inputs x 3 outputs)
48- A623 = np .array ([[1 , 0 , 0 , 0 , 0 , 0 ],
49- [0 , 1 , 0 , 0 , 0 , 0 ],
50- [0 , 0 , 3 , 0 , 0 , 0 ],
51- [0 , 0 , 0 , - 4 , 0 , 0 ],
52- [0 , 0 , 0 , 0 , - 1 , 0 ],
53- [0 , 0 , 0 , 0 , 0 , 3 ]])
54- B623 = np .array ([[0 , - 1 ],
55- [- 1 , 0 ],
56- [1 , - 1 ],
57- [0 , 0 ],
58- [0 , 1 ],
59- [- 1 , - 1 ]])
60- C623 = np .array ([[1 , 0 , 0 , 1 , 0 , 0 ],
61- [0 , 1 , 0 , 1 , 0 , 1 ],
62- [0 , 0 , 1 , 0 , 0 , 1 ]])
63- D623 = np .zeros ((3 , 2 ))
64- self .sys623 = StateSpace (A623 , B623 , C623 , D623 )
48+ self . A623 = np .array ([[1 , 0 , 0 , 0 , 0 , 0 ],
49+ [0 , 1 , 0 , 0 , 0 , 0 ],
50+ [0 , 0 , 3 , 0 , 0 , 0 ],
51+ [0 , 0 , 0 , - 4 , 0 , 0 ],
52+ [0 , 0 , 0 , 0 , - 1 , 0 ],
53+ [0 , 0 , 0 , 0 , 0 , 3 ]])
54+ self . B623 = np .array ([[0 , - 1 ],
55+ [- 1 , 0 ],
56+ [1 , - 1 ],
57+ [0 , 0 ],
58+ [0 , 1 ],
59+ [- 1 , - 1 ]])
60+ self . C623 = np .array ([[1 , 0 , 0 , 1 , 0 , 0 ],
61+ [0 , 1 , 0 , 1 , 0 , 1 ],
62+ [0 , 0 , 1 , 0 , 0 , 1 ]])
63+ self . D623 = np .zeros ((3 , 2 ))
64+ self .sys623 = StateSpace (self . A623 , self . B623 , self . C623 , self . D623 )
6565
6666 def test_pole (self ):
6767 """Evaluate the poles of a MIMO system."""
@@ -107,7 +107,7 @@ def test_zero_mimo_sys222_square(self):
107107 """Evaluate the zeros of a square MIMO system."""
108108
109109 z = np .sort (self .sys222 .zero ())
110- true_z = np .sort ([- 10.568501 , 3.368501 ])
110+ true_z = np .sort ([- 10.568501 , 3.368501 ])
111111 np .testing .assert_array_almost_equal (z , true_z )
112112
113113 @unittest .skipIf (not slycot_check (), "slycot not installed" )
@@ -207,13 +207,13 @@ def test_freq_resp(self):
207207 sys = StateSpace (A , B , C , D )
208208
209209 true_mag = [[[0.0852992637230322 , 0.00103596611395218 ],
210- [0.935374692849736 , 0.799380720864549 ]],
211- [[0.55656854563842 , 0.301542699860857 ],
212- [0.609178071542849 , 0.0382108097985257 ]]]
210+ [0.935374692849736 , 0.799380720864549 ]],
211+ [[0.55656854563842 , 0.301542699860857 ],
212+ [0.609178071542849 , 0.0382108097985257 ]]]
213213 true_phase = [[[- 0.566195599644593 , - 1.68063565332582 ],
214- [3.0465958317514 , 3.14141384339534 ]],
215- [[2.90457947657161 , 3.10601268291914 ],
216- [- 0.438157380501337 , - 1.40720969147217 ]]]
214+ [3.0465958317514 , 3.14141384339534 ]],
215+ [[2.90457947657161 , 3.10601268291914 ],
216+ [- 0.438157380501337 , - 1.40720969147217 ]]]
217217 true_omega = [0.1 , 10. ]
218218
219219 mag , phase , omega = sys .freqresp (true_omega )
@@ -241,7 +241,7 @@ def test_minreal(self):
241241 self .assertEqual (sysr .inputs , sys .inputs )
242242 self .assertEqual (sysr .outputs , sys .outputs )
243243 np .testing .assert_array_almost_equal (
244- eigvals (sysr .A ), [- 2.136154 , - 0.1638459 ])
244+ eigvals (sysr .A ), [- 2.136154 , - 0.1638459 ])
245245
246246 def test_append_ss (self ):
247247 """Test appending two state-space systems."""
@@ -290,7 +290,6 @@ def test_append_tf(self):
290290 np .testing .assert_array_almost_equal (sys3c .A [3 :, :3 ], np .zeros ((2 , 3 )))
291291
292292 def test_array_access_ss (self ):
293-
294293 sys1 = StateSpace ([[1. , 2. ], [3. , 4. ]],
295294 [[5. , 6. ], [6. , 8. ]],
296295 [[9. , 10. ], [11. , 12. ]],
@@ -392,7 +391,7 @@ def test_matrix_static_gain(self):
392391 np .testing .assert_array_equal (d1 + d2 .T , h2 .D )
393392 h3 = g1 .feedback (g2 )
394393 np .testing .assert_array_almost_equal (
395- solve (np .eye (2 ) + d1 * d2 , d1 ), h3 .D )
394+ solve (np .eye (2 ) + d1 * d2 , d1 ), h3 .D )
396395 h4 = g1 .append (g2 )
397396 np .testing .assert_array_equal (block_diag (d1 , d2 ), h4 .D )
398397
@@ -443,11 +442,39 @@ def empty(shape):
443442 m = np .matrix ([])
444443 m .shape = shape
445444 return m
445+
446446 np .testing .assert_array_equal (empty ((0 , 0 )), g .A )
447447 np .testing .assert_array_equal (empty ((0 , D .shape [1 ])), g .B )
448448 np .testing .assert_array_equal (empty ((D .shape [0 ], 0 )), g .C )
449449 np .testing .assert_array_equal (D , g .D )
450450
451+ def test_consistent_dimensions_322 (self ):
452+ true = consistent_dimensions (self .A322 , self .B322 , self .C322 , self .D322 )
453+ np .testing .assert_ (true )
454+ true = consistent_dimensions (B = self .B322 , C = self .C322 , D = self .D322 )
455+ np .testing .assert_ (true )
456+ true = consistent_dimensions (A = self .A322 , C = self .C322 , D = self .D322 )
457+ np .testing .assert_ (true )
458+ true = consistent_dimensions (A = self .A322 , B = self .B322 , D = self .D322 )
459+ np .testing .assert_ (true )
460+ true = consistent_dimensions (A = self .A322 , B = self .B322 , C = self .C322 )
461+ np .testing .assert_ (true )
462+
463+ def test_consistent_dimensions_bad_inputs (self ):
464+ # Number of states not consistent
465+ true = consistent_dimensions (A = self .A222 , B = self .B322 , C = self .C322 , D = self .D322 )
466+ np .testing .assert_ (not true )
467+ true = consistent_dimensions (self .A322 , self .B222 , self .C322 , self .D322 )
468+ np .testing .assert_ (not true )
469+ true = consistent_dimensions (A = self .A322 , C = self .C222 , D = self .D322 )
470+ np .testing .assert_ (not true )
471+ # Number of input not consistent
472+ true = consistent_dimensions (A = self .A322 , B = self .B322 , D = self .A322 )
473+ np .testing .assert_ (not true )
474+ # Number of output not consistent
475+ true = consistent_dimensions (A = self .A322 , C = self .C322 , D = self .A322 )
476+ np .testing .assert_ (not true )
477+
451478
452479class TestRss (unittest .TestCase ):
453480 """These are tests for the proper functionality of statesp.rss."""
0 commit comments