LQE

The linear quadratic estimator (LQE), commonly known as the Kalman filter, calculates the optimal estimator gain matrix L to minimize the state estimation error covariance for a system with process noise and measurement noise.

Given covariances QN (process noise) and RN (sensor noise), it produces the gain L for the stationary Kalman filter: \dot{x}_e = A x_e + B u + L(y - C x_e - D u)

Excel Usage

=LQE(A, G, C, QN, RN, NN)
  • A (list[list], required): The state dynamics matrix A (NxN).
  • G (list[list], required): The process noise input matrix G (NxNw).
  • C (list[list], required): The output matrix C (Ny x N).
  • QN (list[list], required): Process noise covariance matrix (Nw x Nw).
  • RN (list[list], required): Sensor noise covariance matrix (Ny x Ny).
  • NN (list[list], optional, default: null): Optional cross-covariance matrix (Nw x Ny).

Returns (list[list]): The Kalman estimator gain matrix L.

Example 1: Simple LQE design

Inputs:

A G C QN RN
-1 0 1 0 1 1 0.1 0 1
0 -2 0 1 0 0.1

Excel formula:

=LQE({-1,0;0,-2}, {1,0;0,1}, {1,1}, {0.1,0;0,0.1}, {1})

Expected output:

Result
0.0484323
0.0244557
Example 2: Single-state continuous estimator

Inputs:

A G C QN RN
-0.8 1 1 0.2 0.7

Excel formula:

=LQE({-0.8}, {1}, {1}, {0.2}, {0.7})

Expected output:

0.16214

Example 3: Coupled-state continuous estimator

Inputs:

A G C QN RN
-1.2 0.4 1 0 1 -0.5 0.04 0 0.25
-0.2 -0.9 0 1 0 0.04

Excel formula:

=LQE({-1.2,0.4;-0.2,-0.9}, {1,0;0,1}, {1,-0.5}, {0.04,0;0,0.04}, {0.25})

Expected output:

Result
0.0632024
-0.0321583
Example 4: Partially observed continuous estimator

Inputs:

A G C QN RN
-0.6 0.2 1 0 1 0 0.08 0 0.4
0 -1.1 0 1 0 0.03

Excel formula:

=LQE({-0.6,0.2;0,-1.1}, {1,0;0,1}, {1,0}, {0.08,0;0,0.03}, {0.4})

Expected output:

Result
0.149316
0.0036862

Python Code

Show Code
import control as ct
import numpy as np

def lqe(A, G, C, QN, RN, NN=None):
    """
    Linear quadratic estimator (Kalman filter) for continuous-time systems.

    See: https://python-control.readthedocs.io/en/latest/generated/control.lqe.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        A (list[list]): The state dynamics matrix A (NxN).
        G (list[list]): The process noise input matrix G (NxNw).
        C (list[list]): The output matrix C (Ny x N).
        QN (list[list]): Process noise covariance matrix (Nw x Nw).
        RN (list[list]): Sensor noise covariance matrix (Ny x Ny).
        NN (list[list], optional): Optional cross-covariance matrix (Nw x Ny). Default is None.

    Returns:
        list[list]: The Kalman estimator gain matrix L.
    """
    try:
        def to_np(x):
            if x is None:
                return None
            if not isinstance(x, list):
                return np.array([[float(x)]])
            if len(x) > 0 and not isinstance(x[0], list):
                x = [x]
            return np.array([[float(v) if v is not None and str(v) != "" else 0.0 for v in row] for row in x])

        a_np = to_np(A)
        g_np = to_np(G)
        c_np = to_np(C)
        qn_np = to_np(QN)
        rn_np = to_np(RN)
        nn_np = to_np(NN)

        # The control.lqe() implementation currently doesn't support nonzero
        # cross-covariance (NN) despite accepting it as an argument.
        # Accept explicit zero NN for compatibility, otherwise error.
        if nn_np is not None:
            if not np.allclose(nn_np, 0):
                return "Error: cross-covariance (NN) is not implemented"
            nn_np = None

        if nn_np is None:
            L, P, E = ct.lqe(a_np, g_np, c_np, qn_np, rn_np)
        else:
            L, P, E = ct.lqe(a_np, g_np, c_np, qn_np, rn_np, nn_np)

        return L.tolist()
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

The state dynamics matrix A (NxN).
The process noise input matrix G (NxNw).
The output matrix C (Ny x N).
Process noise covariance matrix (Nw x Nw).
Sensor noise covariance matrix (Ny x Ny).
Optional cross-covariance matrix (Nw x Ny).