Order Spectrum — Control Systems/Vibration
Control_Systems/Vibration/Order_Spectrum · 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 Spectrum
Control Systems / Vibration
The order spectrum of a rotating machine – MATLAB's
orderspectrum over the frames completed so far. A component of a
machine sits at a fixed order of its shaft (a multiple of the rotation
rate), so it smears across an ordinary spectrum whenever the speed moves.
This block measures the signal against shaft angle instead of time: it
interpolates the vibration onto a constant-angle grid using the tachometer,
transforms every frame of that grid through a window, and publishes the
root-mean-square over the frames so far, order by order.
Ports
- x – the vibration, a scalar stream.
- rpm – the shaft speed at the same instant, a scalar stream in revolutions per minute. It is what turns time into angle: the block integrates it (trapezoid by trapezoid) to get shaft revolutions.
- spec – the order spectrum, a column of nfft/8 + 2 entries, where nfft = max(256, Window Length). Entry m is order m·Omax/(nfft/8), the last one just past Omax = fs/(2·Maximum RPM/60), which is the highest order the sample rate can carry.
Parameters
- Maximum RPM – the highest shaft speed the run will reach. It sets
Omax, the angle grid (8·Omax samples per
revolution) and the order axis. ⚠ MATLAB takes this from the record
(
max(rpm)), which a stream has not seen; the block isorderspectrumexactly when this value is the run's maximum. A speed above 3.75× it is clamped, because past that a fifteenth of a sample would owe more than one angle sample. - Sample Rate (Hz) – fs, the rate the two streams arrive at.
- Window Length – L, the frame length in angle samples, 4 to 1024. It sets the order resolution, ENBW(window)·8·Omax/L. MATLAB's own default resolution picks 967 for a flat top window (385 for Hann, 350 for Hamming, 256 for rectangular) whatever the speed and rate, which is why 967 is this block's default.
- Window – the taper on each frame: Flat Top
(
rpmordermap's default, and this block's), Hann, Hamming or Rectangular. Each is divided by its own sum first, asrpmordermapdoes, so a sinusoid's amplitude is read off directly. - Overlap Percent – how much of a frame the next one repeats, 0 to 99; the hop is L − min(ceil(percent·L/100), L−1). 50 is MATLAB's default and this block's.
- Amplitude – what an entry means.
- RMS – the root mean square of the frames' magnitudes;
orderspectrum's default and this block's. - Peak – the same, scaled by √2 so a sinusoid reads its amplitude.
- Power – the mean of the squared magnitudes, not its root.
- RMS – the root mean square of the frames' magnitudes;
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
What it does per sample
Every input sample is interpolated to 15 points by a 301-tap zero-phase
filter – MATLAB's resample(x, 15, 1), which reads 10
samples ahead, so the block runs 10 samples behind the input. The tachometer is
interpolated the same way and integrated into revolutions; whenever the shaft
passes the next grid angle, one angle sample is interpolated and pushed into the
frame. A completed frame is windowed, transformed at nfft and accumulated;
the published spectrum is the running root-mean-square, and it holds
between frames. Before the first complete frame it is all zeros.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The 301 interpolation taps and every constant are computed at export time; the windows and the transform's sines and cosines are computed in the emitted core, which keeps the emitted file small whatever the frame length. Every loop has a fixed bound – 15 upsampled points per sample, at most one angle sample each, at most one frame each – so the core's worst case per sample is known at export time. Nothing is a tunable parameter: every setting changes the grid, the window or the accumulators.
The three HDL targets are simulation-only: they carry the
arithmetic in real and quantize only at the port boundary. An angular
resampler divides by a run-time phase increment and a spectrum spans several
decades, neither of which belongs in a Q16.16 datapath. VHDL runs the whole sample
in an emitted function over a record of state, because a clocked process
has three scratch variables and this needs arrays.
Simulink bridge
No equivalent (Support::None), so nothing crosses in either
direction and no parity testbench is owed. orderspectrum and
rpmordermap are Signal Processing Toolbox functions, that
toolbox ships no Simulink library, and no library block resamples a signal onto
shaft angle. Code export verification still covers the block across all ten
languages.
Notes
- Stateful and inherently discrete
(
setDiscreteOnlyBlock(true)): an input delay line, a tachometer delay line, the phase, the angle-domain frame and one accumulator per order, all advancing once per sample. Its period comes from its own "Sampling Time (s)", or the model's global sampling time when that is zero or less. - It runs 10 samples behind, because the interpolation reads that far
ahead. That is
resample's own filter, not an approximation of it. - Three departures from the batch function, all of them stated above:
Maximum RPM is a parameter rather than the record's maximum; the answer is
the spectrum of the frames completed so far, so it is a running estimate
rather than one answer at the end; and the frames MATLAB builds out of a record's
last ten samples – where its own resampling pads with zeros – are
frames a stream never reaches. Measured on a 600-sample run-up (1200 to 3000 rpm,
fs = 1000): every frame's order map agrees with
rpmordermapto 1.0×10−14, the running spectrum over the same frames to 1.1×10−15, and the whole-record answers differ by 0.38–0.60 % where the stream is 1 to 5 frames short of MATLAB's count – and by 1.1×10−15 where it is not. - ⚠ "Maximum RPM" is not a formality. On that same run – whose speed peaks at 2942.6 rpm – setting the parameter to a round 3000 instead moved the answer by 3.5 % to 24 %, because it is what sets the angle grid and the order axis. Give it the run's maximum, not a nameplate figure.
- An order spectrum needs a run-up: at a constant speed it is a frequency spectrum with a relabelled axis. It is the speed CHANGING that separates a shaft-order component from a fixed-frequency one.
- No state space. An angular resampler followed by a magnitude spectrum is not linear.
- Related blocks. Vibration / Time-Synchronous Average sharpens what is synchronous with the shaft in the time domain and makes the same substitution for the period; Spectral Measurements / Welch PSD is the fixed-frequency counterpart of this measurement.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Vibration/Order_Spectrum |
| family | Control_Systems/Vibration |
| solver environment class | ICoreBlock_0_Control_Systems_1_Vibration_2_Order_Spectrum |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Order_Spectrum/ICoreBlock_0_Control_Systems_1_Vibration_2_Order_Spectrum.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Order_Spectrum/ICoreBlock_0_Control_Systems_1_Vibration_2_Order_Spectrum.h |
| default size on canvas | 150 × 86 px |
| ports at insert | 2 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 | x |
| 2 | in | ICoreDouble | rpm |
| 3 | out | ICoreDouble | spec |
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 |
|---|---|---|
Maximum RPM | 3000 | — |
Sample Rate (Hz) | 1000 | — |
Window Length | 967 | — |
Window | Flat Top%~%Hann%~%Hamming%~%Rectangular~~Flat Top | — |
Overlap Percent | 50 | — |
Amplitude | RMS%~%Peak%~%Power~~RMS | — |
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. orderspectrum and rpmordermap are Signal Processing Toolbox MATLAB functions, not blocks; that toolbox ships no Simulink library, and no library block resamples a signal onto shaft angle from a tachometer
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 Spectrum -- MATLAB's orderspectrum(rpmordermap(x, fs, rpm, ...)) as a streaming block A component of a rotating machine sits at a fixed ORDER of the shaft -- a multiple of its rotation rate -- and therefore SMEARS across a frequency spectrum whenever the speed moves. The order spectrum removes that by measuring the signal against SHAFT ANGLE instead of time:
Omax = fs / (2 . maxrpm/60) the highest order the sample rate can carry fsp = 4 . (2 . Omax) samples per revolution of the angle grid xu = resample(x, 15, 1) a 301-tap zero-phase interpolation, 10 samples of lookahead -- the block's only latency phase = cumtrapz(rpmUp / (60 . 15 . fs)) revolutions, trapezoid by trapezoid xp(k) = interp1(phase, xu, k/fsp) the signal on a CONSTANT-ANGLE grid frame j = xp(j.hop .. j.hop+L-1), windowed, transformed at nfft = max(256, L) map(m, j) = |X| . (sqrt2 on every bin but DC and Nyquist) . (sqrt2 again for 'peak') spectrum(m) = sqrt( mean_j map(m, j)^2 ) 'power': mean_j map(m, j)
and the orders kept are those at most Omax, plus one, which is nfft/8 + 2 of them.
⚠ EVERY LINE OF THAT WAS READ OUT OF R2026a's OWN SOURCES AND THEN MEASURED AGAINST THEM. orderspectrum.m calls rpmordermap, which is private/rpmmap.m: toConstantSamplesPerCycle does the 15x resample, the linear interpolation of the tachometer, the cumulative trapezoid and the constant-angle interp1; the window is normalised by its own sum; nOverlap is ceil(op/100 . L) capped at L-1; nfft is max(256, length(win)); and the amplitude scaling is rpmmap's mapAmplitudeScale. A Python transcription of the statements below -- the block's own filter taps, windows, per-frame twiddles and accumulators -- was run against a 600-sample run-up (1200 to 3000 rpm with a wobble, fs = 1000) in four configurations:
hann L 64 rms 51 frames map worst 5.4e-15 running spectrum vs MATLAB's own flattop L 967 rms 2 frames map worst 1.5e-15 map over the SAME frames: 2.2e-16, hamming L 40 peak 82 frames map worst 1.0e-14 1.1e-15, 2.2e-16, 5.6e-16 rectwin L 32 power 206 frames map worst 8.0e-15
⚠ THE ONE PLACE A STREAM CANNOT BE THE BATCH FUNCTION IS THE END OF THE RECORD, and it is measured rather than waved at.
resamplereads ten input samples PAST the sample it is interpolating, so the stream runs ten samples behind and the frames MATLAB builds out of a record's last ten samples (where its own resample pads with zeros) are frames this block has not reached. Over the run above that is 1 to 5 frames of 52, 84 and 211, and the whole-record answers differ by 0.38 % to 0.60 %; where the stream does reach the last frame -- the flattop case, 2 frames of 2 -- the two agree to 1.1e-15. Against MATLAB's own map over the frames the block HAS completed, the agreement is 1e-15 in every configuration.
Sample results#
| t | in ICoreDouble-Out-0 | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 [122x1] entry 0 |
|---|---|---|---|
| 0 | -2 | -2 | [0, 0, 0, 0]… |
| 0.4 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 0.8 | -2 | -2 | [0, 0, 0, 0]… |
| 1.2 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 1.6 | -2 | -2 | [0, 0, 0, 0]… |
| 2 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 2.4 | -2 | -2 | [0, 0, 0, 0]… |
| 2.8 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 3.2 | -2 | -2 | [0, 0, 0, 0]… |
| 3.6 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 4 | -2 | -2 | [0, 0, 0, 0]… |
| 4.4 | 0.5 | 0.5 | [0, 0, 0, 0]… |
| 4.8 | -2 | -2 | [0, 0, 0, 0]… |
| 5.2 | 0.5 | 0.5 | [0, 0, 0, 0]… |
Every 4th of 60 samples, from the table stimulus.
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 0 … 0 |
ramp | Ramp: slope 1 from t = 0 | 0 … 0 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 0 |
step | Step: 0 -> 1 at t = 1 s | 0 … 0 |
Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample
Category static · sample time 0.1 · 60 steps · commit 23d8841c6561ca4bb64cd9b5b64da9638de12629 · produced by docsSample --out <folder> --blocks Fixed_Wing_Point_Mass Kernel_Classifier_Predictor Kernel_Regression_Predictor Rotor Rotor_With_Flap_Effects Multirotor Multirotor_With_Flap_Effects Dynamic_Inflow_3_State Kurtogram Empirical_Mode_Decomposition Modal_FRF Order_Spectrum --steps 60 · data docs/generated/samples/Control_Systems__Vibration__Order_Spectrum.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).