Generated reference › Kalman Filter — Control Systems/State Estimation
kind: generated#block#control-systems-state-estimation

Kalman Filter — Control Systems/State Estimation

Control_Systems/State_Estimation/Kalman_Filter · 2 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

Kalman Filter

Control Systems / State Estimation

Estimates the states of a discrete-time linear plant from a noisy measurement, running the optimal recursive estimator for

x[k+1] = A·x[k] + B·u[k] + G·w[k], y[k] = C·x[k] + D·u[k] + v[k], with cov(w) = Q and cov(v) = R.

Each step forms the innovation covariance S = C·P·C' + R, the gain M = P·C'·S−1, corrects the estimate with the measurement, and propagates both the estimate and its covariance P.

The gain is computed once, not per step. For a time-invariant plant the Riccati recursion has a fixed point, and this block iterates to it when the configuration is loaded and then uses that steady-state gain from the very first sample. That is what Simulink's block does, and it is observable: its first-sample gain corresponds to the steady-state covariance rather than to P[0], and the estimate error decays at exactly A·(1−M·C). A filter that instead ran the covariance transient converges to the same place but disagrees for the first few hundred samples – which is precisely what the Simulink parity run measured before this was corrected.

Ports

  • u – the known plant input, a column of m entries (m = B's column count).
  • y – the measurement, a column of p entries (p = C's row count).
  • xhat () – the state estimate, a column of n entries (n = A's order).

Parameters

  • A, B, C, D – the plant, discrete-time. A is [n,n] and sets the state count; B is [n,m], C is [p,n], D is [p,m].
  • G – how process noise enters the state, [n,q]. Defaults to the identity, i.e. noise on every state.
  • Q – process-noise covariance, [q,q]. A scalar is taken as that value times the identity.
  • R – measurement-noise covariance, [p,p]. A scalar expands the same way. Larger R means the measurement is trusted less and the filter leans on the model.
  • Initial State Estimatex̂[0], [n,1].
  • Initial CovarianceP[0], [n,n] or a scalar. It seeds the iteration that finds the steady-state gain. Because that iteration runs to its fixed point, P[0] does not change the running filter – it is kept because Simulink has it and because a badly scaled value can slow the search, not because it shifts the answer.
  • Estimator TypeCurrent publishes x̂[k|k], corrected with the measurement of the SAME step; Delayed publishes x̂[k|k−1], the prediction made before it. Both run the identical recursion – the difference is which estimate reaches the port, and a wrong choice tracks convincingly while sitting one sample out.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The plant matrices are baked in at export time; the gain is baked in beside them, so the generated core carries no covariance and no matrix solve at all – only innov = y − C·x̂ − D·u, x̂ = x̂ + M·innov and the state propagation.

The three HDL targets are simulation-only, emitted in real arithmetic and quantized only at the port boundary, as Recursive IIR Identification is. With the gain precomputed the remaining arithmetic would in fact sit comfortably in Q16.16; the real form is kept because the gain itself is derived from a covariance spanning many decades, and a core whose constants were rounded to Q16.16 at export would no longer be the filter the tool designed.

Simulink bridge

Import and export, mapped to cstblocks/State Estimation/Kalman Filter – the library is cstblocks, not the "Control System Toolbox" display name, which add_block rejects. A/B/C/D, G, Q, R map by name; "Initial State Estimate" to X0, "Initial Covariance" to P0, "Estimator Type" to UseCurrentEstimator. The rate crosses as Ts, not SampleTime – this block names it differently from the rest of the library, and emitting the standard name would be a hard set_param error.

Notes

  • Discrete only, and stateful: the estimate and the covariance P both persist.
  • Carries no state space. The A/B/C/D it holds describe the PLANT it estimates, not this block – whose own behaviour depends on P and therefore is not time-invariant. Model reduction reports it as unmergeable rather than merging the plant's matrices by mistake.

Code facts#

FactValue
registered typeControl_Systems/State_Estimation/Kalman_Filter
familyControl_Systems/State_Estimation
solver environment classICoreBlock_0_Control_Systems_1_State_Estimation_2_Kalman_Filter
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/State_Estimation/Kalman_Filter/ICoreBlock_0_Control_Systems_1_State_Estimation_2_Kalman_Filter.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/State_Estimation/Kalman_Filter/ICoreBlock_0_Control_Systems_1_State_Estimation_2_Kalman_Filter.h
default size on canvas130 × 90 px
ports at insert2 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleu
2inICoreDoubley
3outICoreDoublexhat

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
A0.95A
B1B
C1C
D0D
G1G
Q0.05Q
R1R
Initial State Estimate0X0
Initial Covariance10P0
Estimator TypeCurrent%~%Delayed~~CurrentUseCurrentEstimator

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::Both
Simulink pathcstblocks/State Estimation/Kalman Filter
port-count rulePortsParam::None
SampleTime parameteryes
rate parameter nameTs
always setModelSource = Individual A, B, C, D matrices, TimeDomain = Discrete-Time, AddInputPort = on, InitialEstimateSource = Dialog, UseK = off, UseGH = on, H = 0, N = 0, AddEnablePort = off, ExternalReset = None, OutputEstimatedY = off, OutputP = off
ICore configSimulink parameterValue translation
AApasses through
BBpasses through
CCpasses through
DDpasses through
GGpasses through
QQpasses through
RRpasses through
Initial State EstimateX0passes through
Initial CovarianceP0passes through
Estimator TypeUseCurrentEstimatorCurrenton, Delayedoff

Caveat (shown to the user): the plant, the noise covariances and the initial estimate all cross; the rate crosses as Ts rather than SampleTime, which is this block's own spelling

Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

Kalman Filter — discrete-time current estimator over a time-invariant plant S = C P C' + R M = P C' S^-1 xhat = xp + M (y - C xp - D u) <- published (current estimator) Pf = P - M C P xp = A xhat + B u P = A Pf A' + G Q G'

See the header for the current-vs-delayed distinction, the state/state-space reasoning, and why the three HDL targets are simulation-only.

Sample results#

Kalman Filter — Step: 0 -> 1 at t = 1 sKalman Filter — Step: 0 -> 1 at t = 1 s024012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)0 … 0.965
rampRamp: slope 1 from t = 00 … 25.53
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-3.617 … 3.789
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-2.575 … 4.984

Plotted: step — Step: 0 -> 1 at t = 1 s

Category dynamic · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__State_Estimation__Kalman_Filter.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).