Particle Filter — Control Systems/State Estimation
Control_Systems/State_Estimation/Particle_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.
Particle Filter
Control Systems / State Estimation
Estimates the states of a nonlinear discrete-time plant from a noisy measurement by carrying a cloud of weighted particles, each a guess of the state. The plant is
x[k+1] = f(x[k], u[k]) + w[k], y[k] = h(x[k], u[k]) + v[k], with w ~ N(0, Q) and v ~ N(0, R),
and f and h are expressions you type over the state and input variables you name. Each sample the filter weighs every particle by how well h(particle) explains the measurement, resamples the cloud when too few particles carry the weight, outputs the estimate, and moves every particle through f with fresh process noise. Unlike a Kalman filter it assumes nothing Gaussian about the estimate, so it follows multimodal and strongly nonlinear problems.
It is MATLAB's own particle filter – the code Simulink's Particle Filter block runs – with the state transition and the measurement likelihood written as expressions instead of MATLAB functions. The block outputs the estimate after the correction, as Simulink's does with Use the current measurements to improve state estimates on (its default).
The factory setting tracks a forced Van der Pol oscillator, stepped by forward Euler at 0.05 s, from its noisy position x1 with 1000 particles.
Ports
- u – the known plant input, a column [p,1] in the order of Input Variables. With no input variables it must be a scalar, and it is ignored.
- y – the measurement, a column [m,1] (m = the entries of Measurement h).
- xhat – the state estimate, a column [n,1] in the order of State Variables.
Parameters
- State Variables – the n state names, separated by spaces: 1 to 8 of them.
- Input Variables – the p input names, 0 to 8 of them; leave it empty for a plant with no input. The state and input names together are at most 12.
- State Transition f – the next state f(x, u) before noise: a column of n expressions.
- Process Noise Q – the covariance of w, n×n symmetric positive definite, or a scalar meaning that times the identity. Zero means no process noise.
- Measurement h – the measurement h(x, u): a column of 1 to 8 expressions.
- Measurement Noise R – the covariance of v, m×m symmetric positive definite, or a positive scalar. The likelihood of a particle is the Gaussian density of y − h(particle) with this covariance.
- Number of Particles – 1 to 5000.
- Initial Distribution – Gaussian (from Initial Mean and Initial Covariance) or Uniform (inside Initial State Bounds). The cloud is drawn on the first sample.
- Initial Mean – a column of n values.
- Initial Covariance – n×n symmetric positive definite, or a positive scalar.
- Initial State Bounds – an n×2 matrix, one [lower upper] row per state.
- Resampling Method – Multinomial, Systematic or Stratified.
- Resampling Trigger – Ratio resamples when the effective number of particles, 1/Σw², falls below Minimum Effective Particle Ratio times the count; Interval resamples every Sampling Interval corrections.
- Minimum Effective Particle Ratio – 0 to 1.
- Sampling Interval – a whole number of corrections, 1 or more, or Inf for never.
- State Estimation Method – Mean (the weighted mean of the cloud) or Max Weight (the first particle of largest weight).
- Seed – the random generator's seed, a whole number: the same seed gives the same run, in simulation and in every export.
- Sampling Time (s) – the filter's sample time; zero or less inherits the solver's rate.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. Each carries the cloud, the weights and its own copy of the random generator, and runs the same step in the same order, so an export reproduces the simulation's particles draw for draw.
⚠ The three HDL targets run in simulation-only real arithmetic, quantizing only at the port boundaries.
Simulink bridge
None (Support::None). Simulink's Particle Filter names its
state transition and measurement likelihood as MATLAB functions on the path, and
this block's are typed expressions, so nothing a model file carries maps onto it;
the bridge reports this block rather than dropping it silently.
Notes
- Discrete only, and stateful: the cloud, the weights and the generator persist from sample to sample.
- ⚠ The random numbers are not MATLAB's. Simulink's block draws from MATLAB's global stream; this one uses the generator of Simulink's Random Number block, so the same seed does not give the same particles as MATLAB. The filter's arithmetic is MATLAB's to the last digits: fed the same draws, it agrees with MATLAB's own code to 4e-15.
- ⚠ Multinomial positions are drawn as normalized sums of exponentials – the same distribution as MATLAB's sorted uniforms, with no sort to carry into ten languages.
- The process noise is additive Gaussian and the likelihood Gaussian. Residual resampling, circular state variables, several measurement likelihoods, enable ports, and particles or weights on an output port are not offered.
- Carries no state space: the filter is nonlinear, and f and h describe the PLANT, not this block.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/State_Estimation/Particle_Filter |
| family | Control_Systems/State_Estimation |
| solver environment class | ICoreBlock_0_Control_Systems_1_State_Estimation_2_Particle_Filter |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/State_Estimation/Particle_Filter/ICoreBlock_0_Control_Systems_1_State_Estimation_2_Particle_Filter.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/State_Estimation/Particle_Filter/ICoreBlock_0_Control_Systems_1_State_Estimation_2_Particle_Filter.h |
| default size on canvas | 150 × 90 px |
| ports at insert | 2 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | u |
| 2 | in | ICoreDouble | y |
| 3 | out | ICoreDouble | xhat |
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 variable | Default | Simulink parameter |
|---|---|---|
State Variables | x1 x2 | — |
Input Variables | u | — |
State Transition f | [x1 + 0.05*x2; x2 + 0.05*((1 - x1^2)*x2 - x1 + u)] | — |
Process Noise Q | [0.000625 0; 0 0.000625] | — |
Measurement h | x1 | — |
Measurement Noise R | 0.016 | — |
Number of Particles | 1000 | — |
Initial Distribution | Gaussian%~%Uniform~~Gaussian | — |
Initial Mean | [0; 0] | — |
Initial Covariance | 1 | — |
Initial State Bounds | [-3 3; -3 3] | — |
Resampling Method | Multinomial%~%Systematic%~%Stratified~~Multinomial | — |
Resampling Trigger | Ratio%~%Interval~~Ratio | — |
Minimum Effective Particle Ratio | 0.5 | — |
Sampling Interval | 1 | — |
State Estimation Method | Mean%~%Max Weight~~Mean | — |
Seed | 0 | — |
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.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): Simulink's Particle Filter block names its state transition and measurement likelihood as MATLAB functions on the path, and ICore's are typed expressions, so nothing a model could carry maps onto it. The block is reported rather than dropped when a model crosses
Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0no sample under docs/generated/samples/ — nothing to cross-check (P8.1)
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).
Particle Filter -- MATLAB's particle filter over typed f(x, u) and h(x, u) correct w_i *= N(y; h(x_i, u), R) + 1e-99; w /= sum(w) resample when neff/N < ratio (or every
intervalcorrections): multinomial, systematic or stratified positions walked along cumsum(w); w = 1/N output the weighted mean, or the particle of largest weight predict x_i = f(x_i, u) + chol(Q)' z_iThe filter is ICoreParticleFilterSupport's, written once for the live run and once as statements for the ten exports. This file holds the configuration, the ports, the state and the calls into the support's per-target wrappers.
⚠ MEASURED AGAINST R2026a's own code -- matlabshared.tracking.internal.ParticleFilter's pfBlockCorrectAndResample and pfBlockPredict, the functions the Simulink block's MATLAB System blocks call -- with this block's draws injected (a shadowing rand for the resampler, the transition function adding the same normals): 4 configurations x 150 samples covering both initial distributions, all three resamplers (27 to 150 resamplings each), both triggers and both estimators, at worst 4.0e-15 relative. The emitted Python is bit-identical to the live run on the same four.
Sample results#
No sample run is committed for this block. Samples come from the headless harness (DOCS_PLAN.md P8.1) into docs/generated/samples/; until one exists this block's behaviour is witnessed by the parity and export-verification suites, not by a plot here.