Generated reference › Order Waveform — Control Systems/Vibration
kind: generated#block#control-systems-vibration

Order Waveform — Control Systems/Vibration

Control_Systems/Vibration/Order_Waveform · 2 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.

Order Waveform

Control Systems / Vibration

The time-domain waveform of one or more shaft orders – MATLAB's orderwaveform, the Vold-Kalman tracking filter – over a running window of the last W samples. An order is the component of a vibration whose frequency follows the shaft: order k rides at k·rpm÷60 hertz, so it sweeps as the machine runs up and a fixed filter cannot follow it. The filter finds, over the window, the complex envelope X that makes 2·Re(X·ejθ) closest to the signal while keeping X smooth – a least-squares problem in which the phase θ[n] = (2πk÷60fs)·Σrpm comes from the speed port and the smoothness weight comes from the bandwidth. The waveform is published for the window's centre sample.

Ports

  • x – the sampled vibration signal, scalar: one channel and its own window.
  • rpm – the shaft speed at the same instant, in revolutions per minute, scalar. Any speed profile is allowed; it is the sample-by-sample phase that the filter tracks.
  • xr – the extracted waveforms, [K, 1] with one row per entry of Order List, in the signal's own units. Row k is the value at the sample (W−1)÷2 ticks ago, not at this tick.

Parameters

  • Order List – the orders to extract, a vector of up to eight positive numbers; they need not be whole (a 0.5 order is a half-shaft rattle). Defaults to [1 2]. K is its length and sets the output height.
  • Bandwidth (Hz) – how fast the extracted envelope is allowed to change, read as the filter's smoothness weight exactly as MATLAB reads it: r = (1.58·fs÷2πbw)2 at filter order 1 and (1.7·fs÷2πbw)3 at order 2. A narrow bandwidth rejects neighbouring orders and follows a run-up slowly; a wide one does the opposite. Positive; defaults to 40. See the Notes for how it must be sized against the window.
  • Window Length – W, the record the filter solves over: an ODD whole number from 17 to 513, odd so that the window has a centre. Defaults to 129. Every generated core carries W-sized arrays and W sine-cosine pairs per order per sample, which is what the upper limit is about.
  • Sample Rate (Hz) – fs, the rate the two signals were sampled at: the bandwidth and the order frequencies are in hertz through it. Positive; defaults to 1000.
  • Filter Order – the structural equation, 1 or 2: 1 keeps the envelope's second difference small, 2 its third difference. Order 2 follows a curved amplitude more closely at the price of a worse-conditioned solve. Defaults to 1, which is MATLAB's.
  • 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 least-squares matrix does not contain the data, so it is solved ONCE at export time and the exported core carries its W solution weights as numbers; each sample is then the window's cumulative speed, one sine-cosine pair per sample per order, and one accumulation. All five settings are structural, so re-export after changing any of them.

⚠ The three HDL targets run those loops in simulation-only real arithmetic, quantizing only at the port boundaries: a Q16.16 datapath carries neither the sine and cosine of an accumulated phase nor a window of a thousand samples. They are not offered as synthesizable.

Simulink bridge

None (Support::None). orderwaveform is a Signal Processing Toolbox function and that toolbox ships no Simulink library, so there is no path a diagram could name; 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, and discrete by nature (setDiscreteOnlyBlock(true)): two shift registers of W samples, zero at the start of the run, so the first W−1 samples of a run are a window that is still filling.
  • ⚠ The output lags by (W−1)÷2 samples – 64 at the default window. The least-squares envelope is unconstrained at the edge of its own record, so the window's newest sample is not a usable estimate: measured against the whole-record answer on a 600 to 1800 rpm sweep, the window's centre converges to it (9.0e−4 at (W−1)·bw÷fs = 5.1, 7.0e−7 at 10.2) while its newest sample stays at 1.0 to 2.4 on a true amplitude of 1.4 whatever the window length. The block reads the centre for that reason and states the latency rather than hiding it.
  • ⚠ Size the window against the bandwidth. The agreement above is governed by (W−1)·bw÷fs: about 1e−3 at 5, 1e−6 at 10, 1e−12 at 20 – so a narrow bandwidth needs a long window, and W < 5·fs÷bw is a window that cannot hold the filter's own response. The defaults sit at 5.1.
  • ⚠ This is the whole-record filter applied to a window, and MATLAB's own answer carries a solver tolerance. orderwaveform solves by preconditioned conjugate gradients at a relative residual of 1e−3; this block solves exactly, by a banded Cholesky. On identical windows the two differ by 1.2e−6 to 1.5e−4 for that reason alone.
  • Orders are extracted independently of one another, which is orderwaveform's default (Decouple false). The coupled solve, which separates orders that cross, needs a K·W system whose matrix DOES contain the data, so it is not offered here.
  • An order whose frequency passes fs÷2 aliases, exactly as it would in MATLAB, which refuses such an order list outright; the speed arrives on a port here, so it cannot be checked at configuration time.
  • Not Order Track: that block publishes the same filter's AMPLITUDE against time, in rms, peak or power units.

