Generated reference › Residual Whiteness Monitor — System Identification/Validation
kind: generated#block#system-identification-validation

Residual Whiteness Monitor — System Identification/Validation

System_Identification/Validation/Residual_Whiteness_Monitor · 1 input / 3 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.

Residual Whiteness Monitor

System Identification / Validation

The standard model-adequacy check, live on the canvas. Over the last N residuals it correlates the signal with a delayed copy of itself at each configured lag, and asks whether every one of those correlations is inside the confidence band a white signal would stay in:

|ρ(l)| ≤ z ÷ √N  for every configured lag l

White residuals mean the model took everything predictable out of the signal. A peak outside the band at lag l says there is structure left that a model of the right order would have captured – and the lag tells you roughly where to look.

Stateful and discrete by nature. The window advances one sample per step and has no derivative to integrate, so the block declares itself discrete-only and always steps at its own rate.

Ports

  • e – the residual, a scalar [1,1]. The lags index TIME, so one block follows one residual; use one block per channel.
  • white1 when every configured lag is inside the band, 0 when any one of them is outside. This is the verdict to gate on.
  • worst – the largest correlation magnitude over the configured lags, so a diagram can show how far from white rather than only whether. What it is measured in follows Magnitude below.
  • lag – the lag at which that largest magnitude occurred. It carries the configured lag value, not its position in the list: with Lags of [1; 5; 12], a peak in the third slot reports 12.

Parameters

  • Window LengthN, the number of residuals the correlation is taken over. It sets the band as well as the window: the band is z ÷ √N, so a longer window is a tighter test. Keep N several times the largest lag, or the longest lags rest on a handful of products.
  • Lags – the lags to test, as a vector such as [1; 2; 3]. Each is a whole number of samples from 1 to N−1. Lag 0 is rejected rather than accepted: it is the window's own energy, ρ(0) is 1 by construction, and including it would put the block permanently outside its own band.
  • Band Multiplierz, the standard-normal multiplier that sets the confidence level. 1.96 is the usual 95% band and the default; 2.576 is 99%. Raising it makes the monitor harder to trip.
  • Magnitude – what the worst port reports. The verdict and the lag are the same in both; only this one output changes:
    • Coefficient – the true |ρ|, in [0, 1] and directly comparable with the band. This is the readable choice, and it costs one divide per sample.
    • Covariance – the unnormalized products averaged over N, keeping the signal's units squared. No divide anywhere, which is what keeps the three HDL targets synthesizable.
  • Remove Mean – whether the window's mean is subtracted before correlating. This block defaults it to Off, unlike Autocorrelation Features, and the difference is deliberate: a residual is a model error and is zero-mean when the model is right, so subtracting the mean would hide a systematically biased model behind a "white" verdict – which is the most useful failure this block can report. Turn it On for the textbook mean-removed ACF, or when the input is a general signal rather than a residual.
  • Initial Window Value – what every slot holds before the first residual arrives. The window is full from the very first step rather than growing, for the reason Rolling Statistics gives: a partial window costs a sample counter and a divide-by-count branch in all ten exported languages, for a startup transient that a validation display discards anyway.
  • Epsilon – a floor on the divisor of the Coefficient magnitude, and on nothing else. The verdict never divides, so it needs no floor: see Code export below.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. Being discrete-only, a non-positive value falls back to the model's global sampling time rather than to the surrounding rate.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The window, every lag's product sum and the comparison chain are unrolled at export time – N and the lag list are both known then – so no backend carries a loop bound, a modulo or a ring-buffer index.

The verdict never forms the ratio. |ρ(l)| ≤ k is exactly |num(l)| ≤ k·den, and den is a sum of squares and so never negative, which means the inequality survives the multiplication with no sign case-split. The comparison is therefore multiply-accumulate and nothing else. It also removes the need for an Epsilon floor on the verdict: a constant window has den = 0, where the test degenerates to |num(l)| ≤ 0 with num(l) = 0, and passes cleanly instead of dividing by zero.

The AND over the lags and the search for the worst lag are one scan, because "every lag is inside the band" is the same statement as "the largest magnitude is inside the band". No backend carries a separate reduction.

The three HDL targets split by magnitude, not by verdict: Covariance is genuine synthesizable Q16.16 throughout – multiply-accumulate, a comparison chain, and the 1/N folded into a constant at export time. Coefficient divides by the window's own energy for that one output, a signal-dependent divisor that cannot be precomputed, so that mode is emitted as simulation-only real arithmetic. Even there the verdict and the lag stay exact: both are decided before the divide and neither depends on it.

