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

Median Frequency — Control Systems/Spectral Measurements

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

Median Frequency

Control Systems / Spectral Measurements

The half-power frequency of a power spectral density – the point that divides its integrated power in two, so that as much power lies below it as above. With bin k at fk = k·Δ carrying Pk = Δ·pk, the block integrates the bins as rectangles whose borders sit halfway between neighbouring bin frequencies, and reports the frequency at which the running total reaches half the whole. This is the streaming counterpart of MATLAB's medfreq.

It is not a weighted average: it inverts the cumulative power curve rather than summing against it, which is why a spectrum can have a mean frequency and a median frequency far apart.

Ports

  • p – the power spectral density, one nonnegative value per bin. A vector, either an [N,1] column or a [1,N] row, with N between 2 and 256. Bin k is the frequency k·Δ.
  • f – the half-power frequency, in the same units as Bin Spacing. Always scalar, whatever the input's length. It lies between 0 and (N−1)·Δ and is generally not on a bin centre.

Parameters

  • Bin Spacing – Δ, the frequency step between neighbouring bins, a positive number. Left at 1 the answer comes out in bins; set it to fs÷(2·(N−1)) for a one-sided spectrum reaching the Nyquist frequency and the answer comes out in Hz.
  • Epsilon – ε, a degeneracy guard, not an accuracy knob. It is what makes a bin of exactly zero power behave as a step rather than a division of zero by zero, and the default of 1e−18 is far below any bin a real spectrum carries. Raising it biases the answer; there is no reason to.
  • 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 bin count, the bin spacing and the border positions are structural and are inlined at export time rather than exposed as tunable parameters – changing any of them changes how many terms the core contains, which no runtime parameter can do. Re-export after changing them.

The three HDL targets are simulation-only: the block divides once per bin, and a Q16.16 divider is not part of this tree's fixed-point base. They compute in real arithmetic – VHDL through an emitted function, Verilog and SystemVerilog through declared real scratch – and quantize only at the port boundary, so they simulate correctly and are not offered as synthesizable.

Simulink bridge

No equivalent (Support::None). Signal Processing Toolbox ships no Simulink library at all, and medfreq is one of its MATLAB functions. DSP System Toolbox was searched block by block and carries no half-power measurement. 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

  • Stateless. The answer depends on this sample's spectrum and nothing else, so there is no startup transient and no history to seed.
  • Verified against MATLAB on three different kinds of spectrum. An 8-bin spectrum [0.12 0.85 2.40 1.10 0.35 0.60 0.18 0.07] at Δ = 0.5 gives 1.1385416666666666; an 11-bin spectrum [2.5105 2.9801 3.191 3.7727 2.9726 3.6932 0.1646 1.8892 3.7763 2.6134 3.6086] at Δ = 0.35 gives 1.5900871872630777; and [0 0 3 0 0 1 0 0] at Δ = 0.5, which has four empty bins, gives 1.0833333333333333. R2026a answers all three, and this block reproduces them.
  • The whole spectrum, always. Unlike Band Power and Mean Frequency this block offers no frequency band: MATLAB's banded form interpolates the cumulative curve at both band edges as well as at the half-power level, which is a third rule again, and it is not offered rather than approximated.
  • An all-zero spectrum answers the middle of the axis, (N−1)·Δ÷2, where MATLAB answers NaN. A spectrum with no power has no half-power point; a finite number is the better thing to hand ten generated cores, and it is the value the ramp form gives with no special case anywhere.
  • The input is expected nonnegative. A power spectral density is, and nothing here checks it – but note that a negative bin makes the cumulative curve non-monotonic, and the inverse of a non-monotonic curve is not well defined. Feed this block something other than a density and the answer means nothing in particular.
  • No state space. The block is not linear in its input at all – it inverts a curve built from it – so it carries none and model reduction correctly declines to merge it.

Code facts#

FactValue
registered typeControl_Systems/Spectral_Measurements/Median_Frequency
familyControl_Systems/Spectral_Measurements
solver environment classICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Median_Frequency
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Median_Frequency/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Median_Frequency.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Median_Frequency/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Median_Frequency.h
default size on canvas140 × 72 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
1inICoreDoublep
2outICoreDoublef

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—
Epsilon1e-18—

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: medfreq() is a MATLAB function and Signal Processing Toolbox ships no Simulink library at all. DSP System Toolbox was searched block by block and carries no half-power measurement. Reported rather than dropped, and it carries no parity testbench

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

Median Frequency -- the half-power point of a power spectral density. THE INVERSE OF A CUMULATIVE CURVE, WRITTEN AS A SUM OF RAMPS. Transcribed from R2026a's medfreq.m: integrate the bins as rectangles, place the borders halfway between neighbouring bin frequencies, and read the frequency at which the running total reaches half the whole. Written as a search that is what it sounds like; written as a sum of clamped ramps it is the same number with a fixed number of operations, no data-dependent index and no branch, which is what lets all ten targets emit one formulation instead of two.

MEASURED AGAINST R2026a rather than asserted, on three spectra chosen to be different KINDS of input rather than three of a kind:

p = [0.12 0.85 2.40 1.10 0.35 0.60 0.18 0.07] at Delta = 0.5 -> 1.1385416666666666 q = eleven bins at Delta = 0.35 -> 1.5900871872630777 p2 = [0 0 3 0 0 1 0 0] at Delta = 0.5, four EMPTY bins -> 1.0833333333333333

This block reproduces all three; the exact values of q are in the block's own description.

⚠ THE THIRD ONE IS THE INTERESTING ONE, AND IT BROKE THE FIRST IMPLEMENTATION. A zero-power bin makes a segment of zero WIDTH, and the natural branch-free clamp -- clamp01(x) spelled (|x| - |x-1| + 1)/2 -- is catastrophically wrong there. The ratio it is handed is enormous, and once |x| passes 2^53 the subtraction |x| - |x-1| rounds to ZERO instead of one, so the clamp answers 1/2 rather than 1. Measured: that spelling answered 1.5833 on p2, where MATLAB answers 1.0833 -- a whole bin and a half out, on a spectrum that is not exotic. Every other test passed.

What this block emits instead never forms a large ratio at all: the NUMERATOR is clamped to the segment before the division, so the quotient is in [0,1] by construction, and a separate step term -- built from the same sign() spelling Zero Crossing Rate uses -- carries the zero-width case. Both are exact in IEEE arithmetic.

📌 A branch-free spelling is not automatically a portable one. The arithmetic has to stay in range as well as stay branch-free.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Median Frequency. 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 26971862e · produced by docsSample --out <folder> --blocks Median_Frequency --steps 60

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