Generated reference › State Levels — Control Systems/Pulse Metrics
kind: generated#block#control-systems-pulse-metrics

State Levels — Control Systems/Pulse Metrics

Control_Systems/Pulse_Metrics/State_Levels · 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.

State Levels

Control Systems / Pulse Metrics

Estimates the two logic levels of a bilevel waveform from a histogram of the last W samples. The window's smallest and largest samples set the histogram's range; the occupied bins are split in half, and each half yields one level – the centre of its most populated bin, or its count-weighted mean bin centre. This is the streaming counterpart of MATLAB's statelevels.

It is the measurement the rest of this family assumes has already been made: Rise Time, Fall Time, Mid Cross, Pulse Width, Pulse Period, Pulse Separation, Slew Rate, Overshoot and Undershoot all take their two state levels as parameters, because IEEE Std 181-2003 states every threshold as a percentage of the amplitude between them.

Ports

  • u – the bilevel signal. Scalar: the block carries one channel and one window, so several channels need one block each – a shared window would mix them.
  • low – the lower state level, in the signal's own units. Scalar.
  • high – the upper state level, the same. Scalar.

Parameters

  • Window Length – W, how many of the most recent samples the histogram is built from. A whole number from 2 to 48. It must be long enough to hold samples of both states, or the two levels come back from one state's scatter.
  • Number of Bins – NBINS, how finely the window's range is divided. A whole number from 2 to 48. More bins resolve the levels more precisely and put fewer samples in each, so a noisy signal wants fewer. MATLAB's own default is 100, which is for a recorded vector of thousands of samples rather than for a window; the default here is 8. W·NBINS may not exceed 640, because the histogram is unrolled at export as one comparison per sample-and-bin pair.
  • Level Rule – which statistic of each half becomes its level. This selects which arithmetic runs, not a tuning of one:
    • Histogram Mode – the centre of the half's most populated bin. MATLAB's default, and the more robust of the two on a waveform whose states are flat: it ignores everything but the winning bin. A tie goes to the lower bin.
    • Histogram Mean – the half's count-weighted mean bin centre. Uses every sample in the half rather than one bin's worth, so it moves smoothly as the signal drifts and is pulled about by outliers that the mode rule discards.
  • 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 window length, the bin count and the level rule are structural and are inlined at export time rather than exposed as tunable parameters. Re-export after changing any of them.

No target emits a ceiling, floor or rounding call. MATLAB's bin index is a ceiling; it is written here as the pair of comparisons that define one, and the half-way split as the largest bin j with 2j ≤ iLow + iHigh. Both give exactly MATLAB's answer, and it is what lets Structured Text carry this block at all – IEC 61131-3 has no ceiling function.

The three HDL targets are simulation-only: the bin index is a division by a range measured from the data, which is not a Q16.16 operation. They compute in real arithmetic and quantize only at the port boundary, so they simulate correctly and are not offered as synthesizable.

On hardware, prefer the mean rule – and the reason is measured rather than stylistic. A sample arriving on a fixed-point port is quantized to about 1.5×10−5, so a sample sitting that close to a bin boundary can be binned differently there than in software. The mean rule then moves by one bin width divided by that half's sample count, which shrinks as the bin count and window grow; the mode rule moves by a whole number of bin widths, which nothing makes smaller. Both are faithful; only one degrades gracefully.

Simulink bridge

No equivalent (Support::None). Signal Processing Toolbox ships no Simulink library at all, and statelevels is one of its MATLAB functions. The DSP System Toolbox and Simulink libraries were searched by name for state level, settling and histogram: the only match is dspstat3/Histogram, which counts values into bins and estimates no levels from them. 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

  • Stateful. The state is the window – a shift register of W samples, newest first.
  • The window is zero-prefilled and the zeros count. MATLAB is handed a whole recorded vector; a stream has nothing before its first sample. The first W−1 answers therefore measure a window that is part signal and part zeros. This is the same convention Hampel Filter, Detrend and Moving Median carry.
  • The two halves overlap in one bin. The split index is the last bin of the lower half and the first bin of the upper half, so its count is weighed into both levels. That is R2026a's arithmetic, measured: on a five-bin histogram of one count each the mean rule answers 0.3 and 0.7, not 0.3 and 0.75.
  • A flat window returns the sample value twice. Both levels come back equal to the constant, rather than as a division by zero or a NaN: the binning denominator is replaced by eps while the bin width keeps the true range, which is zero.
  • Verified against MATLAB on four windows. A 16-sample two-state window gives 0.045624999999999999 and 0.96437499999999998 at 8 bins under both rules, and 0.012812500000000001 / 0.99718750000000012 under the mode rule at 16 bins where the mean rule gives 0.021015625 for the lower level; a 12-sample window at 7 bins gives −0.25285714285714284 and 0.31285714285714278; six identical samples give the sample value twice; and a five-point ramp at 5 bins gives 0.1 and 0.5 under the mode rule against 0.3 and 0.7 under the mean rule. R2026a answers all of these and this block reproduces them.
  • A sample can round past the top bin, and is then not counted – by MATLAB either. Measured over 200000 random windows, that happens on 10.3% of them at 7 bins and on none at 8 or 16, because a power-of-two bin count scales exactly. It changes which bin is the last occupied one, and so where the histogram is split: on the eight-sample window [0.095 0.408 0.15 0.22 0.30 0.35 0.11 0.40], R2026a counts seven of the eight at 7 bins and all eight at 8, and answers 0.11735714285714285 / 0.29621428571428565 against 0.1145625 / 0.38843749999999999.
  • The answer is a step function of the data. Both levels are bin centres, or averages of them, so a sample that moves between two bins moves the answer by a jump rather than by a rounding. That is what the Code export note above is about, and it is also why two nearly identical signals can be given noticeably different levels.
  • No state space. The block is not linear in its input, so it carries none and model reduction correctly declines to merge it.

