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
lqe default input noise matrix is undocumented and differs from Octave #1159
from control import lqe,ss,ctrb,obsv
from numpy import diag,array
from numpy.linalg import matrix_rank
A = array([ [0,1,0],
[0,0,1],
[0,0,0]])
B = array([[0],[0],[1]])
C = array([[1,0,0]])
D = array([[0]])
sys=ss(A,B,C,D)
print(matrix_rank(ctrb(A,B)))
print(matrix_rank(obsv(A,C)))
L,_,_=lqe(A,diag([1,1,1]),C,diag([1,1,1]),array([[1]]))
print(L)
L,_,_=lqe(sys,diag([1,1,1]),array([[1]]))
outputs
3
3
[[2.41421356]
[2.41421356]
[1. ]]
Traceback (most recent call last):
File "/home/paul/Documents/paul/personal/properly named/tippy control with better control/test_lqe.py", line 19, in <module>
L,_,_=lqe(sys,diag([1,1,1]),array([[1]]))
~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/paul/Documents/paul/personal/properly named/tippy control with better control/.venv/lib/python3.13/site-packages/control/stochsys.py", line 176, in lqe
_check_shape("QN", QN, G.shape[1], G.shape[1])
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/paul/Documents/paul/personal/properly named/tippy control with better control/.venv/lib/python3.13/site-packages/control/mateqn.py", line 643, in _check_shape
raise ControlDimension("Incompatible dimensions of %s matrix" % name)
control.exception.ControlDimension: Incompatible dimensions of QN matrix
if the G matrix is manually specified lqe works, otherwise it seems to find a dimension mismatch
Hi @ovhnw I think the library is doing the right thing here.
In the first call to lqe, your G = diag([1,1,1]) matrix has three columns, corresponding to three disturbance inputs, so it works because you have specified a 3x3 disturbance covariance matrix QN.
In your second call, G is assumed to be the B in your state-space system, which has one column (as does D), so sys has one disturbance input. So it raises a an error because you ahve specified the same 3x3 disturbance covariance matrix, which assumes three inputs.
Feel free to reopen if you think I'm missing something.
In your second call, G is assumed to be the B in your state-space system, which has one column (as does D), so sys has one disturbance input.
Are you sure this is what is conventionally assumed?
For example, octave has a similar method signature, and it works just fine with both methods and returns the same result in each case:
pkgload control
A = [ 010;
001;
000];
B = [0;0;1];
C = [100];
D = [0];
sys=ss(A,B,C,D);
rank(ctrb(A,B));
rank(obsv(A,C));
[L,_,_]=lqe(A,diag([111]),C,diag([111]),[1]);
L
[L,_,_]=lqe(sys,diag([111]),[1]);
L
I remember when we chose to use B as G when passed a system, and that I wasn’t convinced one way or the other at the time whether that was the right choice.
It may be (I will have to double check) that Octave is assuming G=diag(ones(m)), which may turn out to be a better assumption.
Here's my two cents: when we are talking about the "noise" entering the state, we are usually talking about external disturbances (eg, wind forces on an aircraft). To me, these disturbances need to enter the system in a structure way and they rarely affect all of the states. For the aircraft, for example, wind acts as a force => it directly affects the derivative of the velocity but not derivative of the position (except through the velocity) => you need a $G$ matrix to capture that. For an example of this type of thinking, see OBC, Section 6.5.
If no $G$ matrix is specified, then a reasonable assumption is that the disturbances enter in the same places as the inputs, and so disturbances are the same as "input noise".
Note that for the outputs, we don't have an equivalent matrix. This makes sense to me since usually measurement noise affects all measurements (with different amounts of noise being reflected in the covariance matrix RN.
The one thing we do need to take care of is documenting the fact that if $G$ is not specified, then its default value is $B$.
My college course notes "book" does not use a G matrix. (implied identity?)
There is a duality between LQR and LQE. They have the same Algebraic Riccati Equation structure. So you can do lqr(A,C',Q,R)' (or something, i don't remember for sure offhand) as an equivalent for lqe. If there is no dual to the G matrix in lqr (is there? i'm not sure), then perhaps the identity may be the only default that preserves this duality.
I took a quick look at matlab's kalman and G seems to be included as part of B.
My vote would go to an identity for default.
The one thing we do need to take care of is documenting the fact that if G is not specified, then its default value is B .
I don't have a strong preference, as long as we leave in the option for $G$ to be specified somehow. We should also be aware that if we change the default, we could break existing code => we should probably either issues a warning or provide some other indication that behavior has changed (and we might wait until v0.11.x before changing the default).
changed the title [-]lqe default input noise matrix differs from Octave[/-][+]lqe default input noise matrix is undocumented and differs from Octave[/+]on Jul 4, 2025
i should point out, although the current behavior deceptively differs from octave's lqe, it may be compatible with matlab's kalman. You might even be able to adapt your code to accept the [B G] style B matrices without breaking existing code.
sidenote: it is unfortunate that matlab decided to format the B matrices as [B G], instead of [G B], which is the convention for robust control.
Activity
sawyerbfuller commentedon Jun 30, 2025
Hi @ovhnw I think the library is doing the right thing here.
In the first call to
lqe, yourG = diag([1,1,1])matrix has three columns, corresponding to three disturbance inputs, so it works because you have specified a 3x3 disturbance covariance matrixQN.In your second call,
Gis assumed to be theBin your state-space system, which has one column (as doesD), sosyshas one disturbance input. So it raises a an error because you ahve specified the same 3x3 disturbance covariance matrix, which assumes three inputs.Feel free to reopen if you think I'm missing something.
bbbccd commentedon Jul 4, 2025
Are you sure this is what is conventionally assumed?
For example, octave has a similar method signature, and it works just fine with both methods and returns the same result in each case:
returns
sawyerbfuller commentedon Jul 4, 2025
I remember when we chose to use B as G when passed a system, and that I wasn’t convinced one way or the other at the time whether that was the right choice.
It may be (I will have to double check) that Octave is assuming G=diag(ones(m)), which may turn out to be a better assumption.
What do you think?
murrayrm commentedon Jul 4, 2025
Here's my two cents: when we are talking about the "noise" entering the state, we are usually talking about external disturbances (eg, wind forces on an aircraft). To me, these disturbances need to enter the system in a structure way and they rarely affect all of the states. For the aircraft, for example, wind acts as a force => it directly affects the derivative of the velocity but not derivative of the position (except through the velocity) => you need a$G$ matrix to capture that. For an example of this type of thinking, see OBC, Section 6.5.
If no$G$ matrix is specified, then a reasonable assumption is that the disturbances enter in the same places as the inputs, and so disturbances are the same as "input noise".
Note that for the outputs, we don't have an equivalent matrix. This makes sense to me since usually measurement noise affects all measurements (with different amounts of noise being reflected in the covariance matrix
RN.The one thing we do need to take care of is documenting the fact that if$G$ is not specified, then its default value is $B$ .
bbbccd commentedon Jul 4, 2025
If you don't mind my thoughts:
lqr(A,C',Q,R)'(or something, i don't remember for sure offhand) as an equivalent for lqe. If there is no dual to the G matrix in lqr (is there? i'm not sure), then perhaps the identity may be the only default that preserves this duality.kalmanand G seems to be included as part of B.My vote would go to an identity for default.
:D yes. and thank you.
murrayrm commentedon Jul 4, 2025
Thoughts definitely welcome @ovhnw!
I don't have a strong preference, as long as we leave in the option for$G$ to be specified somehow. We should also be aware that if we change the default, we could break existing code => we should probably either issues a warning or provide some other indication that behavior has changed (and we might wait until v0.11.x before changing the default).
Reopening this issue, but changing the title.
[-]lqe does not work with 3 arguments[/-][+]lqe default input noise matrix differs from Octave[/+][-]lqe default input noise matrix differs from Octave[/-][+]lqe default input noise matrix is undocumented and differs from Octave[/+]bbbccd commentedon Jul 4, 2025
i should point out, although the current behavior deceptively differs from octave's
lqe, it may be compatible with matlab'skalman. You might even be able to adapt your code to accept the[B G]style B matrices without breaking existing code.sidenote: it is unfortunate that matlab decided to format the B matrices as
[B G], instead of[G B], which is the convention for robust control.