Cross Power Spectral Density — Control Systems/Spectral Measurements
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.
- Window – the taper applied to each segment: Hamming
(MATLAB's default), Hann or Rectangular, the symmetric forms
hammingandhannreturn. - 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#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Spectral_Measurements/Cross_Power_Spectral_Density |
| family | Control_Systems/Spectral_Measurements |
| solver environment class | ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Cross_Power_Spectral_Density |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Cross_Power_Spectral_Density/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Cross_Power_Spectral_Density.cpp |
| header | src/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 canvas | 160 × 86 px |
| ports at insert | 2 in, 2 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 | x |
| 2 | in | ICoreDouble | y |
| 3 | out | ICoreDouble | Re |
| 4 | out | ICoreDouble | Im |
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 |
|---|---|---|
Segment Length | 8 | not crossed |
Segments | 4 | not crossed |
Segment Overlap | WC::OVL_NONE%~%WC::OVL_HALF%~%WC::OVL_3Q~~WC::OVL_HALF | not crossed |
Window | WC::WIN_HAMMING%~%WC::WIN_HANN%~%WC::WIN_RECT~~WC::WIN_HA… | not crossed |
Bin Spacing | 1 | not 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.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| deliberately not crossed | Segment 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#
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.01028 |
ramp | Ramp: slope 1 from t = 0 | 0 … 16.5 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 0.312 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | 2.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).