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

Rational Resample — Control Systems/Resampling

P/Q

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

Rational Resample

Control Systems / Resampling

MATLAB's resample on a stream: a rate change by P/Q through one anti-aliasing filter that the block designs for you, exactly as resample(x, P, Q, n, beta) designs it. The ratio is reduced to lowest terms p/q, and the filter is a Kaiser-windowed least-squares low-pass h = firls(2·n·max(p,q), [0 2fc 2fc 1], [1 1 0 0]) · kaiser(L, beta) with fc = 1/(2·max(p,q)), scaled so its taps sum to p. The output is upfirdn(u, [0…0 h], p, q): the input stuffed with p−1 zeros per sample, filtered once, and one sample in every q kept and held until the next.

How it relates to resample. resample puts nZ = floor(q − mod((L−1)/2, q)) zeros in front of h so that the filter's delay is a whole number D = floor(ceil((L−1)/2 + nZ)/q) of output samples, and then drops the first D samples of its answer so that output 0 lines up with input 0. Dropping them needs the input D samples ahead, which a stream does not have, so this block emits them: its kept sample m IS resample's sample m − D, and its first D kept samples are the filter filling up. At the defaults D = 16 output samples (10.7 input samples).

The block runs at the fast rate – P times the input's – so drive it from a source running at P times this block's "Sampling Time (s)". A new input sample is taken on every Pth tick (k mod P = 0) and a sample is published on every Qth (k mod Q = 0), with k counting from 0 at the start of the run and the filter starting empty.

Ports

  • Input – the signal u to resample, of any size [m,n]. Every entry is resampled on the same ticks through its own delay line; the entries do not interact.
  • Output – the resampled-and-held signal y, the SAME size [m,n] as the input, at the block's own (fast) rate.

Parameters

  • Upsampling Factor – P, the number of ticks per input sample, a whole number of 1 or more. Defaults to 3.
  • Downsampling Factor – Q, the number of ticks per kept sample, a whole number of 1 or more. Defaults to 2. P and Q set the tick grid as typed; the filter is designed from p/q, their ratio in lowest terms, as resample designs it – so P = 4, Q = 2 computes what P = 2, Q = 1 computes, on a grid twice as fine. When the ratio reduces to 1/1 there is no filter and no delay: the block passes the input straight through.
  • Neighbor Term Number – n, resample's own n: each output sample is computed from about n input samples on each side, and the filter has 2·n·max(p,q) + 1 taps. A whole number of 0 or more; at 0 the filter is ones(1,p), a hold rather than a low-pass. Defaults to 10.
  • Kaiser Window Beta – beta, the Kaiser window's shape: 0 is a rectangular window, larger values trade a wider transition band for a lower stopband. A finite number of 0 or more. Defaults to 5.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. On this block that is the fast rate: a new input sample is taken every Pth step of it and a sample is published every Qth.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The filter is designed at export time and its taps are baked into the core as constants, together with both factors: the tap count fixes how many state words the core carries, so none of the four is a tunable parameter on a built core.

The filter is realized in polyphase form: the delay line holds INPUT samples, not stuffed zeros, and on a publishing tick only the taps that meet a real sample are summed – the phase is chosen by which tick it is. At the defaults that is 21 state words per signal entry where a line over the stuffed stream would need 62. Taps that are exactly zero (every max(p,q)-th tap of the designed filter, and the front padding) are left out of the emitted sums.

The three HDL targets are not simulation-only: the arithmetic is a multiply-accumulate over constant taps, which the Q16.16 datapath carries; the small taps at the filter's edges are quantized to that format along with everything else. Because the sum is emitted unrolled, the designed filter is limited to 1025 taps (n = 10 at a reduced max(p,q) of 51), which keeps every generated function inside the size a Java method may have. A longer design is refused with that reason rather than exported.

Simulink bridge

Neither imported nor exported. MATLAB's resample is a Signal Processing Toolbox function, and no Simulink block designs its filter. The Simulink block that computes the same arithmetic once the taps are given is dspmlti4/FIR Rate Conversion with FilterSource set to its dialog and the coefficients set to [0…0 h] – the counterpart of this family's Upfirdn – and it has no sample-based mode: it is frame-based, and refuses a one-element signal. An ICore wire carries one sample per tick, so there is no configuration of it for a bridge to name.

Notes

  • Stateful: the last input samples each phase of the filter needs, the retained sample, and two phase counters – one mod P for which tick takes a sample, one mod Q for which tick publishes. All start from zero at the beginning of every run, so a re-run reproduces the stream exactly.
  • Discrete by nature – the phases advance once per sample, so the block always takes its period from its own "Sampling Time (s)".
  • Direct feedthrough only when the padded filter's first tap is nonzero. With n of 1 or more it never is – the front padding is at least one zero – so the output on a tick never depends on the input on the same tick. It can be at a 1/1 ratio (a pass-through) and for some n = 0 holds with an even p, and the block declares it exactly when it is.
  • No state space, deliberately: which taps meet a sample depends on WHEN it arrives, so the block is periodically time-varying.
  • Rational Resample vs. Upfirdn. Upfirdn computes the same stream from a filter you supply; this block designs resample's filter and pads it. To reproduce resample(x, p, q, b) with your own filter b, use Upfirdn with [0…0 b] as its coefficients.

