Rolling Statistics — Machine Learning/Feature Engineering
Machine_Learning/Feature_Engineering/Rolling_Statistics · 1 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.
Rolling Statistics
Machine Learning / Feature Engineering
Reduces the last N samples of every channel to one number, elementwise: y[c] = stat( u[k][c], u[k−1][c], …, u[k−N+1][c] ), with the statistic chosen by configuration – mean, standard deviation, minimum, maximum or RMS.
This is the feature front end a deployed model needs: a classifier is almost never trained on a raw sample, but on a handful of windowed statistics of it. Feed several of these blocks from one signal and concatenate them to build the feature vector a Dense Layer or a Decision Tree expects.
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
- u – the input sample, any size [m,1]. Each of the m channels carries its own independent window; nothing is mixed across channels.
- y – the statistic, [m,1]: the same size as the input, one reduced value per channel. The reduction is over TIME, never over the vector – for a statistic across the entries of one sample use Sum Of Elements or MinMax instead.
Parameters
- Statistic – which reduction the window gets. Each is a different
code path rather than a retuning of one, so each is verified as its own mode:
- Mean – the arithmetic average, emitted as a sum times the constant 1/N.
- Standard Deviation – the population form, dividing the
squared deviations by N and not by N−1. That is what
numpy.stdgives by default and what Layer Normalization uses in this same library; a model fitted withpandas.rolling().std()(which defaults to N−1) expects the other one, and at small N the two differ materially – at N = 5 by 12%. - Minimum / Maximum – the extreme over the window, a chain of comparisons.
- RMS – √(mean of the squares). Distinct from the standard deviation in that the mean is not removed first, so it carries the signal's DC level.
- Window Length – N, the number of samples the statistic is taken over, one or more. The window is a whole number of samples, so at a sampling time of Ts it spans N·Ts seconds. N = 1 makes every statistic the sample itself (and the standard deviation zero), which is legal and useless.
- Initial Window Value – what every slot of the window holds
before the first sample arrives. The window is full from the very first
step: this block does not produce a shorter average over the first N−1
samples the way
pandas.rollingdoes, because a partial window costs a sample counter and a divide-by-count branch in all ten exported languages for a startup transient a feature pipeline discards anyway. Set it to the signal's resting level if the first N steps matter to you. - 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 is unrolled at export time – N and m are both known then – so no backend contains a loop bound, a modulo or a ring-buffer index, and each carries the N−1 stored samples in its own persistent form seeded with Initial Window Value.
The three HDL targets split by statistic, which is the one thing to know before exporting to hardware:
- Mean, Minimum and Maximum are genuine synthesizable Q16.16. The mean's 1/N is folded into a constant at export time and multiplied, so no divider appears in the datapath; the extremes are a chain of comparisons.
- Standard Deviation and RMS are simulation-only
realarithmetic: both need a square root, which has no place in a Q16.16 datapath. They simulate correctly and quantize at the port boundary, and are not offered as synthesizable.
The reduction multiplies by the constant 1/N in every target, including the in-app solver, so the exported core and the simulation agree to the last bit rather than to within a division's rounding.
Simulink bridge
None, and here for a structural reason rather than a missing block. All
six counterparts do exist in the installed DSP System Toolbox –
dspstat3/Moving Average, Moving RMS, Moving
Standard Deviation, Moving Maximum, Moving
Minimum – but a catalog entry carries exactly one library path,
while this block's statistics are five different Simulink blocks.
Registering any one of them would export the other four as that one, silently,
which is worse than reporting no equivalent. The bridge therefore reports the
block, and it has no parity testbench, which is the documented consequence
of that choice. Code export verification still covers it across all ten
languages.
Notes
- Stateful: the same input gives a different output depending on the N−1 samples before it. The window is re-seeded at the start of every run.
- No state space, deliberately. The mean alone is linear, but the statistic is a configuration choice and the other four are not, so the block declines one in every mode rather than being mergeable in one of five.
- The state is read before it is written. The output is computed from the window as it stood, and only then does the window shift. The exported code shifts from the far end downwards for that reason – except on the three HDL targets, where the state is a registered signal and pre-clock reads give it for free.
- Not Tapped Delay, and not MinMax Running Resettable. The first emits the window itself and reduces nothing; the second runs since its last reset rather than over a window, so its answer never comes back down.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Feature_Engineering/Rolling_Statistics |
| family | Machine_Learning/Feature_Engineering |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Rolling_Statistics |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Feature_Engineering/Rolling_Statistics/ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Rolling_Statistics.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Feature_Engineering/Rolling_Statistics/ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Rolling_Statistics.h |
| default size on canvas | 124 × 84 px |
| ports at insert | 1 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 | out | ICoreDouble | y |
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 |
|---|---|---|
Statistic | Mean%~%Standard Deviation%~%Minimum%~%Maximum%~%RMS~~Mean | — |
Window Length | 5 | — |
Initial Window Value | 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): no single Simulink equivalent: its windowed statistics are five SEPARATE blocks (dspstat3/Moving Average, Moving RMS, Moving Standard Deviation, Moving Maximum, Moving Minimum), while a bridge entry carries exactly one library path -- so any mapping would export four of the five statistics as the wrong block, silently
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).
Rolling Statistics — one statistic over the last N samples, elementwise per channel y[c] = stat( u[k][c], u[k-1][c], ... , u[k-N+1][c] )
Read the header before this file: it records the pre-filled window (and why a partial one was rejected), the config-seed / running-window split every generator depends on, the read-before-write shift, and the per-statistic HDL split.
⚠ EVERY BACKEND MULTIPLIES BY THE RECIPROCAL 1/N, including the C++ reference in reduce(). A backend that divided instead would differ in the last bit from one that multiplied, which is a difference export verification can see and nothing else would explain.
Sample results#
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 0.2 |
ramp | Ramp: slope 1 from t = 0 | 0 … 5.6 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.9604 … 0.96 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -0.7 … 1.3 |
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/Machine_Learning__Feature_Engineering__Rolling_Statistics.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).