Lomb Scargle Periodogram — Control Systems/Spectral Measurements
Control_Systems/Spectral_Measurements/Lomb_Scargle_Periodogram · 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.
Lomb-Scargle Periodogram
Control Systems / Spectral Measurements
The Lomb-Scargle periodogram of a record sampled at arbitrary times
– MATLAB's plomb(x, t, f). The samples arrive on one port and
their time stamps on a second, so the sampling need not be uniform and no
rate is assumed anywhere. At each frequency the block fits a sinusoid to the
mean-removed record by least squares, through the time offset τ that makes
its sine and cosine parts orthogonal:
tan(2ωτ) = Σsin(2ωt) ÷ Σcos(2ωt), ω = 2πf
P(f) = (Σx·cosω(t−τ))² ÷ Σcos²ω(t−τ) + (Σx·sinω(t−τ))² ÷ Σsin²ω(t−τ)
The frequencies are this block's own grid, fk = k·Δf for k = 0 … K−1, and P(0) = 0 as plomb sets it.
Ports
- x – the sample values, an [N,1] column, oldest first. N is read off the wire, from 4 to 128.
- t – the time stamp of each sample, [N,1], in seconds and in the same order as x. It should be increasing; only the last minus the first is read as the record length, and that is what the Power spectral density type divides by.
- P – the periodogram, [K,1], bin k at frequency k·Δf hertz, DC first and zero.
Parameters
- Number of Bins – K, the length of the output and of the frequency grid, a whole number from 2 to 1024. Defaults to 64.
- Bin Spacing – Δf, the frequency step in hertz, a positive number; the same parameter, under the same name, that Welch PSD and the rest of this family read. Defaults to 0.1. plomb's own default grid is 1÷(4·n·Ts) apart, four times finer than the record supports; choose Δf the same way if you want plomb's resolution.
- Spectrum Type – how the fitted power is scaled, plomb's three:
- Power spectral density – the default: divided by the average sampling rate (N−1)÷(tN−t1), so the answer is power per hertz.
- Normalized – divided by twice the record's variance (the unbiased one, N−1), the classical dimensionless Lomb statistic.
- Power – divided by N, so a sinusoid of amplitude A answers about A²/4 at its frequency.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. It is the rate the BLOCK runs at, and has nothing to do with the time stamps on the t port.
Code export
All ten targets: Python, MATLAB, Java, Rust,
C, C++, VHDL, Verilog, SystemVerilog and
PLC Structured Text, all from one program, so every target does the same
arithmetic in the same order as the simulation. The frequency grid is unrolled
into the core at export time, one block of statements per bin; the three
settings and the frame length are structural, so re-export after changing any of
them. The sine is emitted as a shifted cosine and the quadrant of τ is taken
with comparisons rather than an atan2, because PLC Structured Text
has neither.
The three HDL targets run that program in real arithmetic
and quantize only at the two input ports and the output: simulation-only,
not offered as synthesizable. The fit divides by sums that depend on the data,
and a time stamp of several seconds carried in Q16.16 would lose the phase
resolution the estimate is made of.
Simulink bridge
None (Support::None). plomb is a Signal
Processing Toolbox function and that toolbox ships no Simulink library; a
search of every DSP System Toolbox and Simulink library on R2026a found no
Lomb-Scargle or uneven-sampling estimator, so there is no path a diagram could
name. The bridge reports this block rather than dropping it silently, and it has
no parity testbench; code export verification covers all ten
languages.
Notes
- Algebraic: the output depends on this step's two frames alone.
- Verified against R2026a: this program agrees with
plomb(x, t, f, type)to 1.5e−14 of the largest bin over 300 records of 12 to 32 unevenly spaced samples, for all three types. - ⚠
plomb(x, t)with no frequency vector is a different computation: the Press-Rybicki fast approximation on a grid that follows the data. Measured on a 24-sample record, it differs from the exact sum on its own grid by 4.7e−4 per bin. This block is always the exact sum, on the grid the parameters fix. - MATLAB refuses a time vector that is not strictly increasing, or that has a negative entry; this block does not check, and answers what the formulas give. Repeated times are legitimate input to the fit; a decreasing vector makes the density type divide by a negative rate.
- A record with no variation at all – every sample equal – has a zero denominator in the Normalized type and answers infinities; the other two answer zero.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Spectral_Measurements/Lomb_Scargle_Periodogram |
| family | Control_Systems/Spectral_Measurements |
| solver environment class | ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Lomb_Scargle_Periodogram |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Lomb_Scargle_Periodogram/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Lomb_Scargle_Periodogram.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Lomb_Scargle_Periodogram/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Lomb_Scargle_Periodogram.h |
| default size on canvas | 160 × 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 | x |
| 2 | in | ICoreDouble | t |
| 3 | out | ICoreDouble | P |
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 |
|---|---|---|
Number of Bins | 64 | not crossed |
Bin Spacing | 0.1 | not crossed |
Spectrum Type | Power spectral density%~%Normalized%~%Power~~Power spectr… | 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 | Number of Bins, Bin Spacing, Spectrum Type |
Caveat (shown to the user): plomb is a Signal Processing Toolbox function, not a Simulink library block -- that toolbox ships no Simulink library -- and a search of 97 DSP System Toolbox and Simulink libraries (8600 blocks, R2026a) found no Lomb-Scargle or uneven-sampling spectrum block, 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 checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B0every stimulus in the sample errored — cross-checks skipped
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).
Lomb-Scargle Periodogram -- MATLAB's plomb(x, t, f, type), the spectrum of unevenly sampled data For each requested frequency f, with the record's mean removed and a time offset tau that makes the sine and cosine parts orthogonal:
tan(2*w*tau) = SUM sin(2*w*t) / SUM cos(2*w*t), w = 2 pi f P(f) = (SUM x cos(w(t-tau)))^2 / SUM cos^2(w(t-tau))
- (SUM x sin(w(t-tau)))^2 / SUM sin^2(w(t-tau))
Nothing there assumes a sampling rate: the times come in on their own port, so the samples may be as uneven as they like. The grid is this block's own -- f_k = k * Bin Spacing, k = 0 .. K-1 -- which is plomb's EXPLICIT-frequency form, plomb(x, t, f): P is zero at f = 0 by plomb's own rule, and the three spectrum types divide it by the average sampling rate (n-1)/(t_end-t_1), by n, or by twice the record's variance.
⚠ plomb WITHOUT a frequency vector IS NOT THIS: it runs the Press-Rybicki FAST approximation (extirpolation onto a 2^k grid, then two FFTs) on a data-dependent grid f_k = k / (ofac * n * Ts). Measured on R2026a over a 24-sample record: that approximation differs from the exact sum on its OWN grid by 4.7e-4 relative per bin (1.4e-5 of the largest bin), and its grid moves with the data. This block computes the exact sum on a grid the user fixes, so a Simulink-shaped signal path has a fixed output size -- and matches plomb(x, t, f) to 1.5e-14, measured over 300 records and all three types.
⚠ THE SIN IS COS SHIFTED BY pi/2. ICoreStatementProgram spells cos, atan, sqrt and log for all ten targets and not sin, so the program writes sin(a) as cos(a - pi/2) -- exact to a rounding of pi/2 -- and atan2 as atan with the quadrant taken by comparisons, which is also what PLC Structured Text needs, having no ATAN2. MATLAB's own lombscargle uses sinpi/cospi, whose exact argument reduction this cannot reproduce: over wt in [0, 400] the two differ by 1.6e-13.
Support::None: a sweep of 97 Simulink libraries (8600 blocks) found no Lomb, Scargle or uneven-sampling block, and plomb is a Signal Processing Toolbox function, which ships none.
Sample results#
No stimulus produced a sampled output in this rig — Invalid frame length at Lomb-Scargle Periodogram block: ICore Blocks/Home/Lomb Scargle Periodogram. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.
Category unsampled · sample time 0.1 · 60 steps · commit ee1ac01a4e538ed0c5e24de27bed3622cf0687b7 · produced by docsSample --out <folder> --blocks MUSIC_Spectrum Eigenvector_Spectrum Lomb_Scargle_Periodogram --steps 60
Sample data: docs/generated/samples/Control_Systems__Spectral_Measurements__Lomb_Scargle_Periodogram.json