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

Cross Covariance — Control Systems/Correlation And Convolution

Control_Systems/Correlation_And_Convolution/Cross_Covariance · 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-Covariance

Control Systems / Correlation And Convolution

Correlates the last N samples of one stream against the last N samples of another after removing each window's own mean, at every lag from −(N−1) to +(N−1), every sample: r(m) = Σn (a[n+m]−ma)·(b[n]−mb), a column of 2N − 1 entries. It is the streaming counterpart of MATLAB's xcov applied to the two windows.

The mean is the window's own, and it moves every sample. There is no running average and no forgetting factor: at each step the block averages exactly the N samples it is about to correlate. That is the only difference between this block and Cross-Correlation, which shares its lag order, its scalings and its shape.

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 covariance, 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 and the span the mean is taken over. 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 centred 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 centred 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, a mean per window, and a fixed multiply-accumulate tree per lag with the 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's Correlation block is the closest thing and is a different shape twice over: it correlates two vector-valued inputs, takes their lengths from those inputs' dimensions, has no window, lag-range or scaling parameter of its own, and does not remove a mean at all. 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 mean is the window's, not the signal's. It is recomputed from the N samples in hand at every step, so the block has no memory of a mean beyond its window and its answer does not depend on how long the run has been going.
  • 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.215 at lag −4 and 1.044 at lag +4. 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 twice. They take part in the sums and drag the mean towards zero, so the first N−1 outputs of a run are a larger startup transient than the sibling Cross-Correlation's. At unbiased they are also 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. A constant stream reaches that case honestly: its centred window is exactly zero.
  • 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/Cross_Covariance
familyControl_Systems/Correlation_And_Convolution
solver environment classICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Covariance
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Cross_Covariance/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Covariance.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Cross_Covariance/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Cross_Covariance.h
default size on canvas136 × 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
3outICoreDoubler

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 Length8—
Scalingnone%~%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.

supportSupport::None
Simulink path—
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): no Simulink equivalent: xcov() 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 twice over -- it correlates two VECTOR inputs, takes their lengths from those inputs' dimensions, has no window, lag-range or scaling parameter of its own, and does not remove a mean at all. 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-Covariance -- xcov over two windowed streams: xcorr after each window's mean is removed THE MEAN IS THE WINDOW'S OWN, AND IT MOVES EVERY SAMPLE. There is no running average and no forgetting factor: at each step the block averages exactly the N samples it is about to correlate and subtracts that from them. A mean carried across steps would be a different -- and lagging -- operation, and would make the block's answer depend on how long the run had been going. That is the whole difference between this block and Cross-Correlation, which otherwise shares its shape, its lag order and its four scalings.

THE LAG SIGN IS A CONVENTION AND THIS ONE WAS MEASURED, NOT REASONED ABOUT. R2026a's xcov(a, b) returns lags -(N-1) .. +(N-1) with r(m) = SUM ca[n+m]*cb[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.215 at lag -4 and 1.044 at lag +4 -- which are (a[0]-ma)(b[4]-mb) and (a[4]-ma)(b[0]-mb), and are the only cheap way to tell the convention from its mirror image.

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 CENTRED windows, 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 real rather 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, and here they do it twice over: the prefill drags the MEAN towards zero as well as taking part in the sums, so the startup transient is larger than the sibling block's and still lasts the full N - 1 samples.

Sample results#

Cross Covariance — Step: 0 -> 1 at t = 1 sCross Covariance — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [15x1] 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.1094 … 0.01562
rampRamp: slope 1 from t = 0-0.1225 … 0
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.4149 … 0.01772
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-6.234 … 4.266

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