Generated reference › Octave Spectrum — Control Systems/Spectral Measurements
kind: generated#block#control-systems-spectral-measurements

Octave Spectrum — Control Systems/Spectral Measurements

1/3 oct

Control_Systems/Spectral_Measurements/Octave_Spectrum · 1 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.

Octave Spectrum

Control Systems / Spectral Measurements

Integrates a one-sided power spectral density over a bank of fractional-octave bands and reports one power per band, with the band centres taken from the ANSI S1.11-2004 preferred frequencies. This is MATLAB's poctave(Pxx, Fs, F, 'psd'), transcribed from its source. Band m's power is Pm = Σk wmk·pk, where the weights are the share of each bin's width that band m covers.

It rewrites a spectrum on a logarithmic frequency axis, which is how acoustic and vibration levels are read. It is an integration, not a filter bank: given a density there is nothing to filter, and every weight is decided before the run starts.

Ports

  • p – the one-sided power spectral density, an [N,1] column or a [1,N] row of 2 to 256 bins. Bin k sits at frequency k·Δ, so the first bin is DC. Values are expected non-negative, as MATLAB requires.
  • P – the band powers, M of them, in the same orientation as the input. M follows from the configuration and is fixed for the run; at most 64.
  • cf – the band centre frequencies, the same M entries and the same orientation. Constant for a given configuration: it is there so a plot or a log can label the bands without repeating the band arithmetic.

Parameters

  • Bin Spacing – Δ, the frequency step between neighbouring bins, a single positive number. The whole frequency axis follows from it.
  • Sample Rate (Hz) – the rate the density came from. It sets the default upper limit (Fs/2), clips the top band at Nyquist, and decides which bin gets the Nyquist doubling. Zero or less means the axis is taken to end exactly at Nyquist, i.e. Fs = 2·(N−1)·Δ – the ordinary case, and the default. A positive value must put Nyquist at or above the top of the axis.
  • Bands Per Octave – how finely the octave is divided: 1, 3/2, 2, 3, 6, 12 or 24. These are MATLAB's own values, less 48 and 96 – those two put hundreds of bands in a generated core. The parity of this number chooses which ANSI index formula runs, and 3/2 counts as odd, exactly as rem(b,2) reads it.
  • Frequency Range – which part of the axis is banded.
    • Full spectrum – from 3 Hz to Fs/2, MATLAB's own default range.
    • Frequency band – the range in Frequency Band below.
  • Frequency Band – [f_lo f_hi], read only in the banded mode, and it must lie inside [3, Fs/2]. Both edges are snapped OUTWARD to the nearest standard band, so the answer routinely covers more than was asked for.
  • 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. The band structure is resolved at export time, so each core is one short fixed multiply-accumulate per band with the weights inlined – no division, no branch, no loop and no moving array index. The centre frequencies are emitted as constants. Nothing is exposed as a tunable parameter: changing a band edge changes which bins are summed, which is structural rather than a number to retune.

The three HDL targets are genuine synthesizable Q16.16: the whole computation is a weighted sum of the input's bins, and the products accumulate at double width before the single shift back.

Simulink bridge

No equivalent (Support::None), so nothing crosses in either direction, and no parity testbench is owed. Measured rather than assumed: poctave is a Signal Processing Toolbox function, that toolbox ships no Simulink library at all, and a find_system sweep with LookUnderMasks over the DSP System Toolbox and Simulink library roots matched no octave block anywhere. No configuration of it crosses either, including "Sampling Time (s)", which has no counterpart to be written to. Code export verification still covers the block across all ten languages.

Notes

  • Algebraic, with no state: the answer depends on this sample's spectrum and nothing else.
  • A bin straddling two bands is SPLIT, not counted twice. Its power is shared in proportion to the width each band covers, which is what makes the band powers sum back to the total.
  • The DC and Nyquist bins are scaled by two, so a tone sitting on either is counted whole rather than halved by the one-sided convention. That affects the first and last band only.
  • The centres are not the limits you asked for. Both edges snap outward to the nearest standard band, and the rounding is on the band INDEX – geometric, not linear. Measured on a 33-bin density: a request for [10, 200] at one band per octave answers bands centred 7.94 to 251.19.
  • The octave ratio is 103/10, not 2. These are the base-ten bands of ANSI S1.11-2004, which is what MATLAB implements; a base-two bank puts its centres elsewhere.
  • The top band alone is clipped at Nyquist, so its weight differs from its neighbours' for that reason as well as the doubling.
  • There is no band below 3 Hz, MATLAB's own floor. A spectrum whose Nyquist is under it has no band at all and the block reports the configuration rather than answering an empty vector.

