Generated reference › Circular Convolution — Control Systems/Correlation And Convolution
kind: generated#block#control-systems-correlation-and-convolution

Circular Convolution — Control Systems/Correlation And Convolution

Control_Systems/Correlation_And_Convolution/Circular_Convolution · 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.

Circular Convolution

Control Systems / Correlation And Convolution

Convolves the last NA samples of one stream with the last NB samples of another modulo L, every sample: y[n] = Σk+j≡n (mod L) a[k]·b[j], a vector of L entries. It is the streaming counterpart of MATLAB's cconv(a, b, L) applied to the two windows.

The output length is a parameter, not a consequence. Linear convolution answers with NA + NB − 1 entries and has no say in the matter; the circular one folds every term that runs past the end back onto the beginning. Set L to NA + NB − 1 or more and nothing wraps – the block is then the plain Convolution with zero padding. Set it smaller and the tail aliases onto the head, which is what the operation is for.

Ports

  • a – the first stream. Scalar; the block keeps its own window of the last NA samples – see Notes.
  • b – the second stream. Scalar, with its own window of the last NB samples.
  • y – the circular convolution, a column of L entries. Its size is the Output Length parameter alone and does not follow from the windows or from the inputs’ values.

Parameters

  • Window Length A – NA, how many samples of a take part. A whole number from 1 to 32. The bound is a code-size bound: both windows are unrolled in every target and the emitted work is their product.
  • Window Length B – NB, the same for b.
  • Output Length – L, the modulus and the output size. A whole number from 1 to 64. It is independent of the two window lengths.
  • Sampling Time (s) – zero or less inherits the solver’s rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.

All three lengths are structural: they decide how many multiplies the exported core contains and how wide its output is, which no runtime parameter can change, so they are baked in at export time rather than offered as tunable parameters. Re-export after changing any of them.

The three HDL targets are genuine synthesizable Q16.16: two shift registers and a fixed multiply-accumulate tree, with every product accumulated at full width and shifted back once per output entry rather than per term.

Simulink bridge

No equivalent (Support::None). The Signal Processing Toolbox ships no Simulink library at all, and nothing in the Simulink standard library or in DSP System Toolbox convolves two signals modulo a chosen length – DSP System Toolbox’s Convolution block is linear, and takes its lengths from its inputs’ dimensions rather than from a parameter. The bridge reports this block rather than dropping it silently, and it therefore has no parity testbench. Code export verification still covers it across all ten languages.

Notes

  • Stateful, and discrete by nature (setDiscreteOnlyBlock(true)): both windows advance once per sample.
  • Computed directly, where MATLAB transforms. cconv takes an FFT of each operand, multiplies and transforms back; this block sums the products. On a = [0.7 −1.3 0.45 2.1 −0.6] against b = [−0.9 0.25 1.7 −0.35 0.8] the two agree to 4.4e−16 at L = 5, 7 and 3 – a difference in rounding between two algorithms, not in the definition. A direct sum is also the only form the hardware targets can carry.
  • Oldest-first is the published order. a[0] is the oldest sample still in the window and a[NA−1] the newest.
  • The windows are zero-prefilled, and the zeros count. The first max(NA, NB)−1 outputs of a run are a startup transient rather than a convolution of real data.
  • Scalar inputs. Each input is one channel with its own window.
  • No state space. The block multiplies two signals together, so it is bilinear rather than linear, carries no A/B/C/D pair, and model reduction correctly declines to merge it.

Code facts#

FactValue
registered typeControl_Systems/Correlation_And_Convolution/Circular_Convolution
familyControl_Systems/Correlation_And_Convolution
solver environment classICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Circular_Convolution
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Circular_Convolution/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Circular_Convolution.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Circular_Convolution/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Circular_Convolution.h
default size on canvas132 × 80 px
ports at insert2 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublea
2inICoreDoubleb
3outICoreDoubley

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 Length A8—
Window Length B8—
Output Length8—

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: cconv() is a MATLAB function and the Signal Processing Toolbox ships no Simulink library at all. Nothing in the Simulink standard library or in DSP System Toolbox convolves two signals modulo a chosen length -- DSP System Toolbox's Convolution block is LINEAR and takes its lengths from its inputs' dimensions rather than from a parameter. Reported rather than dropped, and it carries no parity testbench

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

Circular Convolution -- the modulo-L convolution of two windowed streams, y = cconv(a, b, L) THE OUTPUT LENGTH IS A PARAMETER, NOT A CONSEQUENCE. Linear convolution of an NA-sample and an NB-sample window has NA + NB - 1 entries and no say in the matter; the circular one folds every term back modulo L and answers with L. Choose L >= NA + NB - 1 and nothing wraps, so the block becomes the plain Convolution with zero padding; choose it smaller and the tail aliases onto the head, which is the whole point of the operation and the default here.

⚠ COMPUTED DIRECTLY, WHERE MATLAB TRANSFORMS. R2026a's cconv() takes an FFT of each operand, multiplies and transforms back, so its answer and a direct sum of products differ by the rounding of two different algorithms rather than by their definitions. MEASURED on a = [0.7 -1.3 0.45 2.1 -0.6] and b = [-0.9 0.25 1.7 -0.35 0.8]: worst disagreement 4.4e-16 at L = 5, 7 and 3. A direct sum is also the only form the three hardware targets can carry, so this is a deliberate choice and not an approximation of one.

⚠ THE WINDOWS ARE ZERO-PREFILLED AND THE ZEROS COUNT -- the convention Detrend and Moving Median carry, the latter measured against Simulink. The first max(NA, NB) - 1 outputs of a run are a startup transient.

⚠ OLDEST-FIRST IS THE PUBLISHED ORDER; NEWEST-FIRST IS THE STORAGE ORDER, exactly as in the sibling Convolution block. The two orders meet in one expression per backend and nowhere else.

Sample results#

Circular Convolution — Step: 0 -> 1 at t = 1 sCircular Convolution — Step: 0 -> 1 at t = 1 s02468012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [8x1] entry 0

The same rig also ran:

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

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

Category dynamic · sample time 0.1 · 60 steps · commit 3c100aff6f27235305db4ad4d572f32e342718ad · produced by docsSample --out <folder> --blocks Convolution Circular_Convolution Convolution_Matrix Deconvolution Cross_Correlation Cross_Covariance --steps 60 · data docs/generated/samples/Control_Systems__Correlation_And_Convolution__Circular_Convolution.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).