Simulink bridge

None. The System Identification Toolbox checks residual whiteness with resid – a FUNCTION that runs after a simulation over a whole logged signal and draws a correlation plot – not with a block that reports a running verdict sample by sample. Every block in this family registers Support::None for the same reason. The bridge reports the block rather than dropping it silently, and it has no parity testbench, which is the documented consequence of Support::None. Code export verification still covers it across all ten languages.

Notes

  • Stateful: the answer depends on the N−1 residuals before the current one. The window is re-seeded at the start of every run.
  • No state space: the correlation is quadratic in the input, so no A/B/C/D describes it and model reduction correctly refuses the block.
  • The state is read before it is written. Every lag is computed from the window as it stood, and only then does the window shift – on the three HDL targets that comes free from the registered write, and the other seven shift from the far end downwards.
  • Ties go to the LOWEST lag. The scan replaces its running best only on a strictly greater magnitude, scanning the lags in written order – Argmax Decision's convention, spelled identically in all ten backends.
  • The lag output is discontinuous, as any argmax is: two lags whose magnitudes are within a fixed-point quantum can rank the other way round in the three HDL targets, moving the reported lag by a whole step. That is a property of the block, not of the codegen – the same caveat Argmax Decision and Time Delay Estimator carry.
  • It is a monitor, not a filter: it passes judgement on the residual and never alters it. Feed the residual on to whatever consumes it and take white as a gate.

Code facts#

FactValue
registered typeSystem_Identification/Validation/Residual_Whiteness_Monitor
familySystem_Identification/Validation
solver environment classICoreBlock_0_System_Identification_1_Validation_2_Residual_Whiteness_Monitor
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Validation/Residual_Whiteness_Monitor/ICoreBlock_0_System_Identification_1_Validation_2_Residual_Whiteness_Monitor.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/System_Identification/Validation/Residual_Whiteness_Monitor/ICoreBlock_0_System_Identification_1_Validation_2_Residual_Whiteness_Monitor.h
default size on canvas146 × 96 px
ports at insert1 in, 3 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublee
2outICoreDoublewhite
3outICoreDoubleworst
4outICoreDoublelag

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
Window Length12
Lags[1; 2; 3]
Band Multiplier1.96
MagnitudeCoefficient%~%Covariance~~Coefficient
Remove MeanOff%~%On~~Off
Initial Window Value0
Epsilon1e-12

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::None
Simulink path
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): no Simulink equivalent: it has no block that reports a running whiteness verdict. The residual-correlation test this follows is a System Identification Toolbox FUNCTION (resid) that runs after a simulation over a whole logged signal and draws a correlation plot, so there is nothing sample-by-sample to map onto

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).

Residual Whiteness Monitor — is the residual's autocorrelation inside the confidence band? num(l) = SUM_{k=0..N-1-l} (e[k] - m)(e[k+l] - m) e[0] the current sample den = num(0) = SUM_k (e[k] - m)^2 rho(l) = num(l) / den

white = 1 when |rho(l)| <= k for EVERY configured lag, k = z / sqrt(N) worst = max_l |rho(l)| (Coefficient) or max_l |num(l)| * (1/N) (Covariance) lag = the CONFIGURED lag value at that maximum

Read the header before this file: it records why the test is cross-multiplied (and so why this block is not a wiring pattern over Autocorrelation_Features), why the AND-reduction and the argmax are one scan, why the mode splits only the magnitude output, and why Remove Mean defaults to Off here where the ACF block defaults it On.

⚠ The window is UNROLLED at export time and the mean, when it is removed at all, is INLINED into every deviation rather than held in a temporary — Autocorrelation_Features' reason: the HDL targets have no spare scratch of the right type, and one emission path shared by ten backends is worth more than the repeated text. N is small by design so it stays so.

⚠ The three HDL targets carry exactly three scratch variables (acc, acc2, iacc), which is what fixes the ORDER of the emitted body: the lag scan first (acc working, acc2 the running maximum, iacc the winning lag), then den into acc, and only then the verdict — so den is still live for the Coefficient divide and nothing needs a fourth variable.

Sample results#

Residual Whiteness Monitor — Step: 0 -> 1 at t = 1 sResidual Whiteness Monitor — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0out ICoreDouble-Out-0out ICoreDouble-Out-1out ICoreDouble-Out-2

The same rig also ran:

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

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/System_Identification__Validation__Residual_Whiteness_Monitor.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).