Code facts#

FactValue
registered typeControl_Systems/Spectral_Measurements/Octave_Spectrum
familyControl_Systems/Spectral_Measurements
solver environment classICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Octave_Spectrum
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Octave_Spectrum/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Octave_Spectrum.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Octave_Spectrum/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Octave_Spectrum.h
default size on canvas150 × 84 px
ports at insert1 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublep
2outICoreDoubleP
3outICoreDoublecf

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
Bin Spacing1—
Sample Rate (Hz)0—
Bands Per Octave1 (octave)%~%3/2%~%2 (half octave)%~%3 (third octave)%~%6…—
Frequency RangeFull spectrum%~%Frequency band~~Full spectrum—
Frequency Band[3 10]—

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. poctave is a Signal Processing Toolbox MATLAB function, not a block; that toolbox ships no Simulink library, and a find_system sweep of 8001 blocks across 26 library roots at depth 6 with LookUnderMasks carries no octave-band spectrum block

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:

  • B0 every 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).

Octave Spectrum -- fractional-octave band powers of a one-sided power spectral density (MATLAB poctave(Pxx, Fs, F, 'psd')). ONE WEIGHT MATRIX, TEN IDENTICAL MULTIPLY-ACCUMULATES. Which bins each band covers, and by how much, follows from the bin spacing, the bin count, the sample rate, the bands per octave and the frequency limits -- every one of them settled before the run starts. So the whole band structure is resolved once when the configuration is read, and each emitted core is a short fixed dot product per band: no division, no branch, no moving array index, and a GENUINE fixed-point pipeline on the three hardware targets rather than a simulation.

TRANSCRIBED FROM R2026a's poctave.m -- its octaveSmoothing branch, which is the 'psd' path -- together with signal.internal.octave.computeOctaveBands and getListOfANSICenterFrequencies. Prototyped in Python and DIFFED against a run of the installed R2026a before any of this was written. On the 33-bin density

f = 0:8:256 (Delta = 8, Fs = 512), pxx = [0.90 1.75 3.20 2.40 1.10 0.65 ...]

R2026a answers seven bands at one band per octave --

cf 3.9810717055349745 P 4.9678839145550953 cf 7.9432823472428176 P 9.7943497594532545 cf 15.848931924611138 P 32.693984375355797 cf 31.6227766016838 P 27.751403544700295 cf 63.095734448019329 P 29.583064459270677 cf 125.89254117941672 P 26.54418054066133 cf 251.188643150958 P 14.312044129727541

-- twenty at one third octave, and six over the limits [10, 200]. The weight form below reproduces all three sets to a worst relative error of 2.8e-16, which is summation order and nothing else.

⚠ THE ANSI BAND INDEX HAS TWO FORMULAE AND THE PARITY OF b PICKS ONE. For an odd number of bands per octave the centre is G^((x-30)/b)*1000; for an even one it is G^((2x-59)/(2b))*1000, with G = 10^(3/10) -- a BASE-TEN octave ratio, not 2. The two are not small variations of each other: at b = 2 the even formula puts a centre where the odd one puts a band edge. MATLAB's own rem(b,2) test reads 3/2 as odd, which is why that value is offered here and behaves like 1 and 3 rather than like 2.

⚠ THE REQUESTED LIMITS ARE SNAPPED OUTWARD, GEOMETRICALLY. getNearestANSIBand rounds the band INDEX, so the nearest band is the one whose passband contains the requested frequency, not the one whose centre is closest in hertz. Measured: limits [10, 200] at b = 1 answer

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Octave Spectrum. 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 3c100aff6f27235305db4ad4d572f32e342718ad · produced by docsSample --out <folder> --blocks Spectral_Entropy Octave_Spectrum Magnitude_Squared_Coherence --steps 60

Sample data: docs/generated/samples/Control_Systems__Spectral_Measurements__Octave_Spectrum.json