You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
StateSpace constructor should not call _remove_useless_states #244
State space representations should, in my opinion, not be reduced automatically with StateSpace._remove_useless_states(), similar to the fact that we don't call minreal() automatically.
Unlike transfer functions, state space models can model non-observable or non-controllable behaviour, and cannot always be considered equivalent to their minimized form. Additionally, it is rather confusing to have ss(A,B,C,D).A !== A and e.g. ss(A,B,C,D).sample(T).A !== expm(A*T). For a more object-oriented interface, it would also be great to have member functions like stateSpace.isControllable(), which do not make sense if the system has already been minimized.
To give an example: The autonomous system x'=0, y=x is a signal model for the constant output y=x(0). It is not equivalent to the system y=0 if you consider the initial response for x(0) !== 0.
import control
print(control.__version__)
print(control.ss(0,0,1,0)) # expected: A,B,C,D unchanged from input
print(control.ss(0,0,1,0).sample(1)) # expected: ss(1,0,1,0, dt=1)
output:
0.8.0
A = []
B = []
C = []
D = [[0]]
A = []
B = []
C = []
D = [[0]]
dt = 1
Is there a reason for the current behavior, or would it be okay to change it?
One thing to think through is whether anything "breaks" if we stop calling _remove_useless_states(). Eg, are there operations that create spurious states that were getting reduced out?
Perhaps create a branch, try removing that call to _remove_useless_states() and see if unit tests pass?
The current master branch allows you to specify the keyword remove_useless=False when creating a state space system, which will keep all states. This is not yet in the release code, but should be part of release 0.8.3.
Anybody know why _remove_useless_states was added in the first place? I ran unit tests and a lot of failures are simply because the test assumes. rows of zeros ought to be removed.
Is it something to do with extra states being added in the the course of interconnecting systems, e.g. feedback?
This may be something useful to fix in 0.9.0, since we will be breaking some user code in any case.
I'll take a crack at removing it and seeing how much change is required to unit tests and whether there is anything that seems like it is going to cause problems.
Found something unexpected in the way that the feedback function was implemented: if you pass a constant as one of the arguments for feedback (eg, feedback(P*C, 1)) then the constant was being converted to a state space system with a single state and B=0, C=0. This gives the right input/output response, but created an unobservable/uncontrollable (= "useless") state. This generated a half dozen or so errors when I switched remove_useless_states to False since systems had an "extra" state.
By changing the statesp._convert_to_state_space function to create a state space with no state (A = []) the problem went away and all but one unit test passed. That unit test was explicitly testing that useless states were removed, so had to pass remove_useless_states=True to make that happen.
With that fix, everything appears to work. PR coming as soon as I confirm via CI.
Activity
murrayrm commentedon Nov 14, 2018
I agree with this comment.
One thing to think through is whether anything "breaks" if we stop calling
_remove_useless_states(). Eg, are there operations that create spurious states that were getting reduced out?Perhaps create a branch, try removing that call to
_remove_useless_states()and see if unit tests pass?MaxGaukler commentedon Nov 20, 2018
Lots of tests break if the call is removed, mainly blockdiagram algebra (LTI system interconnection) and some others which may be caused by that (rlocus, LQR). It seems that some more effort is required.
https://github.com/MaxGaukler/python-control/tree/remove-useless-states
https://travis-ci.org/MaxGaukler/python-control/jobs/457349504#L4054
DapRock commentedon Aug 14, 2019
I'm having the same problem with the system order reduction. I've tried to use the library to work with a Luenberger observer which assumes a state as invariant in time and I'm getting this same state being reduced in the problem. I have better description here: https://stackoverflow.com/questions/57484563/why-some-a-state-is-removed-from-the-model-while-using-control-ss-in-python
Do you have any tip to workaround in this case? Thanks for your time!
murrayrm commentedon Aug 15, 2019
The current master branch allows you to specify the keyword
remove_useless=Falsewhen creating a state space system, which will keep all states. This is not yet in the release code, but should be part of release 0.8.3.sawyerbfuller commentedon Jul 23, 2020
Anybody know why _
remove_useless_stateswas added in the first place? I ran unit tests and a lot of failures are simply because the test assumes. rows of zeros ought to be removed.Is it something to do with extra states being added in the the course of interconnecting systems, e.g. feedback?
murrayrm commentedon Jan 15, 2021
This may be something useful to fix in 0.9.0, since we will be breaking some user code in any case.
I'll take a crack at removing it and seeing how much change is required to unit tests and whether there is anything that seems like it is going to cause problems.
murrayrm commentedon Jan 15, 2021
Found something unexpected in the way that the
feedbackfunction was implemented: if you pass a constant as one of the arguments forfeedback(eg,feedback(P*C, 1)) then the constant was being converted to a state space system with a single state and B=0, C=0. This gives the right input/output response, but created an unobservable/uncontrollable (= "useless") state. This generated a half dozen or so errors when I switchedremove_useless_statestoFalsesince systems had an "extra" state.By changing the
statesp._convert_to_state_spacefunction to create a state space with no state (A = []) the problem went away and all but one unit test passed. That unit test was explicitly testing that useless states were removed, so had to passremove_useless_states=Trueto make that happen.With that fix, everything appears to work. PR coming as soon as I confirm via CI.
murrayrm commentedon Jan 18, 2021
Fixed in #509.