@@ -347,7 +347,7 @@ def test_impulse_response_mimo(self, mimo_ss2):
347347 yref_notrim = np .zeros ((2 , len (t )))
348348 yref_notrim [:1 , :] = yref
349349 _t , yy = impulse_response (sys , T = t , input = 0 )
350- np .testing .assert_array_almost_equal (yy , yref_notrim , decimal = 4 )
350+ np .testing .assert_array_almost_equal (yy [:, 0 ,:] , yref_notrim , decimal = 4 )
351351
352352 @pytest .mark .skipif (StrictVersion (sp .__version__ ) < "1.3" ,
353353 reason = "requires SciPy 1.3 or greater" )
@@ -639,9 +639,10 @@ def test_time_vector(self, tsystem, fun, squeeze, matarrayout):
639639 if hasattr (tsystem , 't' ):
640640 # tout should always match t, which has shape (n, )
641641 np .testing .assert_allclose (tout , tsystem .t )
642- if squeeze is False or sys .outputs > 1 :
642+
643+ if squeeze is False or not sys .issiso ():
643644 assert yout .shape [0 ] == sys .outputs
644- assert yout .shape [1 ] == tout .shape [0 ]
645+ assert yout .shape [- 1 ] == tout .shape [0 ]
645646 else :
646647 assert yout .shape == tout .shape
647648
@@ -725,21 +726,22 @@ def test_time_series_data_convention_2D(self, siso_ss1):
725726
726727 @pytest .mark .usefixtures ("editsdefaults" )
727728 @pytest .mark .parametrize ("fcn" , [ct .ss , ct .tf , ct .ss2io ])
728- @pytest .mark .parametrize ("nstate, nout, ninp, squeeze, shape" , [
729- [1 , 1 , 1 , None , (8 ,)],
730- [2 , 1 , 1 , True , (8 ,)],
731- [3 , 1 , 1 , False , (1 , 8 )],
732- [3 , 2 , 1 , None , (2 , 8 )],
733- [4 , 2 , 1 , True , (2 , 8 )],
734- [5 , 2 , 1 , False , (2 , 8 )],
735- [3 , 1 , 2 , None , (1 , 8 )],
736- [4 , 1 , 2 , True , (8 ,)],
737- [5 , 1 , 2 , False , (1 , 8 )],
738- [4 , 2 , 2 , None , (2 , 8 )],
739- [5 , 2 , 2 , True , (2 , 8 )],
740- [6 , 2 , 2 , False , (2 , 8 )],
729+ @pytest .mark .parametrize ("nstate, nout, ninp, squeeze, shape1, shape2" , [
730+ # state out in squeeze in/out out-only
731+ [1 , 1 , 1 , None , (8 ,), (8 ,)],
732+ [2 , 1 , 1 , True , (8 ,), (8 ,)],
733+ [3 , 1 , 1 , False , (1 , 1 , 8 ), (1 , 8 )],
734+ [3 , 2 , 1 , None , (2 , 1 , 8 ), (2 , 8 )],
735+ [4 , 2 , 1 , True , (2 , 8 ), (2 , 8 )],
736+ [5 , 2 , 1 , False , (2 , 1 , 8 ), (2 , 8 )],
737+ [3 , 1 , 2 , None , (1 , 2 , 8 ), (1 , 8 )],
738+ [4 , 1 , 2 , True , (2 , 8 ), (8 ,)],
739+ [5 , 1 , 2 , False , (1 , 2 , 8 ), (1 , 8 )],
740+ [4 , 2 , 2 , None , (2 , 2 , 8 ), (2 , 8 )],
741+ [5 , 2 , 2 , True , (2 , 2 , 8 ), (2 , 8 )],
742+ [6 , 2 , 2 , False , (2 , 2 , 8 ), (2 , 8 )],
741743 ])
742- def test_squeeze (self , fcn , nstate , nout , ninp , squeeze , shape ):
744+ def test_squeeze (self , fcn , nstate , nout , ninp , squeeze , shape1 , shape2 ):
743745 # Figure out if we have SciPy 1+
744746 scipy0 = StrictVersion (sp .__version__ ) < '1.0'
745747
@@ -750,27 +752,56 @@ def test_squeeze(self, fcn, nstate, nout, ninp, squeeze, shape):
750752 else :
751753 sys = fcn (ct .rss (nstate , nout , ninp , strictly_proper = True ))
752754
753- # Keep track of expect users warnings
754- warntype = UserWarning if sys .inputs > 1 else None
755-
756755 # Generate the time and input vectors
757756 tvec = np .linspace (0 , 1 , 8 )
758757 uvec = np .dot (
759758 np .ones ((sys .inputs , 1 )),
760759 np .reshape (np .sin (tvec ), (1 , 8 )))
761760
761+ #
762762 # Pass squeeze argument and make sure the shape is correct
763- with pytest .warns (warntype , match = "Converting MIMO system" ):
764- _ , yvec = ct .impulse_response (sys , tvec , squeeze = squeeze )
765- assert yvec .shape == shape
763+ #
764+ # For responses that are indexed by the input, check against shape1
765+ # For responses that have no/fixed input, check against shape2
766+ #
766767
767- _ , yvec = ct .initial_response (sys , tvec , 1 , squeeze = squeeze )
768- assert yvec .shape == shape
768+ # Impulse response
769+ if isinstance (sys , StateSpace ):
770+ # Check the states as well
771+ _ , yvec , xvec = ct .impulse_response (
772+ sys , tvec , squeeze = squeeze , return_x = True )
773+ if sys .issiso ():
774+ assert xvec .shape == (sys .states , 8 )
775+ else :
776+ assert xvec .shape == (sys .states , sys .inputs , 8 )
777+ else :
778+ _ , yvec = ct .impulse_response (sys , tvec , squeeze = squeeze )
779+ assert yvec .shape == shape1
769780
770- with pytest .warns (warntype , match = "Converting MIMO system" ):
781+ # Step response
782+ if isinstance (sys , StateSpace ):
783+ # Check the states as well
784+ _ , yvec , xvec = ct .step_response (
785+ sys , tvec , squeeze = squeeze , return_x = True )
786+ if sys .issiso ():
787+ assert xvec .shape == (sys .states , 8 )
788+ else :
789+ assert xvec .shape == (sys .states , sys .inputs , 8 )
790+ else :
771791 _ , yvec = ct .step_response (sys , tvec , squeeze = squeeze )
772- assert yvec .shape == shape
792+ assert yvec .shape == shape1
793+
794+ # Initial response (only indexed by output)
795+ if isinstance (sys , StateSpace ):
796+ # Check the states as well
797+ _ , yvec , xvec = ct .initial_response (
798+ sys , tvec , 1 , squeeze = squeeze , return_x = True )
799+ assert xvec .shape == (sys .states , 8 )
800+ else :
801+ _ , yvec = ct .initial_response (sys , tvec , 1 , squeeze = squeeze )
802+ assert yvec .shape == shape2
773803
804+ # Forced response (only indexed by output)
774805 if isinstance (sys , StateSpace ):
775806 # Check the states as well
776807 _ , yvec , xvec = ct .forced_response (
@@ -779,52 +810,54 @@ def test_squeeze(self, fcn, nstate, nout, ninp, squeeze, shape):
779810 else :
780811 # Just check the input/output response
781812 _ , yvec = ct .forced_response (sys , tvec , uvec , 0 , squeeze = squeeze )
782- assert yvec .shape == shape
813+ assert yvec .shape == shape2
783814
784815 # Test cases where we choose a subset of inputs and outputs
785816 _ , yvec = ct .step_response (
786817 sys , tvec , input = ninp - 1 , output = nout - 1 , squeeze = squeeze )
787- # Possible code if we implemenet a squeeze='siso' option
788818 if squeeze is False :
789819 # Shape should be unsqueezed
790- assert yvec .shape == (1 , 8 )
820+ assert yvec .shape == (1 , 1 , 8 )
791821 else :
792822 # Shape should be squeezed
793823 assert yvec .shape == (8 , )
794824
795- # For InputOutputSystems, also test input_output_response
825+ # For InputOutputSystems, also test input/output response
796826 if isinstance (sys , ct .InputOutputSystem ) and not scipy0 :
797827 _ , yvec = ct .input_output_response (sys , tvec , uvec , squeeze = squeeze )
798- assert yvec .shape == shape
828+ assert yvec .shape == shape2
799829
800830 #
801831 # Changing config.default to False should return 3D frequency response
802832 #
803833 ct .config .set_defaults ('control' , squeeze_time_response = False )
804834
805- with pytest . warns ( warntype , match = "Converting MIMO system" ):
806- _ , yvec = ct . impulse_response ( sys , tvec )
807- assert yvec .shape == (sys .outputs , 8 )
835+ _ , yvec = ct . impulse_response ( sys , tvec )
836+ if squeeze is not True or sys . inputs > 1 or sys . outputs > 1 :
837+ assert yvec .shape == (sys .outputs , sys . inputs , 8 )
808838
809- _ , yvec = ct .initial_response (sys , tvec , 1 )
810- assert yvec .shape == (sys .outputs , 8 )
839+ _ , yvec = ct .step_response (sys , tvec )
840+ if squeeze is not True or sys .inputs > 1 or sys .outputs > 1 :
841+ assert yvec .shape == (sys .outputs , sys .inputs , 8 )
811842
812- with pytest . warns ( warntype , match = "Converting MIMO system" ):
813- _ , yvec = ct . step_response ( sys , tvec )
814- assert yvec .shape == (sys .outputs , 8 )
843+ _ , yvec = ct . initial_response ( sys , tvec , 1 )
844+ if squeeze is not True or sys . outputs > 1 :
845+ assert yvec .shape == (sys .outputs , 8 )
815846
816847 if isinstance (sys , ct .StateSpace ):
817848 _ , yvec , xvec = ct .forced_response (
818849 sys , tvec , uvec , 0 , return_x = True )
819850 assert xvec .shape == (sys .states , 8 )
820851 else :
821852 _ , yvec = ct .forced_response (sys , tvec , uvec , 0 )
822- assert yvec .shape == (sys .outputs , 8 )
853+ if squeeze is not True or sys .outputs > 1 :
854+ assert yvec .shape == (sys .outputs , 8 )
823855
824856 # For InputOutputSystems, also test input_output_response
825857 if isinstance (sys , ct .InputOutputSystem ) and not scipy0 :
826858 _ , yvec = ct .input_output_response (sys , tvec , uvec )
827- assert yvec .shape == (sys .noutputs , 8 )
859+ if squeeze is not True or sys .outputs > 1 :
860+ assert yvec .shape == (sys .outputs , 8 )
828861
829862 @pytest .mark .parametrize ("fcn" , [ct .ss , ct .tf , ct .ss2io ])
830863 def test_squeeze_exception (self , fcn ):
@@ -861,3 +894,37 @@ def test_squeeze_0_8_4(self, nstate, nout, ninp, squeeze, shape):
861894
862895 _ , yvec = ct .initial_response (sys , tvec , 1 , squeeze = squeeze )
863896 assert yvec .shape == shape
897+
898+ @pytest .mark .parametrize (
899+ "nstate, nout, ninp, squeeze, ysh_in, ysh_no, xsh_in" , [
900+ [4 , 1 , 1 , None , (8 ,), (8 ,), (8 , 4 )],
901+ [4 , 1 , 1 , True , (8 ,), (8 ,), (8 , 4 )],
902+ [4 , 1 , 1 , False , (8 , 1 , 1 ), (8 , 1 ), (8 , 4 )],
903+ [4 , 2 , 1 , None , (8 , 2 , 1 ), (8 , 2 ), (8 , 4 , 1 )],
904+ [4 , 2 , 1 , True , (8 , 2 ), (8 , 2 ), (8 , 4 , 1 )],
905+ [4 , 2 , 1 , False , (8 , 2 , 1 ), (8 , 2 ), (8 , 4 , 1 )],
906+ [4 , 1 , 2 , None , (8 , 1 , 2 ), (8 , 1 ), (8 , 4 , 2 )],
907+ [4 , 1 , 2 , True , (8 , 2 ), (8 ,), (8 , 4 , 2 )],
908+ [4 , 1 , 2 , False , (8 , 1 , 2 ), (8 , 1 ), (8 , 4 , 2 )],
909+ [4 , 2 , 2 , None , (8 , 2 , 2 ), (8 , 2 ), (8 , 4 , 2 )],
910+ [4 , 2 , 2 , True , (8 , 2 , 2 ), (8 , 2 ), (8 , 4 , 2 )],
911+ [4 , 2 , 2 , False , (8 , 2 , 2 ), (8 , 2 ), (8 , 4 , 2 )],
912+ ])
913+ def test_response_transpose (
914+ self , nstate , nout , ninp , squeeze , ysh_in , ysh_no , xsh_in ):
915+ sys = ct .rss (nstate , nout , ninp )
916+ T = np .linspace (0 , 1 , 8 )
917+
918+ # Step response - input indexed
919+ t , y , x = ct .step_response (
920+ sys , T , transpose = True , return_x = True , squeeze = squeeze )
921+ assert t .shape == (T .size , )
922+ assert y .shape == ysh_in
923+ assert x .shape == xsh_in
924+
925+ # Initial response - no input indexing
926+ t , y , x = ct .initial_response (
927+ sys , T , 1 , transpose = True , return_x = True , squeeze = squeeze )
928+ assert t .shape == (T .size , )
929+ assert y .shape == ysh_no
930+ assert x .shape == (T .size , sys .states )
0 commit comments