Cross Correlation — Control Systems/Correlation And Convolution
Control_Systems/Correlation_And_Convolution/Cross_Correlation · 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.
Cross-Correlation
Control Systems / Correlation And Convolution
Correlates the last N samples of one stream against the last N
samples of another at every lag from −(N−1) to +(N−1),
every sample: r(m) = Σn a[n+m]·b[n], a column of
2N − 1 entries. It is the streaming counterpart of MATLAB's
xcorr applied to the two windows, in the same lag order and with the
same four scalings.
Lag order: entry 1 carries lag −(N−1), entry N carries lag 0, and entry 2N−1 carries lag +(N−1). A positive lag is a leading a.
Ports
- a – the first stream, the one a positive lag advances. Scalar; the block keeps its own window of the last N samples – see Notes.
- b – the second stream, held still. Scalar, with its own window of the same length.
- r – the correlation, a column of 2N − 1 entries ordered by increasing lag. Its size follows from Window Length alone.
Parameters
- Window Length – N, how many samples of each stream take part, and therefore the widest lag. A whole number from 2 to 24. The bound is a code-size bound: the emitted work grows as N².
- Scaling – how each lag is normalised:
- none – the raw sum of products. MATLAB's default, and this block's.
- biased – divided by N at every lag.
- unbiased – divided by N − |m|, the number of terms that lag actually has, so the far lags are not damped by having fewer of them.
- coeff – divided by √(Sa·Sb), the geometric mean of the two windows' energies, which puts lag 0 at 1 for identical streams and keeps every entry within ±1. This is the only scaling built from the data, and the only one with a square root in it – see Code export.
- 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.
Window Length and Scaling are structural: they decide how many multiplies the core contains, how wide its output is, and for three of the four scalings the constants folded into the arithmetic. They are baked in at export time rather than offered as tunable parameters. Re-export after changing either.
The three HDL targets are genuine synthesizable Q16.16 at
none, biased and unbiased: two shift registers and a fixed
multiply-accumulate tree per lag, with each lag's constant folded in. At
coeff they are simulation-only instead, and deliberately so: that
scaling needs a square root and a division of two run-time quantities, neither
of which belongs in a Q16.16 datapath, so the emitted core computes that
configuration in real arithmetic and quantizes only at the port
boundary. The other nine targets are unaffected.
Simulink bridge
No equivalent (Support::None). The Signal Processing
Toolbox ships no Simulink library at all. DSP System Toolbox does have a
Correlation block, and it is a different shape: it correlates two
vector-valued inputs, takes their lengths from those inputs' dimensions
and has no window parameter, no lag-range parameter and no scaling parameter of
its own, so nothing this block is configured with maps onto it. 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. - The lag sign was measured, not assumed. On a = [0.7 −1.3 0.45 2.1 −0.6] against b = [−0.9 0.25 1.7 −0.35 0.8], R2026a reports 0.56 at lag −4 and 0.54 at lag +4, which are a[0]·b[4] and a[4]·b[0]. The opposite convention mirrors the whole output about its centre.
- Oldest-first is the published order. a[0] is the oldest sample still in the window and a[N−1] the newest.
- The windows are zero-prefilled, and the zeros count – and this matters most at unbiased, which divides by the number of terms the lag would have in a full window rather than by the number that are real data. The first N−1 outputs of a run are a startup transient scaled as though the prefill were measurement. MATLAB has the whole vector in hand and never meets the case.
- At coeff, an empty window answers zero rather than infinity. If Sa·Sb falls below 1e−12 every entry is set to 0; all ten targets use that same constant, so they agree on where the answer stops being defined.
- 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#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Correlation_And_Convolution/Cross_Correlation |
| family | Control_Systems/Correlation_And_Convolution |
| solver environment class | ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Correlation |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Cross_Correlation/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Correlation.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Cross_Correlation/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Correlation.h |
| default size on canvas | 136 × 80 px |
| ports at insert | 2 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 | a |
| 2 | in | ICoreDouble | b |
| 3 | out | ICoreDouble | r |
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 |
|---|---|---|
Window Length | 8 | — |
Scaling | none%~%biased%~%unbiased%~%coeff~~none | — |
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 Simulink equivalent: xcorr() is a MATLAB function and the Signal Processing Toolbox ships no Simulink library at all. DSP System Toolbox's Correlation block is a different shape -- it correlates two VECTOR inputs, takes their lengths from those inputs' dimensions, and has no window, lag-range or scaling parameter of its own, so nothing this block is configured with maps onto it. 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).
Cross-Correlation -- xcorr over two windowed streams, at every lag, with the four scalings THE LAG SIGN IS A CONVENTION AND THIS ONE WAS MEASURED, NOT REASONED ABOUT. R2026a's xcorr(a, b) returns lags -(N-1) .. +(N-1) with r(m) = SUM a[n+m]*b[n], so a POSITIVE lag is a LEADING a. 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 run reports 0.56 at lag -4 and 0.54 at lag +4 -- which is exactly a[0]*b[4] and a[4]*b[0], and is the only cheap way to tell the convention from its mirror image. Get it backwards and the whole output is reflected about its centre, which no test with interchangeable inputs sees.
THREE OF THE FOUR SCALINGS ARE CONSTANTS AND ONE IS NOT. none 1 biased 1/N -- known at export time unbiased 1/(N-|m|) -- known at export time, and DIFFERENT per lag coeff 1/sqrt(Sa*Sb) -- built from the windows themselves, every sample The first three are inlined into the arithmetic. coeff is the only one that puts a square root and a division in the emitted core, and it is therefore the only configuration whose three HDL targets are simulation-only
realrather than synthesizable Q16.16 -- the same choice Cartesian To Polar makes, for the same reason.MEASURED AGAINST MATLAB R2026a on all four scalings; the probe and its numbers are recorded in the notes of the toolbox-blocks plan, Family B.
⚠ THE WINDOWS ARE ZERO-PREFILLED AND THE ZEROS COUNT -- the convention Detrend and Moving Median carry. The first N - 1 outputs of a run are a startup transient. Note what this does to the UNBIASED scaling in particular: it divides by the number of terms the lag WOULD have in a full window, not by the number that are real data, so the early samples are scaled as if the zeros were measurements. MATLAB has the whole vector and never meets the case.
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 |
ramp | Ramp: slope 1 from t = 0 | 0 … 30.68 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.4147 … 0.5848 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -6 … 6 |
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__Cross_Correlation.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).