Generated reference › Decimate — Control Systems/Resampling
kind: generated#block#control-systems-resampling

Decimate — Control Systems/Resampling

Control_Systems/Resampling/Decimate · 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.

Decimate

Control Systems / Resampling

Low-pass filters a stream and then keeps one sample in every D, holding each retained sample until the next one, so the output runs at the block's own rate rather than at a slower one. The filter runs on every sample; only its publication is decimated:

w[k] = c0·u[k] + c1·u[k−1] + … + cn·u[k−n], then y[k] = w[k] when k mod D = 0 and y[k] = y[k−1] on the D−1 samples in between. The sample index k counts from 0 at the start of the run, so the very first sample is always a retained one, and the filter's delay line starts empty.

The filter is what separates this block from Downsample: anything above half the retained rate folds back into the band when it is not removed first.

Ports

  • Input – the signal u to filter and decimate, of any size [m,n]. Every entry is filtered and retained on the same samples, each carrying its own delay line; the entries do not interact.
  • Output – the filtered-and-held signal y, the SAME size [m,n] as the input.

Parameters

  • FIR Coefficients – c0…cn, the anti-alias filter's impulse response as a non-empty vector, first entry multiplying the current sample and last the oldest. This block does not design the filter: pair it with FIR Window Design, or pass a response designed elsewhere. Defaults to [0.25 0.5 0.25], the three-tap half-band smoother that suits the default factor of 2.
  • Decimation Factor – D, the number of samples in one period, a whole number of 1 or more. At D = 1 every filtered sample is published and the block is a plain FIR filter. Defaults to 2.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. On this block it also sets what one "sample" means: D counts steps of this rate, so the retained stream comes out at one Dth of it.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The coefficients and the factor are baked into the core at export time rather than exposed as tunable parameters: the tap count also fixes how many state words the core carries, and a decimator whose period could be retuned on a built core would be a different block.

The three HDL targets are not simulation-only. The arithmetic is one multiply-accumulate over a short constant tap list, which the Q16.16 datapath carries without difficulty; what those columns do carry is the port's own quantization, which is a property of an HDL signal rather than of this block. Measured over a 1001-sample export-verification run at four taps and factor 3, the three of them come back at 0.0031–0.0036 % residual while the software targets are exact or within one double rounding (0 to 1.2×10 −14 %). The delay line is emitted unrolled, so a long filter on a large signal is a large entity: the state word count is n×m×p for a filter with n taps behind the current sample on an [m,p] signal, plus one word per signal entry for the retained sample.

What every target writes the same way is the retained sample: it publishes the freshly computed sum directly rather than reading back the register it is storing into, because an HDL register write is deferred to the clock edge and reading it in the same tick would return the previous retained sample.

Simulink bridge

Import and export, mapped to dspmlti4/FIR Decimation – the DSP System Toolbox block, not a core Simulink one. "FIR Coefficients" to h and "Decimation Factor" to D, both pass-through.

Five of that block's parameters are always emitted with a fixed value, because this block offers no choice behind them: FilterSource = Dialog parameters (the taps are a config here, never a port and never a filter object), filtStruct = Direct form, InputProcessing = Elements as channels (sample based), framing = Enforce single-rate processing and outputBufInitCond = 0. That middle pair is what makes the crossing exact: it is the one configuration in which the Simulink block's output port runs at its input's rate, which is the only kind of block an ICore wire can carry. The last one is pinned rather than mapped because it is unobservable in that configuration – with no phase offset the first sample is itself a retained one, and a run at 0 and a run at −9 are identical to the digit.

"Sampling Time (s)" does not cross. dspmlti4/FIR Decimation defines no SampleTime parameter at all – verified against the R2026a block dialog – and set_param on a parameter a block does not define is a hard error in MATLAB that aborts the whole generated script rather than degrading. The rate stays on the ICore side, and a block configured with an explicit positive rate reports that it did not cross.

Notes

  • Stateful: the filter's delay line, the retained sample and the phase counter. All three start from zero at the beginning of every run, so a re-run reproduces the stream exactly.
  • Discrete by nature – the phase advances once per sample, so the block always takes its period from its own "Sampling Time (s)" and is never pushed through a continuous solver's intermediate stages.
  • No state space, deliberately. The filter alone would be linear, but which sample is published depends on WHEN it arrives, so no single A/B/C/D describes the block and fabricating one would let the model-reduction commands absorb it into a neighbour as a filter that publishes everything.
  • It is not MATLAB's decimate function, which filters with a forward-and-backward pass that is not causal and then returns a SHORTER vector. A stream can carry neither, so the filter here is the ordinary causal one and the retained samples are held.

