@@ -849,7 +849,8 @@ def test_gainsched_unicycle(unicycle, method):
849849 # Make sure that gains are different from 'nearest'
850850 if method is not None and method != 'nearest' :
851851 ctrl_nearest , clsys_nearest = ct .create_statefbk_iosystem (
852- unicycle , (gains , points , 'nearest' ), gainsched_indices = [3 , 2 ])
852+ unicycle , (gains , points , 'nearest' ),
853+ gainsched_indices = ['ud[0]' , 2 ])
853854 nearest_lin = clsys_nearest .linearize (xe , [xd , ud ])
854855 assert not np .allclose (
855856 np .sort (clsys_lin .poles ()), np .sort (nearest_lin .poles ()), rtol = 1e-2 )
@@ -880,7 +881,8 @@ def test_gainsched_unicycle(unicycle, method):
880881
881882 # Create gain scheduled controller
882883 ctrl , clsys = ct .create_statefbk_iosystem (
883- unicycle , (gains , points ), gainsched_indices = [3 , 7 ])
884+ unicycle , (gains , points ),
885+ ud_labels = ['vd' , 'phid' ], gainsched_indices = ['vd' , 'theta' ])
884886
885887 # Check the gain at the selected points
886888 for speed , angle in points :
@@ -903,3 +905,43 @@ def test_gainsched_unicycle(unicycle, method):
903905 resp = ct .input_output_response (clsys , timepts , [Xd , Ud ], X0 )
904906 np .testing .assert_allclose (
905907 resp .states [:, - 1 ], Xd [:, - 1 ], atol = 1e-2 , rtol = 1e-2 )
908+
909+ def test_gainsched_errors (unicycle ):
910+ # Set up gain schedule (same as previous test)
911+ speeds = [1 , 5 , 10 ]
912+ angles = np .linspace (0 , pi / 2 , 4 )
913+ points = list (itertools .product (speeds , angles ))
914+
915+ Q = np .identity (unicycle .nstates )
916+ R = np .identity (unicycle .ninputs )
917+ gains = [np .array (ct .lqr (unicycle .linearize (
918+ [0 , 0 , angle ], [speed , 0 ]), Q , R )[0 ]) for speed , angle in points ]
919+
920+ # Make sure the generic case works OK
921+ ctrl , clsys = ct .create_statefbk_iosystem (
922+ unicycle , (gains , points ), gainsched_indices = [3 , 2 ])
923+ xd , ud = np .array ([0 , 0 , angles [0 ]]), np .array ([speeds [0 ], 0 ])
924+ ctrl_lin = ctrl .linearize ([], [xd , ud , xd * 0 ])
925+ K , S , E = ct .lqr (unicycle .linearize (xd , ud ), Q , R )
926+ np .testing .assert_allclose (
927+ ctrl_lin .D [- xd .size :, - xd .size :], - K , rtol = 1e-2 )
928+
929+ # Wrong type of gain schedule argument
930+ with pytest .raises (ControlArgument , match = "gain must be an array" ):
931+ ctrl , clsys = ct .create_statefbk_iosystem (
932+ unicycle , [gains , points ], gainsched_indices = [3 , 2 ])
933+
934+ # Mismatched dimensions for gains and points
935+ with pytest .raises (ControlArgument , match = "length of gainsched_indices" ):
936+ ctrl , clsys = ct .create_statefbk_iosystem (
937+ unicycle , (gains , [speeds ]), gainsched_indices = [3 , 2 ])
938+
939+ # Unknown gain scheduling variable label
940+ with pytest .raises (ValueError , match = ".* not in list" ):
941+ ctrl , clsys = ct .create_statefbk_iosystem (
942+ unicycle , (gains , points ), gainsched_indices = ['stuff' , 2 ])
943+
944+ # Unknown gain scheduling method
945+ with pytest .raises (ControlArgument , match = "unknown gain scheduling method" ):
946+ ctrl , clsys = ct .create_statefbk_iosystem (
947+ unicycle , (gains , points , 'stuff' ), gainsched_indices = [3 , 2 ])
0 commit comments