Code facts#

FactValue
registered typeControl_Systems/Vibration/Order_Waveform
familyControl_Systems/Vibration
solver environment classICoreBlock_0_Control_Systems_1_Vibration_2_Order_Waveform
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Order_Waveform/ICoreBlock_0_Control_Systems_1_Vibration_2_Order_Waveform.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Order_Waveform/ICoreBlock_0_Control_Systems_1_Vibration_2_Order_Waveform.h
default size on canvas140 × 76 px
ports at insert2 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublex
2inICoreDoublerpm
3outICoreDoublexr

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
Order List[1 2]not crossed
Bandwidth (Hz)40not crossed
Window Length129not crossed
Sample Rate (Hz)1000not crossed
Filter Order1not crossed

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
deliberately not crossedOrder List, Bandwidth (Hz), Window Length, Sample Rate (Hz), Filter Order

Caveat (shown to the user): orderwaveform is a Signal Processing Toolbox function and that toolbox ships no Simulink library, so there is no path a diagram could name; the Vold-Kalman order filter has no counterpart in any shipped block library

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

Order Waveform -- MATLAB's orderwaveform (the Vold-Kalman filter) over a running window Over the last W samples of the signal x and of the shaft speed rpm, both oldest first, with the phase the speed implies,

theta[n] = (2 pi order / (60 fs)) * SUM(k <= n) rpm[k]

the Vold-Kalman filter finds the complex envelope X that minimises

|| x - Re(2 X e^{j theta}) ||^2 subject to a smooth envelope, r^2 || S X ||^2 small,

where S is the second difference [1 -2 1] at filter order 1 and the third difference [1 -3 3 -1] at filter order 2, and r is the bandwidth read as a weight, (1.58 fs / (2 pi bw))^2 or (1.7 fs / (2 pi bw))^3. The published waveform is the real part 2 Re(X e^{j theta}) at the WINDOW'S CENTRE.

⚠ THE MATRIX IS A CONSTANT OF THE CONFIGURATION, so the solve is done ONCE. The normal equations are (r^2 S'S + I) X = conj(e^{j theta}) . x, and with the orders uncoupled -- orderwaveform's default, 'Decouple' false -- the matrix does not contain the data at all. The block therefore solves A g = e_centre once, by a banded Cholesky, and every tick is SUM g[n] x[n] cos(theta[centre] - theta[n]) and its sine twin: W multiplies and W sine-cosine pairs per order, no linear algebra in any generated core.

⚠ EVERY NUMBER BELOW WAS MEASURED AGAINST R2026a, not read off a page:

  • THE WINDOWED SOLVE IS MATLAB'S SOLVE, on the same window: against

signal.internal.vk (the function orderwaveform itself calls) driven to a tight tolerance over W = 33 and 129, bandwidths 20/40/80 Hz and both filter orders, the largest disagreement is 3.2e-14 at filter order 1 and 2.1e-8 at filter order 2, where the matrix is conditioned by r^2 with r cubed.

  • ⚠ MATLAB'S OWN DEFAULT IS FURTHER FROM EXACT THAN THIS BLOCK IS. orderwaveform solves

by preconditioned conjugate gradients at a relative-residual tolerance of 1e-3, and on the same windows its answer sits 1.2e-6 to 1.5e-4 from the exact least-squares solution. A user comparing the two should expect to meet that difference, and it is MATLAB's solver setting rather than a disagreement about the filter.

  • THE CENTRE IS THE ONLY HONEST READ POINT. Against the whole-record solve on a 4 s

sweep from 600 to 1800 rpm, the window's centre converges as the window grows -- 9.0e-4 at (W-1)*bw/fs = 5.1, 7.0e-7 at 10.2, 7.0e-13 at 20.5 (order 1) -- while the window's NEWEST sample never does: it sits at 1.0 to 2.4 against a true amplitude of 1.4, at every window length tried, because the least-squares envelope is unconstrained at the record's own edge. That is what buys the (W-1)/2 samples of latency.

Sample results#

Order Waveform — Step: 0 -> 1 at t = 1 sOrder Waveform — Step: 0 -> 1 at t = 1 s00.51012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [2x1] entry 0

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)-0.004844 … 0.04861
rampRamp: slope 1 from t = 0-0.09239 … 0.07829
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-0.03578 … 0.3583
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-0.1267 … 0.005774

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

Category dynamic · sample time 0.1 · 60 steps · commit 6b0471a23bd6163d7d7f33f764df08a614c2b6b8 · produced by docsSample --out <folder> --blocks Scalar_Root_Find Scalar_Bounded_Minimization Order_Waveform Order_Track RPM_Frequency_Map RPM_Order_Map --steps 60 · data docs/generated/samples/Control_Systems__Vibration__Order_Waveform.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).