Observer

Observer estimates every state of a plant, including the ones no sensor measures — a velocity from position alone, a load torque from motor current, a temperature inside a body from its surface.
3.30–3.34

Observer estimates every state of a plant, including the ones no sensor measures — a velocity from position alone, a load torque from motor current, a temperature inside a body from its surface. It runs a model of the plant, compares the model’s predicted measurement against the real one, and uses the difference to pull the model back toward the truth every cycle.

It is a plant model plus one correction term. Without that term the model drifts away from reality; with it, the estimate converges and stays converged.

flowchart LR
    i1(["inputVector — the plant's input"]) --> B["Observer"]
    i2(["measurementVector — what the sensors read"]) --> B
    B --> o1(["stateVector — the estimated states"])
    B --> o2(["stateDotVector — rate of change of the estimate"])
    B --> o3(["outputVector — the predicted measurement"])

The model is $\dot{\hat{x}} = A\hat{x} + Bu + L(y_m - \hat{y})$ and $\hat{y} = C\hat{x} + Du$. Tuning is entirely observerGain ($L$): it sets how fast the estimate is pulled toward the measurement. Place the observer 3 to 10 times faster than the plant. Faster converges sooner and passes more sensor noise into every estimate, and past a point it makes the block diverge — see Limits and errors. observerGain at zero leaves an open-loop simulation that ignores the measurement entirely.

Every matrix is written as one flat list, filled column by column. For a 4-state 2-measurement system the first four values of observerGain are the gains from the first measurement to all four states.

This block has no enable, no disable and no reset you can reach. It always runs, and its estimate cannot be re-initialised from the parameter tree — see Limits and errors.

Signals

Inputs

Path Unit Range Description
inputVector plant input units unbounded What is being commanded into the real plant, one element per input. The observer needs this to predict how the plant will respond.
measurementVector sensor units unbounded What the sensors actually read, one element per measurement. This is the truth the estimate is corrected against. Note the block’s predicted measurement is outputVector — do not confuse the two.

Outputs

Path Unit Description
stateVector model state units The estimated state, one element per state — the reason to use this block. It starts at zero after a controller start and converges from there. It is not cleared by a stop, so after a restart it briefly holds an estimate unrelated to the machine.
stateDotVector model state units per second Rate of change of the estimate on this cycle.
outputVector sensor units The measurement the model predicts, for comparison against measurementVector. Subtract the two to see how well the observer is tracking: that difference should be small and settle toward zero.

Parameters

Path Unit Default Range Effect
observerGain model state units per sensor unit per second all zeros any The one thing to tune. How hard the measurement pulls the estimate. Higher converges faster and passes more noise; too high makes the estimate grow without bound. States × measurements, column-major. Zero leaves an open-loop simulation.
matrixA 1/s all zeros any Plant dynamics, states × states, column-major. Continuous-time.
matrixB state units per input unit per second all zeros any Input matrix, states × inputs, column-major.
matrixC sensor unit per state unit all zeros any Which states the sensors see, and how. Measurements × states, column-major. A state no row of this matrix reaches cannot be estimated at any gain.
matrixD sensor unit per input unit all zeros any Direct feed-through from input to predicted measurement, measurements × inputs, column-major. Usually zeros.
stateVectorInit model state units all zeros any Intended as the state a reset restores. It has no effect — the reset is not reachable and the estimate always starts at zero.

All six parameters are persistent and survive a controller restart. The inputs and outputs do not. No parameters exist below this block.

Setup

  1. Write down your model’s dimensions: states, inputs, measurements. Read the lengths of stateVector, inputVector and measurementVector from the parameter tree and confirm they match. They are fixed when the machine is built.

  2. Check that every state you want estimated is reachable through matrixC. A state that no measurement depends on, directly or through the dynamics, cannot be estimated at any gain.

  3. Confirm your matrices are continuous-time. A discretised model will be wrong by a factor of the task period.

  4. Write matrixA through matrixD as flat lists, column by column. For a 2×2 matrix the order is row 1 column 1, row 2 column 1, row 1 column 2, row 2 column 2.

  5. Leave observerGain at zeros. Link inputVector from whatever commands the real plant, and measurementVector from the sensors.

  6. Compare outputVector against measurementVector on one trace. With zero gain the model runs open loop, so the two will drift apart — but they should start out the same shape. If they are not, the model is wrong; fix that before adding any gain.

  7. Raise observerGain from zero until outputVector tracks measurementVector closely.

    Step 7 is where this block becomes unstable if you push it. Too high a gain does not merely pass noise — it makes the estimate grow without bound, and only a controller restart clears it. Raise it in steps and watch stateVector between each.

  8. Confirm stateVector settles and stays settled with the machine at rest.

