Skip to content

lqe default input noise matrix is undocumented and differs from Octave #1159

Description

@bbbccd
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

Activity

  1. sawyerbfuller commented on Jun 30, 2025

    @sawyerbfuller
    Contributor

    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.

  2. bbbccd commented on Jul 4, 2025

    @bbbccd
    Author

    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:

    pkg load control
    
    A = [ 0 1 0;
          0 0 1;
          0 0 0];
    B = [0;0;1];
    C = [1 0 0];
    D = [0];
    
    sys=ss(A,B,C,D);
    rank(ctrb(A,B));
    rank(obsv(A,C));
    
    [L,_,_]=lqe(A,diag([1 1 1]),C,diag([1 1 1]),[1]);
    L
    [L,_,_]=lqe(sys,diag([1 1 1]),[1]);
    L

    returns

    L =
    
       2.4142
       2.4142
       1.0000
    
    L =
    
       2.4142
       2.4142
       1.0000
    
  3. sawyerbfuller commented on Jul 4, 2025

    @sawyerbfuller
    Contributor

    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?

  4. murrayrm commented on Jul 4, 2025

    @murrayrm
    Member

    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$.

  5. bbbccd commented on Jul 4, 2025

    @bbbccd
    Author

    If you don't mind my thoughts:

    • 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 .

    :D yes. and thank you.

  6. murrayrm commented on Jul 4, 2025

    @murrayrm
    Member

    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.

  7. changed the title [-]lqe does not work with 3 arguments[/-] [+]lqe default input noise matrix differs from Octave[/+] on Jul 4, 2025
  8. 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
  9. bbbccd commented on Jul 4, 2025

    @bbbccd
    Author

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions