Mean Frequency — Control Systems/Spectral Measurements
Control_Systems/Spectral_Measurements/Mean_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.
Mean Frequency
Control Systems / Spectral Measurements
The first moment of a power spectral density – where its mass
sits on the frequency axis. With bin k at frequency fk =
k·Δ and carrying power Pk = Δ·pk,
the answer is
f = ΣkPk·fk ÷
ΣkPk, taken over the whole spectrum or over one
band. This is the streaming counterpart of MATLAB's meanfreq.
Both weight vectors follow from the parameters alone, so the block is two weighted sums and one division: no branch and nothing carried between samples.
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 512. Bin k is the frequency k·Δ.
- f – the mean frequency, in the same units as Bin Spacing. Always scalar, whatever the input's length.
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.
- Integration Range – which bins the moment is taken over:
- Full spectrum – every bin. This is
meanfreq(Pxx, F), and it is the default. - Frequency band – only the bins inside the band. This is
meanfreq(Pxx, F, [flo fhi]).
- Full spectrum – every bin. This is
- Frequency Band – [flo fhi], a two element vector in the same units as Bin Spacing, read only in Frequency band mode. The band is narrowed to the bins it contains: a bin counts when flo ≤ fk ≤ fhi. See Notes – Band Power snaps the other way.
- Epsilon – ε, added to the total power before the division. It is what makes an all-zero band return 0 instead of a NaN – it is a degeneracy guard, not an accuracy knob, so the default is 1e−30: far below any total power a real spectrum carries, and small enough that the answer matches MATLAB's to the last bit. A larger value biases every answer toward zero by ε÷ΣP.
- 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.
Both weight vectors are structural and are inlined into the arithmetic at export time rather than exposed as tunable parameters – they follow from the bin spacing, the bin count and the band, and changing any of them changes how many multiplies the core contains, which no runtime parameter can do. Re-export after changing them.
The three HDL targets are simulation-only: the block divides,
and a Q16.16 divider is not part of this tree's fixed-point base. They compute
in real arithmetic 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 meanfreq is one of its
MATLAB functions. DSP System Toolbox was searched block by block and carries no
spectral moment. 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.
- The band is narrowed, not widened – and Band Power does the opposite. This block keeps the bins inside the band; Band Power keeps the bins that bracket it. Measured on an 8-bin spectrum at Δ = 0.5 over the band [0.6, 2.9], this block integrates bins 2–5 and Band Power integrates bins 1–6. Both are MATLAB's own rules, on the same PSD, so the two blocks can legitimately report a band's mean frequency and its power over different sets of bins.
- Verified against MATLAB. On that spectrum R2026a answers 1.3156966490299824 over the full range and 1.4044943820224718 over [0.6, 2.9]; this block reproduces both.
- An all-zero band answers 0, where MATLAB answers NaN. That is the one deliberate divergence, and Epsilon is what makes it: the total power is floored rather than tested, because VHDL has no inline conditional in the single expression the ten backends share, and a NaN is the wrong thing to bake into ten cores.
- The input is expected nonnegative. A power spectral density is, and nothing here checks it: a negative bin takes part in both sums like any other, which is the right behaviour for a user taking the first moment of something else.
- No state space. The block divides one linear functional of its input by another, so it is not linear at all and carries none; model reduction correctly declines to merge it.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Spectral_Measurements/Mean_Frequency |
| family | Control_Systems/Spectral_Measurements |
| solver environment class | ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Mean_Frequency |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Mean_Frequency/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Mean_Frequency.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Spectral_Measurements/Mean_Frequency/ICoreBlock_0_Control_Systems_1_Spectral_Measurements_2_Mean_Frequency.h |
| default size on canvas | 132 × 72 px |
| ports at insert | 1 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 | p |
| 2 | out | ICoreDouble | f |
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 |
|---|---|---|
Bin Spacing | 1 | — |
Integration Range | Full spectrum%~%Frequency band~~Full spectrum | — |
Frequency Band | [0 1] | — |
Epsilon | 1e-30 | — |
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 |
Caveat (shown to the user): no Simulink equivalent: meanfreq() 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 spectral moment. 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:
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).
Mean Frequency -- the first moment of a power spectral density, over the whole spectrum or over one frequency band. TWO WEIGHT VECTORS, ONE DIVISION, TEN IDENTICAL BODIES. The moment weights and the mass weights follow from the bin spacing, the bin count and the band alone -- all settled before the run starts -- so both are derived once when the configuration is read and every target inlines the same pair of multiply-accumulates. No branch anywhere, and nothing carried between samples.
TRANSCRIBED FROM R2026a's meanfreq.m, and checked against a run of it rather than inferred. On the 8-bin spectrum
p = [0.12 0.85 2.40 1.10 0.35 0.60 0.18 0.07] at Delta = 0.5
R2026a answers 1.3156966490299824 over the full spectrum and 1.4044943820224718 over the band [0.6, 2.9]. This block reproduces both.
⚠ THE BAND IS SNAPPED INWARD, and Band Power snaps the other way. meanfreq.m selects with
Frange(1) <= F & F <= Frange(2), keeping only the bins INSIDE the band; bandpower.m takes the bins that BRACKET it. On the band above, this block integrates bins 2..5 and Band Power integrates bins 1..6 -- of the same PSD, in the same toolbox.⚠ THE DIVISION IS GUARDED BY AN EPSILON RATHER THAN BY A BRANCH. MATLAB answers NaN on an all-zero band (0/0); a NaN baked into ten cores is the wrong thing to ship, and VHDL has no inline conditional in which to write the test. The epsilon is a parameter, so a core that dropped that floor is distinguishable from one that kept it.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Mean 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 b639d6540 · produced by docsSample --out <folder> --blocks Band_Power Mean_Frequency --steps 60
Sample data: docs/generated/samples/Control_Systems__Spectral_Measurements__Mean_Frequency.json