Tuning

  1. Get the model right first, with observerGain at zero, per Setup step 6. No gain can rescue a wrong model — it will give you a confidently wrong estimate with a small-looking error.
  2. Work out your plant’s fastest pole, in rad/s. Aim to place the observer 3 to 10 times faster than that. That factor, not a number, is the target.
  3. Raise observerGain from zero in steps of roughly double. After each step, watch stateVector for a few seconds with the machine at rest.
  4. Stop as soon as noise appears on stateVector. Every measurement’s noise reaches every estimated state through the gain, and the states no sensor measures are usually the noisiest.
  5. Judge convergence by subtracting outputVector from measurementVector. That difference is the observer’s error signal: it should be small in steady state and settle quickly after a disturbance.
  6. Test convergence deliberately: start the controller with the machine away from zero, and time how long stateVector takes to reach the truth. That time is your observer’s response.
  7. Check the gain against your task period. A gain fast enough to converge in a few task periods will make the block diverge — the practical ceiling is an observer response no faster than about a fifth of the task period.
  8. If you need both fast convergence and quiet estimates, and your model is uncertain, use a Kalman filter instead — it trades the two off explicitly.

Estimation error after a wrong initial state at three observer gains: gain 2settles in about 0.5 s, gain 10 in about 0.1 s, and gain 50 in about0.02 s.

Read the convergence time off any curve as the point it crosses 0.37.

Symptom Cause Action
stateVector grows without bound observerGain too high for the task period, or a wrong model Lower the gain, restart the controller, and re-check step 6 of Setup
Everything reads zero Expected with unconfigured matrices — all default to zero Write matrixA through matrixD
outputVector never comes near measurementVector observerGain is zero, so the model runs open loop Raise observerGain
outputVector tracks but one state never settles That state is not reachable through matrixC, so no gain can estimate it Add a measurement, or accept that the state is not observable
The estimate is noisy Gain too high — every measurement’s noise reaches every state Lower observerGain and accept slower convergence
The estimate converges too slowly Gain too low Raise observerGain, watching for noise and divergence
The estimate looks confident and is wrong The model is wrong: a bad model produces a small error and a false estimate Set observerGain to zero and re-verify the model open loop
The estimate is smooth but lags the machine Gain too low, or the model’s dynamics are too slow Raise the gain; if that adds noise, fix the model instead
The response has the right timescale but the wrong shape A matrix was written row by row instead of column by column Rewrite it column-major
One measurement seems to affect the wrong states observerGain is transposed Rewrite it column-major: states × measurements
The response is far faster or slower than your offline design Discretised matrices were supplied; this block wants continuous-time ones Convert back to continuous time
A wrong estimate immediately after a controller restart Expected: the estimate is not cleared by a stop and starts from wherever it was Wait for it to converge, or gate the consumer for a few observer time constants
stateVectorInit seems to be ignored Expected: it has no effect, because the reset that would apply it is not reachable Ignore this parameter
You cannot re-initialise the estimate Expected: there is no reset input Restart the controller
A value went non-numeric and stayed there A non-numeric value reached a matrix or an input Restart the controller; there is no way to clear it in service
You need a different number of states Not possible — the dimensions are fixed when the machine is built It needs a configuration change

A starting point for estimating velocity from a position measurement on a 1 ms task. Two states — position and velocity — one input, one measurement:

matrixA      = 0, 0, 1, 0
matrixB      = 0, 1
matrixC      = 1, 0
matrixD      = 0
observerGain = 200, 10000

matrixA is column-major. Start with observerGain at zeros and work Setup steps 6 and 7. This is a starting point, not a final tuning.

Limits and errors

Limit Set by What happens Reported
observerGain against the task period Nothing Not checked, and this is the bound you will hit while tuning. Too high a gain makes the estimate grow without bound. Only a controller restart clears it Not reported
Task period against the model’s poles Nothing Not checked. The same limit applies to matrixA alone: the task period must stay below 2 divided by the largest pole magnitude in rad/s Not reported
Observability Nothing Not checked. A state no measurement reaches cannot be estimated at any gain, and the symptom is a state that simply drifts Not reported
Model accuracy Nothing Not checked, and cannot be. A wrong model gives a confident, wrong estimate with a small error signal Not reported
Matrix element order Fixed Column-major, always. A row-major list silently produces a transposed matrix Not reported
Model time domain Fixed Continuous-time only Not reported
Matrix dimensions Machine configuration Fixed when the machine is built. Read the array lengths to discover them Not reported
Estimate state Nothing There is no reset input, so the estimate cannot be re-initialised in service. stateVectorInit has no effect. A restart is the only way Not reported
stateVector, outputVector Nothing Unbounded Not reported

The block raises no errors or warnings and logs nothing. Every failure above shows as a value on a trace, not as a message.


Verified against motorcortex-control3 3.30.0 (bc348fd).