control//controllability and observability//observability//observability matrix

The observability matrix is the stack of the sensor matrix and its images under the dynamics, whose rank decides whether the initial state of a linear system can be recovered from its first \(n\) measurements, and it is how observability is checked numerically when a set of sensors is chosen. Take a system without inputs, \(x_{k+1}=Ax_k\) and \(y_k=Cx_k\) (known inputs do not change the answer), and stack the first \(n\) readings:


The observability matrix is the stack of the sensor matrix and its images under the dynamics, whose rank decides whether the initial state of a linear system can be recovered from its first nnn measurements, and it is how observability is checked numerically when a set of sensors is chosen. Take a system without inputs, xk+1=Axkx_{k+1}=Ax_kxk+1​=Axk​ and yk=Cxky_k=Cx_kyk​=Cxk​ (known inputs do not change the answer), and stack the first nnn readings:

[y0y1⋮yn−1]=[CCA⋮CAn−1]⏟O x0.\begin{bmatrix}y_0\\ y_1\\ \vdots\\ y_{n-1}\end{bmatrix}=\underbrace{\begin{bmatrix}C\\ CA\\ \vdots\\ CA^{n-1}\end{bmatrix}}_{\mathcal O}\,x_0 .​y0​y1​⋮yn−1​​​=O​CCA⋮CAn−1​​​​x0​.

Each block CAkCA^kCAk is what the sensor sees of the initial state kkk steps later. With rank⁡O=n\operatorname{rank}\mathcal O=nrankO=n, only one x0x_0x0​ fits the readings and the system is observable. With a smaller rank there is a direction with Ox=0\mathcal Ox=0Ox=0, a state that produces exactly the same readings as zero: the unobservable directions are the null space of O\mathcal OO.

A cart with position and velocity and a position sensor has A=[1Δt01]A=\begin{bmatrix}1&\Delta t\0&1\end{bmatrix}A=[10​Δt1​] and C=[1   0]C=[1;,0]C=[10], so O=[101Δt]\mathcal O=\begin{bmatrix}1&0\1&\Delta t\end{bmatrix}O=[11​0Δt​], rank 2. Solving Ox0=y\mathcal Ox_0=yOx0​=y gives p0=y0p_0=y_0p0​=y0​ and v0=(y1−y0)/Δtv_0=(y_1-y_0)/\Delta tv0​=(y1​−y0​)/Δt: inverting the observability matrix is literally the finite difference. The Δt\Delta tΔt inside it is the warning. Over a short window O\mathcal OO is nearly singular, the difference turns centimetres of position noise into metres per second of velocity noise, and that is why a filter averages over many readings instead of inverting two.

A gyroscope's bias is observable through the same test. With the angle θ\thetaθ, the bias bbb and the model θk+1=θk+Δt (ωk−bk)\theta_{k+1}=\theta_k+\Delta t,(\omega_k-b_k)θk+1​=θk​+Δt(ωk​−bk​), a constant bias and an accelerometer that measures θ\thetaθ, the matrix has rank 2 again: the bias can be estimated. Remove the accelerometer and no choice of CCC remains to help.

How poorly the worst direction is seen is read from the smallest singular value of O\mathcal OO (SVD); a rank computed in floating point is itself a threshold on those values.

In Python the check is numpy.linalg.matrix_rank(control.obsv(A, C)), with the python-control package.

Its mirror is the controllability matrix: transpose AAA and put CTC^{\mathsf T}CT in the place of BBB, and one test becomes the other.