Generated reference › Wigner Ville Distribution — Control Systems/Time Frequency
kind: generated#block#control-systems-time-frequency

Wigner Ville Distribution — Control Systems/Time Frequency

WVD

Control_Systems/Time_Frequency/Wigner_Ville_Distribution · 1 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.

Wigner-Ville Distribution

Control Systems / Time Frequency

The Wigner-Ville distribution of a stream, one time column per sample – MATLAB's wvd of the last N samples:

W[k] = |z(n)|² + 2·Σp=1..N/4 Re{z(n+p)·z*(n−p)·e−i2πkp/N},   k = 0 … N−1

where z is the analytic signal of the window and n = N/2: the output is column N+1 of wvd of the window, the time at its middle.

Ports

  • u – the sampled signal. Scalar: one channel and its own window.
  • W – the distribution at one instant, [N, 1]: row k is the frequency k·fs/(2N), DC first. It is real, and it can be negative – interference between components is what the distribution is known for.

Parameters

  • Window Length – N, the samples the distribution is formed over and the number of output rows: an even whole number from 4 to 16. Even because wvd pads an odd record to the next even length; bounded above because every row is a quadratic form of the window, unrolled at export, and the cost grows as N³.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Frames and timing

Once the window has filled – from sample N − 1, counting from 0 – the output at sample j is column N+1 of wvd(x(j−N+1 : j)): the distribution at the window's middle, time N/2, which is N/2 − 1 samples behind the newest input. It is recomputed on every sample; before the window fills it is all zeros.

The middle, and not the newest sample, because a finite record's newest column has no lag support at all: it is |z|² in every row.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The analytic-signal transform, the lag products and the frequency transform are folded into one fixed quadratic form per row at export time, so a generated core is products and sums only – no sine, no division, no square root. The window length is structural: re-export after changing it.

The three HDL targets are genuine Q16.16 and synthesizable: each product of two window samples is formed once per tick and every row is a multiply-accumulate over those products. Scale the signal into roughly ±1 first: the output is a sum of products of samples.

Simulink bridge

None (Support::None). wvd is a Signal Processing Toolbox function and that toolbox ships no Simulink library, so there is no path a diagram could name. 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: a register of the last N samples and a fill count.
  • Verified against R2026a: over every window of a 30-sample record at N = 4, 8, 10 and 16 the output matches column N+1 of wvd to 8.4×10−15 (the source banner carries the numbers).
  • Not reproduced: wvd's 'smoothedPseudo' windows, its NumFrequencyPoints and MinThreshold options, and a complex input (a real input is always turned into its analytic signal, as wvd does). The half-sample columns wvd also returns are not published: one column per input sample is the integer-time one.
  • MATLAB's frequency labels differ from the rows: wvd's second output names row k k·fs/(2(N−1)), while the transform puts it at k·fs/(2N) – a tone at fs/4 peaks exactly on row N/2. The matrix is MATLAB's either way.
  • For two signals use Cross Wigner-Ville Distribution, which is xwvd – a different construction, not this one with a second input.
  • No state space. The distribution is quadratic in the input, so model reduction correctly declines to merge it.

Code facts#

FactValue
registered typeControl_Systems/Time_Frequency/Wigner_Ville_Distribution
familyControl_Systems/Time_Frequency
solver environment classICoreBlock_0_Control_Systems_1_Time_Frequency_2_Wigner_Ville_Distribution
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Time_Frequency/Wigner_Ville_Distribution/ICoreBlock_0_Control_Systems_1_Time_Frequency_2_Wigner_Ville_Distribution.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Time_Frequency/Wigner_Ville_Distribution/ICoreBlock_0_Control_Systems_1_Time_Frequency_2_Wigner_Ville_Distribution.h
default size on canvas150 × 80 px
ports at insert1 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleu
2outICoreDoubleW

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—

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): wvd is a Signal Processing Toolbox function, not a Simulink library block -- that toolbox ships no Simulink library at all -- so there is no path a diagram could name; the block is reported rather than dropped when a model crosses

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

Wigner-Ville Distribution -- MATLAB's wvd, one time column per sample W[k] = |z(n)|^2 + 2 * SUM(p = 1..floor(N/4)) Re{ z(n+p) conj(z(n-p)) e^(-j 2 pi k p / N) }

over the last N samples, with z the analytic signal of that window (zero-padded to 2N, as wvd forms it) and n = N/2: the output at sample k is column N+1 of wvd(x(k-N+1 : k)).

MEASURED AGAINST R2026a before a line was written, and the conventions are what was checked:

  • wvd of an N-sample record is N-by-2N -- its time axis is a HALF-SAMPLE grid, 0, 0.5, ...,

N-0.5 -- and the even columns (integer times) are exactly the sum above, reproduced to 1.3e-14 on every even column at N = 4, 8, 10, 12 and 16. The lag sum stops at floor(N/4): that is wvdImpl's maxLag = floor(N/2) counted in half-samples.

  • The NEWEST column of a record is degenerate: at time N-1 no lag has support, and the column

is |z(N-1)|^2 in every row (0.955372 flat on the 16-sample check). So a streaming block cannot publish it; it publishes time N/2, where the lag support is whole, N/2 - 1 samples behind the newest input.

  • Row k is frequency k*fs/(2N): a tone at fs/4 peaks on row N/2 exactly. MATLAB's second

output labels the same rows linspace(0, fs/2, N), i.e. k*fs/(2(N-1)) -- a label, not the transform, and it names the fs/4 row 0.533*fs/2.

  • For the record x = [1.2 0.7 2.5 0.3 0.12 0.8 1.1 -0.22], column 9 of wvd(x) is

[6.0508790114570 2.0514242084229 -8.0985740311937 -5.4494751059774 5.3812266007568 5.0451436285106 -3.1951630146658 -1.5087241646017]; the block's quadratic forms give it to 2.7e-15, and to 8.4e-15 over every window of a 30-sample record at N = 4, 8, 10, 16.

Support::None: wvd is a Signal Processing Toolbox FUNCTION and that toolbox ships no Simulink library, so there is no counterpart to bridge to or run a parity testbench against.

Sample results#

Wigner Ville Distribution — Step: 0 -> 1 at t = 1 sWigner Ville Distribution — Step: 0 -> 1 at t = 1 s024012345t (s)in 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 … 0.2351
rampRamp: slope 1 from t = 00 … 151.6
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias0 … 4.324
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-3.325 … 6.316

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

Category dynamic · sample time 0.1 · 60 steps · commit 875fdbf564cf31a145283edf6a75dc1d64d1090a · produced by docsSample --out <folder> --blocks Wigner_Ville_Distribution Cross_Wigner_Ville_Distribution Inverse_STFT Fourier_Synchrosqueezed_Transform Time_Frequency_Ridges Frequency_Domain_Filter_Identification Fill_Gaps EOM_6DOF_ECEF_Quaternion EOM_6DOF_Custom_Variable_Mass_ECEF_Quaternion EOM_6DOF_Simple_Variable_Mass_ECEF_Quaternion ECI_To_ECEF_Rotation_Matrix ECI_Position_To_LLA LLA_To_ECI_Position ECI_Position_To_AER --steps 60 · data docs/generated/samples/Control_Systems__Time_Frequency__Wigner_Ville_Distribution.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).