@@ -849,7 +849,8 @@ def test_gainsched_unicycle(unicycle, method):
849
849
# Make sure that gains are different from 'nearest'
850
850
if method is not None and method != 'nearest' :
851
851
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 ])
853
854
nearest_lin = clsys_nearest .linearize (xe , [xd , ud ])
854
855
assert not np .allclose (
855
856
np .sort (clsys_lin .poles ()), np .sort (nearest_lin .poles ()), rtol = 1e-2 )
@@ -880,7 +881,8 @@ def test_gainsched_unicycle(unicycle, method):
880
881
881
882
# Create gain scheduled controller
882
883
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' ])
884
886
885
887
# Check the gain at the selected points
886
888
for speed , angle in points :
@@ -903,3 +905,43 @@ def test_gainsched_unicycle(unicycle, method):
903
905
resp = ct .input_output_response (clsys , timepts , [Xd , Ud ], X0 )
904
906
np .testing .assert_allclose (
905
907
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