From 114bce6499a05f4fd3d4d2dee2818e9aaa9964f2 Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Thu, 14 Jan 2021 22:49:56 -0800 Subject: [PATCH 1/2] change default value of statesp.remove_useless_states to False --- control/config.py | 3 +++ control/statesp.py | 20 +++++++++++++------- control/tests/statesp_test.py | 10 +++------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/control/config.py b/control/config.py index b4950ae5e..a81d8347f 100644 --- a/control/config.py +++ b/control/config.py @@ -226,4 +226,7 @@ def use_legacy_defaults(version): linearized_system_name_prefix='', linearized_system_name_suffix='_linearized') + # turned off _remove_useless_states + set_defaults('statesp', remove_useless_states=True) + return (major, minor, patch) diff --git a/control/statesp.py b/control/statesp.py index ff4c73c4e..0be783bce 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -72,7 +72,7 @@ # Define module default parameter values _statesp_defaults = { 'statesp.use_numpy_matrix': False, # False is default in 0.9.0 and above - 'statesp.remove_useless_states': True, + 'statesp.remove_useless_states': False, 'statesp.latex_num_format': '.3g', 'statesp.latex_repr_type': 'partitioned', } @@ -217,8 +217,7 @@ class StateSpace(LTI): __array_priority__ = 11 # override ndarray and matrix types def __init__(self, *args, **kwargs): - """ - StateSpace(A, B, C, D[, dt]) + """StateSpace(A, B, C, D[, dt]) Construct a state space object. @@ -228,6 +227,13 @@ def __init__(self, *args, **kwargs): True for unspecified sampling time). To call the copy constructor, call StateSpace(sys), where sys is a StateSpace object. + The `remove_useless_states` keyword can be used to scan the A, B, and + C matrices for rows or columns of zeros. If the zeros are such that a + particular state has no effect on the input-output dynamics, then that + state is removed from the A, B, and C matrices. If not specified, the + value is read from `config.defaults['statesp.remove_useless_states'] + (default = False). + """ # first get A, B, C, D matrices if len(args) == 4: @@ -251,8 +257,8 @@ def __init__(self, *args, **kwargs): "Expected 1, 4, or 5 arguments; received %i." % len(args)) # Process keyword arguments - remove_useless = kwargs.get( - 'remove_useless', + remove_useless_states = kwargs.get( + 'remove_useless_states', config.defaults['statesp.remove_useless_states']) # Convert all matrices to standard form @@ -321,7 +327,7 @@ def __init__(self, *args, **kwargs): raise ValueError("C and D must have the same number of rows.") # Check for states that don't do anything, and remove them. - if remove_useless: + if remove_useless_states: self._remove_useless_states() def _remove_useless_states(self): @@ -1274,7 +1280,7 @@ def _convert_to_statespace(sys, **kw): # Generate a simple state space system of the desired dimension # The following Doesn't work due to inconsistencies in ltisys: # return StateSpace([[]], [[]], [[]], eye(outputs, inputs)) - return StateSpace(0., zeros((1, inputs)), zeros((outputs, 1)), + return StateSpace([], zeros((0, inputs)), zeros((outputs, 0)), sys * ones((outputs, inputs))) # If this is a matrix, try to create a constant feedthrough diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 8a91da68b..43f9e236a 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -395,9 +395,6 @@ def test_is_static_gain(self): D0 = 0 D1 = np.ones((2,1)) assert StateSpace(A0, B0, C1, D1).is_static_gain() - # TODO: fix this once remove_useless_states is false by default - # should be False when remove_useless is false - # print(StateSpace(A1, B0, C1, D1).is_static_gain()) assert not StateSpace(A0, B1, C1, D1).is_static_gain() assert not StateSpace(A1, B1, C1, D1).is_static_gain() assert StateSpace(A0, B0, C0, D0).is_static_gain() @@ -586,10 +583,9 @@ def test_matrix_static_gain(self): def test_remove_useless_states(self): """Regression: _remove_useless_states gives correct ABC sizes.""" - g1 = StateSpace(np.zeros((3, 3)), - np.zeros((3, 4)), - np.zeros((5, 3)), - np.zeros((5, 4))) + g1 = StateSpace(np.zeros((3, 3)), np.zeros((3, 4)), + np.zeros((5, 3)), np.zeros((5, 4)), + remove_useless_states=True) assert (0, 0) == g1.A.shape assert (0, 4) == g1.B.shape assert (5, 0) == g1.C.shape From b7945f3b39ef61d88e6a4ce6137e3de1c281aedd Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Fri, 15 Jan 2021 08:18:58 -0800 Subject: [PATCH 2/2] added missing unit test --- control/tests/statesp_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 43f9e236a..ccbd06881 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -395,6 +395,7 @@ def test_is_static_gain(self): D0 = 0 D1 = np.ones((2,1)) assert StateSpace(A0, B0, C1, D1).is_static_gain() + assert not StateSpace(A1, B0, C1, D1).is_static_gain() assert not StateSpace(A0, B1, C1, D1).is_static_gain() assert not StateSpace(A1, B1, C1, D1).is_static_gain() assert StateSpace(A0, B0, C0, D0).is_static_gain()