Code facts#

FactValue
registered typeControl_Systems/Resampling/Decimate
familyControl_Systems/Resampling
solver environment classICoreBlock_0_Control_Systems_1_Resampling_2_Decimate
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Resampling/Decimate/ICoreBlock_0_Control_Systems_1_Resampling_2_Decimate.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Resampling/Decimate/ICoreBlock_0_Control_Systems_1_Resampling_2_Decimate.h
default size on canvas100 × 70 px
ports at insert1 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDouble—
2outICoreDouble—

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
FIR Coefficients[0.25 0.5 0.25]h
Decimation Factor2D

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 pathdspmlti4/FIR Decimation
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setFilterSource = Dialog parameters, filtStruct = Direct form, InputProcessing = Elements as channels (sample based), framing = Enforce single-rate processing, outputBufInitCond = 0
ICore configSimulink parameterValue translation
FIR Coefficientshpasses through
Decimation FactorDpasses through

Caveat (shown to the user): dspmlti4/FIR Decimation has NO SampleTime parameter (verified against the R2026a block dialog), so "Sampling Time (s)" does not cross. The entry also pins the block to sample-based, single-rate processing - the one configuration whose output port runs at its input's rate, and therefore the only one an ICore wire can carry - and pins outputBufInitCond to 0, which that configuration makes unobservable: with no phase offset the first sample is itself a retained one, measured identical at 0 and at -9

Catalog contract: src/ICoreBlocks/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).

Decimate block — anti-alias FIR, then keep one sample in every D and hold it A single-rate decimator with a filter in front of it. The FIR runs at the FULL input rate, every sample; only its PUBLICATION is decimated, so the output carries the retained samples at the same rate the block runs at rather than at a slower one:

w[k] = c0*u[k] + c1*u[k-1] + ... + cn*u[k-n] the anti-alias filter, every sample y[k] = w[k] when k mod D = 0 (a retained sample) y[k] = y[k-1] otherwise (a hold sample)

k counts SAMPLES from the start of the run, beginning at 0, and the filter's delay line starts empty (zeros), exactly as the reference block's does.

⚠ THE SEMANTICS ARE MEASURED AGAINST R2026a, NOT INFERRED FROM THE FUNCTION decimate. That function low-pass filters with filtfilt — a forward-and-backward pass that is not causal and cannot be run on a stream at all — and then returns a SHORTER vector. A wire can do neither. What this block reproduces is the real Simulink block dspmlti4/FIR Decimation driven with FilterSource = 'Dialog parameters', InputProcessing = 'Elements as channels (sample based)' and framing = 'Enforce single-rate processing', which is the one configuration of it whose output port runs at the input's own rate. Measured with u = 1..12, h = [1 2 3] and D = 3, that block answers

1 1 1 16 16 16 34 34 34 52 52 52

which is the recursion above term for term: 1*1 at k = 0, then 4 + 2*3 + 3*2 = 16 at k = 3.

⚠ ITS outputBufInitCond IS NOT CARRIED HERE, AND THE REASON IS A MEASUREMENT. The real block offers a seed for the samples before the first retained one, but this configuration has none: there is no phase offset, so sample 0 is itself a retained sample and the seed is never published. Measured by running the same stimulus at outputBufInitCond = 0 and again at -9: the two runs are identical, to the digit. A config carrying a value nothing can observe would be worse than no config, so the entry pins the parameter to 0 instead.

⚠ THE RETAINED SAMPLE PUBLISHES THE FRESHLY COMPUTED SUM, NOT THE HELD REGISTER — the same rule Downsample is written to, and for the same reason. A held value written on a clocked tick is a REGISTERED assignment, so reading it back in the same tick returns its pre-clock contents: a body that stored the sum and then emitted the register would publish the PREVIOUS retained sample and lag the reference by a whole interval on one sample in D. Every one of the ten targets writes the same branch.

Sample results#

Decimate — Step: 0 -> 1 at t = 1 sDecimate — Step: 0 -> 1 at t = 1 s00.51012345t (s)in 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.5
rampRamp: slope 1 from t = 00 … 5.7
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.99 … 0.9886
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-1.125 … 1.5

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

Category dynamic · sample time 0.1 · 60 steps · commit 9237993cf · produced by docsSample --out <folder> --blocks Decimate Interpolate Upfirdn --steps 60 · data docs/generated/samples/Control_Systems__Resampling__Decimate.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).