@@ -63,6 +63,50 @@ def setUp(self):
6363 D623 = np .zeros ((3 , 2 ))
6464 self .sys623 = StateSpace (A623 , B623 , C623 , D623 )
6565
66+ # Systems with complex matrices, sysC322, sysC222, sysC623
67+ # These systems have the same shape as the previous ones
68+
69+ A = np .array ([[6.0 + 9.0j , 8.0 + 9.0j , - 4.0 - 7.0j ],
70+ [8.0 - 7.0j , 3.0 , 1.0 - 1.0j ],
71+ [- 7.0 + 9.0j , - 8.0 + 6.0j , 9.0 + 8.0j ]])
72+ B = np .array ([[6.0 + 3.0j , - 9.0 - 2.0j ],
73+ [9.0 + 5.0j , 7.0 + 3.0j ],
74+ [3.0 + 5.0j , 8.0 - 6.0j ]])
75+ C = np .array ([[4.0 + 4.0j , - 4.0 + 9.0j , - 8.0 - 1.0j ],
76+ [- 9.0 - 3.0j , - 9.0 - 9.0j , 6.0 - 2.0j ]])
77+ D = np .array ([[5.0 - 1.0j , - 6.0 + 4.0j ],
78+ [6.0 + 3.0j , 5.0j ]])
79+ self .sysC322 = StateSpace (A , B , C , D )
80+
81+ A = np .array ([[- 4.0 - 7.0j , 3.0 + 9.0j ],
82+ [3.0 , - 6.0 - 3.0j ]])
83+ B = np .array ([[2.0 , 5.0 + 7.0j ],
84+ [- 5.0 + 4.0j , - 5.0 + 9.0j ]])
85+ C = np .array ([[1.0 + 6.0j , - 7.0 + 6.0j ],
86+ [- 7.0 - 5.0j , - 5.0 - 5.0j ]])
87+ D = np .array ([[8.0 + 2.0j , - 6.0 - 3.0j ],
88+ [- 3.0 - 1.0j , - 5.0 + 6.0j ]])
89+ self .sysC222 = StateSpace (A , B , C , D )
90+
91+ A = np .array (
92+ [[2.0 - 8.0j , - 2.0 + 6.0j , 8.0 - 1.0j , - 6.0 + 7.0j , - 5.0 - 3.0j , - 5.0 - 6.0j ],
93+ [1.0 - 1.0j , 1.0 + 7.0j , - 7.0 + 8.0j , 6.0 + 2.0j , 3.0 , 8.0 - 5.0j ],
94+ [8.0 - 7.0j , - 8.0 - 8.0j , 1.0 - 6.0j , - 4.0 + 1.0j , 4.0 - 2.0j , - 7.0 - 2.0j ],
95+ [- 4.0 + 9.0j , - 8.0 - 2.0j , - 1.0 - 4.0j , 1.0 - 7.0j , 5.0 - 8.0j , 6.0 - 9.0j ],
96+ [5.0 - 9.0j , 1.0 - 5.0j , - 9.0 - 7.0j , - 6.0 + 7.0j , - 1.0 - 5.0j , 1.0 + 8.0j ],
97+ [5.0 + 5.0j , 5.0 + 6.0j , - 3.0 - 7.0j , 2.0 + 2.0j , - 8.0 - 7.0j , 9.0 + 8.0j ]])
98+ B = np .array ([[6.0j , 5.0 + 3.0j , 8.0 + 4.0j ],
99+ [- 9.0j , - 2.0 - 1.0j , 9.0 - 6.0j ],
100+ [- 3.0 - 9.0j , - 5.0 + 1.0j , 1.0 - 2.0j ],
101+ [8.0 - 6.0j , - 2.0 - 4.0j , - 8.0 + 2.0j ],
102+ [- 2.0 + 3.0j , - 8.0 + 5.0j , - 5.0 + 5.0j ],
103+ [- 7.0 + 4.0j , - 7.0 - 6.0j , - 3.0 - 8.0j ]])
104+ C = np .array ([[8.0 + 6.0j , - 3.0j , - 1.0 + 7.0j , 2.0j , 6.0 - 6.0j , 3.0 - 1.0j ],
105+ [5.0 + 1.0j , - 1.0 + 8.0j , - 4.0 + 1.0j , 2.0j , 6.0 - 4.0j , - 2.0 - 5.0j ]])
106+ D = np .array ([[7.0 - 4.0j , - 5.0 - 1.0j , - 5.0 + 8.0j ],
107+ [- 6.0 + 8.0j , - 6.0 - 6.0j , - 1.0 + 9.0j ]])
108+ self .sysC623 = StateSpace (A , B , C , D )
109+
66110 def test_D_broadcast (self ):
67111 """Test broadcast of D=0 to the right shape"""
68112 # Giving D as a scalar 0 should broadcast to the right shape
@@ -519,6 +563,177 @@ def test_lft(self):
519563 np .testing .assert_allclose (np .array (pk .C ).reshape (- 1 ), Cmatlab )
520564 np .testing .assert_allclose (np .array (pk .D ).reshape (- 1 ), Dmatlab )
521565
566+ def test_pole_complex (self ):
567+ """Evaluate the poles of a complex MIMO system."""
568+
569+ p = np .sort (self .sysC322 .pole ())
570+ true_p = np .sort ([21.7521962567499187 + 7.8381752267389437j
571+ - 6.4620734598457208 + 2.8701578198630169j ,
572+ 2.7098772030958163 + 6.2916669533980274j ])
573+
574+ np .testing .assert_array_almost_equal (p , true_p )
575+
576+
577+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
578+ def test_zero_siso_complex (self ):
579+ """Evaluate the zeros of a complex SISO system."""
580+ # extract only first input / first output system of sysC222. This system is denoted sysC111
581+ # or tfC111
582+ tfC111 = ss2tf (self .sysC222 )
583+ sysC111 = tf2ss (tfC111 [0 , 0 ])
584+
585+ # compute zeros as root of the characteristic polynomial at the numerator of tfC111
586+ # this method is simple and assumed as valid in this test
587+ true_z = np .sort (tfC111 [0 , 0 ].zero ())
588+ # Compute the zeros through ab08nd, which is tested here
589+ z = np .sort (sysC111 .zero ())
590+
591+ np .testing .assert_almost_equal (true_z , z )
592+
593+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
594+ def test_zero_mimo_sysC322_square_complex (self ):
595+ """Evaluate the zeros of a square complex MIMO system."""
596+
597+ z = np .sort (self .sysC322 .zero ())
598+ true_z = np .sort ([36.4937595620286217 + 8.0738640861708575j ,
599+ - 4.7860079612333388 + 29.3266582804945379j ,
600+ - 7.4509692664104161 + 5.5262915134608006j ])
601+ np .testing .assert_array_almost_equal (z , true_z )
602+
603+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
604+ def test_zero_mimo_sysC222_square_complex (self ):
605+ """Evaluate the zeros of a square complex MIMO system."""
606+
607+ z = np .sort (self .sysC222 .zero ())
608+ true_z = np .sort ([- 10.5685005560737366 ,
609+ 3.3685005560737391 ])
610+ np .testing .assert_array_almost_equal (z , true_z )
611+
612+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
613+ def test_zero_mimo_sysC623_non_square_complex (self ):
614+ """Evaluate the zeros of a non square complex MIMO system."""
615+
616+ z = np .sort (self .sysC623 .zero ())
617+ true_z = np .sort ([]) # System has no transmission zeros, not sure what slycot returns
618+ np .testing .assert_array_almost_equal (z , true_z )
619+
620+ def test_add_ss_complex (self ):
621+ """Add two complex MIMO systems."""
622+
623+ A = np .array ([[6.0 + 9.0j , 8.0 + 9.0j , - 4.0 - 7.0j , 0.0 , 0.0 ],
624+ [8.0 - 7.0j , 3.0 , 1.0 - 1.0j , 0.0 , 0.0 ],
625+ [- 7.0 + 9.0j , - 8.0 + 6.0j , 9.0 + 8.0j , 0.0 , 0.0 ],
626+ [0.0 , 0.0 , 0.0 , - 4.0 - 7.0j , 3.0 + 9.0j ],
627+ [0.0 , 0.0 , 0.0 , 3.0 , - 6.0 - 3.0j ]])
628+ B = np .array ([[6.0 + 3.0j , - 9.0 - 2.0j ],
629+ [9.0 + 5.0j , 7.0 + 3.0j ],
630+ [3.0 + 5.0j , 8.0 - 6.0j ],
631+ [2.0 , 5.0 + 7.0j ],
632+ [- 5.0 + 4.0j , - 5.0 + 9.0j ]])
633+ C = np .array ([[4.0 + 4.0j , - 4.0 + 9.0j , - 8.0 - 1.0j , 1.0 + 6.0j , - 7.0 + 6.0j ],
634+ [- 9.0 - 3.0j , - 9.0 - 9.0j , 6.0 - 2.0j , - 7.0 - 5.0j , - 5.0 - 5.0j ]])
635+ D = np .array ([[13.0 + 1.0j , - 12.0 + 1.0j ],
636+ [3.0 + 2.0j , - 5.0 + 11.0j ]])
637+
638+ sys = self .sysC322 + self .sysC222
639+
640+ np .testing .assert_array_almost_equal (sys .A , A )
641+ np .testing .assert_array_almost_equal (sys .B , B )
642+ np .testing .assert_array_almost_equal (sys .C , C )
643+ np .testing .assert_array_almost_equal (sys .D , D )
644+
645+ def test_subtract_ss_complex (self ):
646+ """Subtract two complex MIMO systems."""
647+
648+ A = np .array ([[6.0 + 9.0j , 8.0 + 9.0j , - 4.0 - 7.0j , 0.0 , 0.0 ],
649+ [8.0 - 7.0j , 3.0 , 1.0 - 1.0j , 0.0 , 0.0 ],
650+ [- 7.0 + 9.0j , - 8.0 + 6.0j , 9.0 + 8.0j , 0.0 , 0.0 ],
651+ [0.0 , 0.0 , 0.0 , - 4.0 - 7.0j , 3.0 + 9.0j ],
652+ [0.0 , 0.0 , 0.0 , 3.0 , - 6.0 - 3.0j ]])
653+ B = np .array ([[6.0 + 3.0j , - 9.0 - 2.0j ],
654+ [9.0 + 5.0j , 7.0 + 3.0j ],
655+ [3.0 + 5.0j , 8.0 - 6.0j ],
656+ [2.0 , 5.0 + 7.0j ],
657+ [- 5.0 + 4.0j , - 5.0 + 9.0j ]])
658+ C = np .array ([[4.0 + 4.0j , - 4.0 + 9.0j , - 8.0 - 1.0j , - 1.0 - 6.0j , 7.0 - 6.0j ],
659+ [- 9.0 - 3.0j , - 9.0 - 9.0j , 6.0 - 2.0j , 7.0 + 5.0j , 5.0 + 5.0j ]])
660+ D = np .array ([[- 3.0 - 3.0j , 7.0j ],
661+ [9.0 + 4.0j , 5.0 - 1.0j ]])
662+
663+ sys = self .sysC322 - self .sysC222
664+
665+ np .testing .assert_array_almost_equal (sys .A , A )
666+ np .testing .assert_array_almost_equal (sys .B , B )
667+ np .testing .assert_array_almost_equal (sys .C , C )
668+ np .testing .assert_array_almost_equal (sys .D , D )
669+
670+ def test_multiply_ss_complex (self ):
671+ """Multiply two complex MIMO systems."""
672+
673+ A = np .array ([[6.0 + 9.0j , 8.0 + 9.0j , - 4.0 - 7.0j , 41.0 + 98.0j , - 25.0 + 70.0j ],
674+ [8.0 - 7.0j , 3.0 , 1.0 - 1.0j , - 55.0 + 3.0j , - 113.0 - 31.0j ],
675+ [- 7.0 + 9.0j , - 8.0 + 6.0j , 9.0 + 8.0j , - 113.0 + 25.0j , - 121.0 - 27.0j ],
676+ [0.0 , 0.0 , 0.0 , - 4.0 - 7.0j , 3.0 + 9.0j ],
677+ [0.0 , 0.0 , 0.0 , 3.0 , - 6.0 - 3.0j ]])
678+ B = np .array ([[67.0 + 51.0j , 30.0 - 80.0j ],
679+ [44.0 + 42.0j , - 92.0 - 30.0j ],
680+ [- 16.0 + 56.0j , - 7.0 + 39.0j ],
681+ [2.0 , 5.0 + 7.0j ],
682+ [- 5.0 + 4.0j , - 5.0 + 9.0j ]])
683+ C = np .array ([[4.0 + 4.0j , - 4.0 + 9.0j , - 8.0 - 1.0j , 73.0 + 31.0j , 21.0 + 47.0j ],
684+ [- 9.0 - 3.0j , - 9.0 - 9.0j , 6.0 - 2.0j , 13.0 + 4.0j , - 35.0 - 10.0j ]])
685+ D = np .array ([[64.0 - 4.0j , - 27.0 - 65.0j ],
686+ [47.0 + 21.0j , - 57.0 - 61.0j ]])
687+
688+ sys = self .sysC322 * self .sysC222
689+
690+ np .testing .assert_array_almost_equal (sys .A , A )
691+ np .testing .assert_array_almost_equal (sys .B , B )
692+ np .testing .assert_array_almost_equal (sys .C , C )
693+ np .testing .assert_array_almost_equal (sys .D , D )
694+
695+ def test_evalfr (self ):
696+ """Evaluate the frequency response at one frequency."""
697+
698+ resp = [[4.6799374736968655 - 34.9854626345217383j ,
699+ - 10.8392352552155344 - 10.3778031623880267j ],
700+ [28.8313352973005479 + 17.1145433776227947j ,
701+ 5.6628990560933081 + 8.8759694583057787j ]]
702+
703+ # Correct versions of the call
704+ np .testing .assert_almost_equal (evalfr (sysC322 , 1j ), resp )
705+ np .testing .assert_almost_equal (sysC322 ._evalfr (1. ), resp )
706+
707+ # Deprecated version of the call (should generate warning)
708+ import warnings
709+ with warnings .catch_warnings (record = True ) as w :
710+ # Set up warnings filter to only show warnings in control module
711+ warnings .filterwarnings ("ignore" )
712+ warnings .filterwarnings ("always" , module = "control" )
713+
714+ # Make sure that we get a pending deprecation warning
715+ sys .evalfr (1. )
716+ assert len (w ) == 1
717+ assert issubclass (w [- 1 ].category , PendingDeprecationWarning )
718+
719+ @unittest .skipIf (not slycot_check (), "slycot not installed" )
720+ def test_freq_resp (self ):
721+ """Evaluate the frequency response at multiple frequencies."""
722+
723+ true_mag = [[15.2721178549527039 , 3.9176691825112484 , 20.5865790875032246 ],
724+ [24.5384389050919864 , 2.8374330975514015 , 18.2268344283306227 ]]
725+
726+ true_phase = [[1.0345533469994428 , 2.2133291186570987 , 2.6715324185062164 ],
727+ [1.8217663044282106 , - 2.8266936088743044 , 2.2694910839768196 ]]
728+ true_omega = [0.1 , 10 , 0.01j , - 1j ];
729+
730+ mag , phase , omega = sysC623 .freqresp (true_omega )
731+
732+ np .testing .assert_almost_equal (mag , true_mag )
733+ np .testing .assert_almost_equal (phase , true_phase )
734+ np .testing .assert_equal (omega , true_omega )
735+
736+
522737class TestRss (unittest .TestCase ):
523738 """These are tests for the proper functionality of statesp.rss."""
524739
0 commit comments