Code facts#

FactValue
registered typeControl_Systems/Pulse_Metrics/State_Levels
familyControl_Systems/Pulse_Metrics
solver environment classICoreBlock_0_Control_Systems_1_Pulse_Metrics_2_State_Levels
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Pulse_Metrics/State_Levels/ICoreBlock_0_Control_Systems_1_Pulse_Metrics_2_State_Levels.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Pulse_Metrics/State_Levels/ICoreBlock_0_Control_Systems_1_Pulse_Metrics_2_State_Levels.h
default size on canvas132 × 82 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
1inICoreDoubleu
2outICoreDoublelow
3outICoreDoublehigh

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
Window Length16—
Number of Bins8—
Level RuleHistogram Mode%~%Histogram Mean~~Histogram Mode—

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: statelevels() is a MATLAB function and Signal Processing Toolbox ships no Simulink library at all. The DSP System Toolbox and Simulink libraries were searched by name for 'state level', 'settling' and 'histogram' -- the only match is dspstat3/Histogram, which counts values into bins and estimates no levels from them. Reported rather than dropped, and it carries no parity testbench

Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

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

State Levels -- the two logic levels of a bilevel waveform, from a HISTOGRAM of the last W samples. This is the measurement the other seven Pulse Metrics blocks assume somebody has already made. Each of them takes its two state levels as PARAMETERS, because IEEE Std 181-2003 states every threshold as a percentage of the amplitude between them, and a block reading a stream cannot go back over the signal to guess them. This one makes the guess, one window at a time, so the pair can be wired straight into a threshold rather than typed in by hand.

Transcribed from R2026a's statelevels.m and the two helpers it calls, signal.internal.getHistogram and signal.internal.getLevelsByHistogram, and then MEASURED against them. Every number below is R2026a's, reproduced here to the last bit:

w1 = [0.02 -0.01 0.03 0.98 1.02 0.99 0.05 0.00 -0.02 1.01 0.97 1.03 0.01 0.04 0.99 1.00] 8 bins, mode -> 0.045624999999999999 0.96437499999999998 8 bins, mean -> 0.045624999999999999 0.96437499999999998 16 bins, mode -> 0.012812500000000001 0.99718750000000012 16 bins, mean -> 0.021015625 0.99718750000000012 5 bins, mode -> 0.085000000000000006 0.92500000000000004 w2 = [-0.29 -0.28 0.36 0.35 -0.27 0.34 0.36 -0.29 -0.30 0.33 0.36 0.35] 7 bins, mode -> -0.25285714285714284 0.31285714285714278 7 bins, mean -> -0.25285714285714284 0.31285714285714289 w3 = six identical samples, all 1 4 bins, both -> 1 1 w4 = [0 0.25 0.5 0.75 1], one count per bin 5 bins, mode -> 0.10000000000000001 0.5 5 bins, mean -> 0.29999999999999999 0.70000000000000007 w5 = [0.095 0.408 0.15 0.22 0.30 0.35 0.11 0.40], whose TOP SAMPLE IS DROPPED at 7 bins 7 bins, mode -> 0.11735714285714285 0.29621428571428565 7 bins, mean -> 0.15089285714285713 0.34092857142857136 8 bins, mode -> 0.1145625 0.38843749999999999

The last three rows are there because each pins a rule that a paraphrase gets wrong:

⚠ THE TWO HALVES OVERLAP IN ONE BIN. The histogram between its first and last occupied bin is split at iLow + floor((iHigh-iLow)/2), and that index is the LAST bin of the lower half AND the FIRST bin of the upper half. On w4 it is bin 3, whose single count is therefore weighed into both levels -- which is why the mean rule answers 0.3 and 0.7 there and not 0.3 and 0.75. A reader who splits the range cleanly in two gets a different number on every histogram with an odd occupied span.

Sample results#

State Levels — Step: 0 -> 1 at t = 1 sState Levels — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0out ICoreDouble-Out-0out ICoreDouble-Out-1

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)0 … 0.0625
rampRamp: slope 1 from t = 00 … 4.394
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.9376 … 0.2549
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-1.875 … 0.1875

Plotted: step — Step: 0 -> 1 at t = 1 s

Category dynamic · sample time 0.1 · 60 steps · commit 1ab967922b203d9f7355122e1907864296a419be · produced by docsSample --out <folder> --blocks State_Levels --steps 60 · data docs/generated/samples/Control_Systems__Pulse_Metrics__State_Levels.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).