Generated reference › Cross Power Spectral Density — Control Systems/Spectral Measurements
kind: generated#block#control-systems-spectral-measurements

Cross Power Spectral Density — Control Systems/Spectral Measurements

Pxy

Control_Systems/Spectral_Measurements/Cross_Power_Spectral_Density · 2 input / 2 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 Power Spectral Density

Control Systems / Spectral Measurements

The one-sided cross power spectral density of two streams by Welch's method – MATLAB's cpsd – over a sliding window: K windowed L-point segments of x and of y, their transforms multiplied and averaged:

Pxy(m) = c(m) ÷ (K·fs·Σw²) · Σs Xs(m)·conj(Ys(m)), with c = 1 at DC and Nyquist and 2 between.

That is cpsd(x, y, window, noverlap, L, fs) over the last W = L + (K−1)·hop samples. The answer is complex; it is published as its real and imaginary parts on two ports, because an ICore signal carries doubles.

Ports

  • x – the first stream, a scalar.
  • y – the second stream, a scalar.
  • Re – the real part of Pxy, a column of L/2 + 1 entries, DC first and Nyquist last; entry m is at m·fs/L hertz.
  • Im – the imaginary part, the same size.

Parameters

  • Segment Length – L, the transform length, an even whole number from 4 to 32. It sets the frequency resolution and the number of output bins.
  • Segments – K, how many segments are averaged, from 1 to 8. One is allowed: a single segment is an ordinary cross periodogram, noisy but meaningful – unlike a coherence, which it makes identically 1.
  • Segment Overlap – how far the segments overlap.
    • None (0%) – the hop is L.
    • Half (50%) – the hop is L/2. MATLAB's default, and this block's.
    • Three quarters (75%) – the hop is L/4; needs L divisible by four.
    The window the block holds is W = L + (K−1)·hop samples long.
  • Window – the taper applied to each segment: Hamming (MATLAB's default), Hann or Rectangular, the symmetric forms hamming and hann return.
  • Bin Spacing – Δf, the frequency step between output bins, in hertz; the sampling rate follows as fs = L·Δf and is what makes the answer a density. The same parameter, under the same name, that Welch PSD and the rest of this family read.
  • 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. Every transform is a fixed weighted sum of window taps, computed once at export time, so no emitted core contains a sine, a cosine or a loop over data; the two windows become shift registers. All five settings are structural.

The three HDL targets are simulation-only: they carry the arithmetic in real and quantize only at the port boundary, as Magnitude-Squared Coherence's do.

Simulink bridge

No equivalent a bridge can write (Support::None), and the block that exists is named here rather than denied. DSP System Toolbox's dspspect3/Cross-Spectrum Estimator computes a Welch cross-spectrum, but, measured on R2026a: it answers on one complex port, where this block presents Re and Im on two real ones; driven one sample per step it publishes once every hop samples, so its output runs at a lower rate than its input; and its windows are the periodic forms – its steady-state outputs equal cpsd with hann(L,'periodic') over the W samples ending one sample before each output, while this block uses the symmetric window cpsd uses by default. Any one of the three leaves no port-to-port mapping to write, so no configuration crosses and no parity testbench is owed.

Notes

  • Stateful and inherently discrete: two shift registers of W samples, advanced once per sample (setDiscreteOnlyBlock(true)), and zero-prefilled at the start of every run.
  • ⚠ The conjugate is on y. MATLAB's cpsd(x, y) is ΣX·conj(Y); swapping the ports conjugates the answer, which negates Im and leaves Re alone.
  • Related blocks. Magnitude-Squared Coherence reads the same averaged sums and divides by both auto-spectra; Transfer Function Estimate reads them too; Welch PSD is the auto-spectrum of one stream.

Code facts#

FactValue
registered typeControl_Systems/Spectral_Measurements/Cross_Power_Spectral_Density
familyControl_Systems/Spectral_Measurements
solver environment classICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Cross_Power_Spectral_Density
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Cross_Power_Spectral_Density/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Cross_Power_Spectral_Density.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Cross_Power_Spectral_Density/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Cross_Power_Spectral_Density.h
default size on canvas160 × 86 px
ports at insert2 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublex
2inICoreDoubley
3outICoreDoubleRe
4outICoreDoubleIm

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
Segment Length8not crossed
Segments4not crossed
Segment OverlapWC::OVL_NONE%~%WC::OVL_HALF%~%WC::OVL_3Q~~WC::OVL_HALFnot crossed
WindowWC::WIN_HAMMING%~%WC::WIN_HANN%~%WC::WIN_RECT~~WC::WIN_HA…not crossed
Bin Spacing1not 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 crossedSegment Length, Segments, Segment Overlap, Window, Bin Spacing

Caveat (shown to the user): dspspect3/Cross-Spectrum Estimator computes a Welch cross-spectrum and is named here rather than denied, but no port-to-port mapping exists, for three reasons measured on R2026a: it answers on ONE COMPLEX port where this block presents Re and Im on two real ones; driven one sample per step it publishes once every hop samples (15 outputs from 60 samples at hop 4), so its output rate is not its input's; and its windows are the PERIODIC forms (its steady-state outputs equal cpsd with hann(L,'periodic') over the W samples ending one sample before each output, to 1.6e-16), where this block uses the symmetric window cpsd uses by default

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 Power Spectral Density -- MATLAB's cpsd over a sliding window, as Re and Im Pxy(m) = c(m) / (K fs SUM w^2) * SUM_s X_s(m) conj(Y_s(m)), c = 1 at DC and Nyquist, 2 between

over the last W = L + (K-1)*hop samples of x and y, K windowed L-point segments. With the four averaged sums Magnitude-Squared Coherence already computes -- pr + j pi = SUM conj(X) Y -- that is Re = c/(K fs U) * pr and Im = -c/(K fs U) * pi, U = SUM w^2. The sums, the table and the emitted multiply-accumulates are that block's, shared through ICoreWelchCrossSupport, so this is not a second implementation of Welch.

⚠ MEASURED AGAINST R2026a BEFORE ANY C++ WAS WRITTEN, and what it pinned is the one sign a reader would guess wrong: MATLAB's cpsd(x, y) is SUM X conj(Y), the conjugate of the sum the coherence reads. Against sc*SUM conj(X)Y cpsd disagrees by 1.7-1.9 (relative); against sc*SUM X conj(Y) it agrees to 2.5e-16 at worst, over hamming, hann and rectwin at L = 8, K = 4, 50 % overlap -- which also pins the divisor K*fs*SUM w^2 and the interior doubling, the same two conventions Welch PSD measured for pwelch.

⚠ THE SIMULINK BLOCK EXISTS AND CANNOT BE THE BRIDGE, for three measured reasons, each on its own enough. dspspect3/Cross-Spectrum Estimator (1) answers on ONE COMPLEX port; (2) driven one sample per step with WindowLength 8, Overlap 50 and SpectralAverages 4 it publishes once every HOP samples -- 15 outputs from 60 samples -- so its output runs at a quarter of its input's rate; (3) its windows are PERIODIC: its steady-state outputs equal cpsd(x, y, hann(8,'periodic'), 4, 8, fs) over the W samples ending one sample BEFORE the output instant, to 1.6e-16, and the symmetric hann(8) this block and cpsd use by default does not match them. So the entry is Support::None and names the block.

The three HDL targets are SIMULATION-ONLY real arithmetic, as the coherence's are.

Sample results#

Cross Power Spectral Density — Step: 0 -> 1 at t = 1 sCross Power Spectral Density — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [5x1] entry 0out ICoreDouble-Out-1 [5x1] 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 … 0.01028
rampRamp: slope 1 from t = 00 … 16.5
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias0 … 0.312
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample2.869e-4 … 0.5499

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

Category dynamic · sample time 0.1 · 60 steps · commit 93133d604 · produced by docsSample --out <folder> --blocks Gain_Scheduled_Lead_Lag Controller_1D Controller_Blend_1D Controller_2D Controller_3D Observer_Form_1D Self_Conditioned_1D Line_Of_Sight_Access Orbit_Propagator_Kepler Attitude_Dynamics Attitude_Profile_Nadir_Pointing Attitude_Profile_Geographic_Pointing Multitaper_PSD Cross_Power_Spectral_Density Transfer_Function_Estimate Envelope_Spectrum Compose_String Scan_String --steps 60 · data docs/generated/samples/Control_Systems__Spectral_Measurements__Cross_Power_Spectral_Density.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).