Code facts#

FactValue
registered typeControl_Systems/Resampling/Rational_Resample
familyControl_Systems/Resampling
solver environment classICoreBlock_0_Control_Systems_1_Resampling_2_Rational_Resample
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Resampling/Rational_Resample/ICoreBlock_0_Control_Systems_1_Resampling_2_Rational_Resample.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Resampling/Rational_Resample/ICoreBlock_0_Control_Systems_1_Resampling_2_Rational_Resample.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
Upsampling Factor3not crossed
Downsampling Factor2not crossed
Neighbor Term Number10not crossed
Kaiser Window Beta5not crossed

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
deliberately not crossedUpsampling Factor, Downsampling Factor, Neighbor Term Number, Kaiser Window Beta

Caveat (shown to the user): MATLAB's resample is a Signal Processing Toolbox FUNCTION and no Simulink block designs its filter. The block that computes the same arithmetic once the taps are given is dspmlti4/FIR Rate Conversion with FilterSource = 'Dialog parameters' and the coefficients [zeros(1,nZ) h] - Upfirdn's counterpart - and it HAS NO SAMPLE-BASED MODE: its dialog carries no InputProcessing parameter and, measured on R2026a, it refuses a one-element signal under 'Enforce single-rate processing'. An ICore wire carries one sample per tick, so there is no configuration of it for a bridge to name

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

Rational Resample block — MATLAB's resample, on a stream: P/Q through ONE designed polyphase filter A rate change by P/Q whose anti-aliasing filter is designed for you, the way MATLAB's resample(x, p, q, n, beta) designs it. What that function adds over upfirdn is exactly three things, and all three were read out of R2026a's own sources and then measured:

  1. P/Q IS REDUCED TO LOWEST TERMS FIRST — rat(p/q, 1e-12) — so resample(x,4,2) IS

resample(x,2,1), filter and all, and a ratio that reduces to 1/1 returns x untouched: no filter and no delay at all (measured at 3/3: max |y - x| = 0).

  1. THE FILTER IS DESIGNED: firls(2*n*max(p,q), [0 2fc 2fc 1], [1 1 0 0]) .* kaiser(L, beta),

fc = 1/(2*max(p,q)), then scaled to SUM TO p. Defaults n = 10, beta = 5. Measured, that is p*fir1(L-1, 1/max(p,q), kaiser(L,beta)) to 2.2e-16 and a Kaiser-windowed sinc to 3.3e-16, and every tap a whole multiple of max(p,q) away from the centre is EXACTLY zero. At n = 0 the filter is ones(1,p), a hold.

  1. THE FILTER'S DELAY IS PADDED TO A WHOLE NUMBER OF OUTPUT SAMPLES AND THEN DROPPED:

nZ = floor(q - mod((L-1)/2, q)) zeros go in front of the filter, and the first D = floor(ceil((L-1)/2 + nZ)/q) samples of upfirdn's answer are thrown away, so that output sample 0 lines up with input sample 0.

The third is the one a stream cannot do: dropping the first D samples of an answer means knowing the input D output samples AHEAD. So this block emits what can honestly be emitted — the whole of upfirdn(x, [zeros(1,nZ) h], p, q), in which resample's answer is the part from sample D on. Measured over seven ratios (3/2, 2/3, 5/3, 4/2, 1/4, 4/1, 7/5) and the n = 0 hold: resample(x,p,q) equals that stream shifted by D to exactly 0, so the block's kept sample m IS resample's sample m - D, and its first D kept samples are the filter filling — the ones resample discards. At the defaults (3/2) D = 16 output samples, 10.7 input samples. resample's END handling (it treats the record as zero past its last sample) has no counterpart on a stream, which has no last sample.

The block runs at the FAST rate, P times its input's, like Upfirdn beside it: a new input sample enters every Pth tick and a sample is published every Qth, held in between. The tick grid follows the factors AS TYPED; only the filter is designed from the reduced pair (p, q). On a published tick k (a multiple of Q, hence of g = gcd(P,Q)) the reduced stuffed stream is at k' = k/g, its phase is r = (k mod P)/g, and only the taps h[r], h[r+p], h[r+2p], ... meet a real sample — which is the polyphase form:

y = sum_i c[r + i*p] * x[j - i] j = the newest input sample taken

so the delay line holds INPUT samples, not stuffed zeros, and the filter runs only on the ticks that publish. At the defaults that is 21 words per signal entry where a delay line over

Sample results#

Rational Resample — Step: 0 -> 1 at t = 1 sRational Resample — 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
rampRamp: slope 1 from t = 0-0.02116 … 2.598
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.9968 … 0.987
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-2.001 … 3.217

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

Category dynamic · sample time 0.1 · 60 steps · commit 6280f52f3 · produced by docsSample --out <folder> --blocks Rational_Resample,Three_Axis_Accelerometer,Three_Axis_Gyroscope,Three_Axis_Inertial_Measurement_Unit,Eclipse_Shadow_Model,To_String,String_To_ASCII,ASCII_To_String,Substring,String_Constant,String_Concatenate,String_Compare,String_Length --steps 60 · data docs/generated/samples/Control_Systems__Resampling__Rational_Resample.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).