Peak Finder — Control Systems/Signal Measurements
Control_Systems/Signal_Measurements/Peak_Finder · 1 input / 4 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, 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.
Peak Finder
Control Systems / Signal Measurements
Finds the local maxima and minima of the frame on its input and reports the first K of them, in index order. An interior sample x[i] is a
- maximum when x[i] − x[i−1] > T and x[i] − x[i+1] > T,
- minimum when x[i−1] − x[i] > T and x[i+1] − x[i] > T,
with T the threshold when Ignore Peaks Within Threshold is on and 0 when it is off. Both comparisons are strict, so a plateau is never a peak, and the first and last samples never are, having one neighbour each.
Ports
- x – the frame, an [N,1] column with N from 1 to 64. One channel: a multi-column input is refused rather than read column by column.
- cnt (
u32,ICoreUInt32) – how many peaks were reported, [1,1], never more than K. - idx (
u32,ICoreUInt32) – their positions in the frame, [K,1], counted from 0 or from 1 per Index Base. Slots past cnt hold 0. - val – their values, [K,1]; slots past cnt hold 0.
- max (
bool,ICoreBool) – true where the peak is a maximum, false where it is a minimum, [K,1]; slots past cnt are false. This is the port that selects maxima or minima downstream.
Parameters
- Index Base – Zero (the first sample is index 0) or One.
- Maximum Number of Peaks – K, 1 to 16: the length of the three vector outputs. When a frame has more peaks than this, the first K in index order are reported, not the largest.
- Ignore Peaks Within Threshold – off or on. On, a point counts only when it stands more than Threshold clear of both neighbours.
- Threshold – T, read only when the switch above is on.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Code export
Seven targets: Python, MATLAB, Java, Rust, C, C++ and PLC Structured Text. Every target subtracts first and compares second, as Simulink does – at T = 0.3, 2 − 1.7 is 0.30000000000000004 and clears the threshold, where the algebraically equal x[i] > x[i−1] + T would not.
VHDL, Verilog and SystemVerilog are not applicable: the cnt and idx outputs are unsigned 32-bit integers, which the HDL targets' Q16.16 carrier cannot hold exactly past 32767, so an export to one of them stops and names the port rather than emitting a core that would agree over part of the range. PLC Structured Text unrolls the search over the frame, which is why N is bounded.
Simulink bridge
Import and export, mapped to DSP System Toolbox's
dspsigops/Peak Finder. Index Base →
indexBase, Maximum Number of Peaks →
maxPeaks, Ignore Peaks Within Threshold →
NoiseDistinguish and Threshold → thresh, all
one to one. Three parameters are fixed: polarity at Maxima and
Minima and outputIdx / outputVal at on
– choosing Maxima or Minima alone, or switching an output off, removes a
Simulink port this block has, so such a block is reported on import rather than
brought in with the wrong ports. The Simulink block defines no
SampleTime, so a positive Sampling Time (s) stays on this side
and is reported.
Notes
- Algebraic and stateless: every output depends on this frame alone.
- Verified against R2026a: [1 3 2 5 4 4 6 1] gives count 4, indices [1 2 3 6], values [3 2 5 6] and is-maximum [true false true true]; the plateau [5 4 4 4 6 2 2 3] gives the one peak 6.
- The count and index outputs are unsigned 32-bit integers and the flag is a boolean, matching the Simulink block's output types.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Measurements/Peak_Finder |
| family | Control_Systems/Signal_Measurements |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Measurements_2_Peak_Finder |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Measurements/Peak_Finder/ICoreBlock_0_Control_Systems_1_Signal_Measurements_2_Peak_Finder.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Measurements/Peak_Finder/ICoreBlock_0_Control_Systems_1_Signal_Measurements_2_Peak_Finder.h |
| default size on canvas | 130 × 100 px |
| ports at insert | 1 in, 4 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | x |
| 2 | out | ICoreUInt32 | cnt |
| 3 | out | ICoreUInt32 | idx |
| 4 | out | ICoreDouble | val |
| 5 | out | ICoreBool | max |
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 |
|---|---|---|
Index Base | Zero%~%One~~Zero | indexBase |
Maximum Number of Peaks | 10 | maxPeaks |
Ignore Peaks Within Threshold | off%~%on~~off | NoiseDistinguish |
Threshold | 0 | thresh |
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::Both |
| Simulink path | dspsigops/Peak Finder |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| always set | polarity = Maxima and Minima, outputIdx = on, outputVal = on |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Index Base | indexBase | Zero → Zero, One → One |
Maximum Number of Peaks | maxPeaks | passes through |
Ignore Peaks Within Threshold | NoiseDistinguish | off → off, on → on |
Threshold | thresh | passes through |
Caveat (shown to the user): x is the one input; cnt, idx, val and max are Simulink's four outputs in order. polarity is fixed at 'Maxima and Minima' and outputIdx / outputVal at 'on': any other choice removes a Simulink port this block has, so such a block is reported on import. The fixed-point rounding and overflow settings do not apply to a double frame. The Simulink block defines no SampleTime, so the rate stays on the ICore side
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:
B0no sample under docs/generated/samples/ — nothing to cross-check (P8.1)
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).
Peak Finder -- the local maxima and minima of a frame, dspsigops/Peak Finder maximum at i: x[i] - x[i-1] > T and x[i] - x[i+1] > T minimum at i: x[i-1] - x[i] > T and x[i+1] - x[i] > T 1 <= i <= N-2
T is the threshold when "Ignore Peaks Within Threshold" is on, 0 when it is off. The first maxPeaks found in index order are reported -- count, indices, values, is-maximum -- and the unused slots are zero.
MEASURED AGAINST R2026a, eight frames and six threshold cases, and every rule below was read off a simulation rather than the help page:
- [1 3 2 5 4 4 6 1] -> count 4, indices [1 2 3 6] (zero-based), values [3 2 5 6], is-max
[1 0 1 1]: the ENDPOINTS are never peaks, and the plateau 4 4 is neither a maximum nor a minimum -- both neighbour comparisons are STRICT.
- the same frame at maxPeaks = 2 -> [1 2]: the FIRST two in index order, not the largest.
- [5 4 4 4 6 2 2 3] -> one peak (6 at index 4); the plateaus 4 4 4 and 2 2 are not minima.
- threshold: a point is kept when BOTH neighbour differences exceed T strictly. At T = 0.5 a
difference of exactly 0.5 drops the point; at T = 0.3, 2 - 1.7 = 0.30000000000000004 keeps it -- so the test is a DIFFERENCE compared with T, not x[i] > x[i-1] + T, which would have dropped it (2 > 2.0 is false). Every backend subtracts first.
- index base One adds one to every index; the unused slots stay 0 either way.
⚠ ONE ARRANGEMENT ONLY: Peak Type "Maxima and Minima" with the index and value outputs on. Measured: Maxima or Minima alone drops the is-maximum port (4 -> 3 outputs), and the two output switches drop their ports. The bridge has no way to say that a parameter moves a port, so those three are fixed parameters and the block has all four outputs.
Sample results#
No sample run is committed for this block. Samples come from the headless harness (DOCS_PLAN.md P8.1) into docs/generated/samples/; until one exists this block's behaviour is witnessed by the parity and export-verification suites, not by a plot here.