Envelope Spectrum — Control Systems/Vibration
Control_Systems/Vibration/Envelope_Spectrum · 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.
Envelope Spectrum
Control Systems / Vibration
The envelope spectrum of the signal – MATLAB's
envspectrum – over a running window of the last N samples: the
bearing-fault analysis. A defect struck once per revolution of a ball or race
rings the structure at a high frequency; the envelope of that ringing repeats at
the defect's own rate, and its spectrum shows that rate as a line with harmonics
where the raw spectrum shows a smear.
xc = x − mean(x); then the band [f1, f2] is isolated either by complex demodulation – z = 2·(xc·e−j2πf0n/fs) filtered by a lowpass of cutoff (f2−f1)/2, with f0 = (f1+f2)/2 – or by a bandpass and the analytic signal; then env = |z| − mean(|z|) and ES(f) = c(f)·|DFT(env)(f)| ÷ N, with c = 1 at DC and Nyquist and 2 between. Both filters are fir1 designs (Hamming window), and the filtering is MATLAB's conv2(·, b, 'same') over the window.
Ports
- u – the sampled vibration signal. Scalar: one channel and its own window.
- es – the envelope spectrum, [N/2+1, 1], one-sided with DC first and Nyquist last; bin k is at k·fs/N hertz. An AMPLITUDE spectrum, in the signal's own units – not a density.
Parameters
- Record Length – N, the window and transform length. An even whole number from 4 (envspectrum's own floor) to 128. Defaults to 32.
- Sample Rate (Hz) – fs, the rate the signal was sampled at: the band, the demodulating frequency and the output bins are all in hertz through it. Positive. Defaults to 1000.
- Frequency Band – [f1 f2] in hertz, the band where the fault's impacts ring. 0 ≤ f1 < f2 < fs/2, and f1 above 0 for the Hilbert method, whose bandpass needs two edges. envspectrum's default is [fs/4, 3fs/8]; this block's default of [250 375] is exactly that at the default rate.
- Method – how the band is isolated:
- Demodulation – envspectrum's default: shift the band's centre to zero frequency and lowpass it.
- Hilbert – bandpass it and take the analytic signal.
- Filter Order – the order of the fir1 filter, a whole number from 1 to 256; envspectrum's default is 50, which is this block'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 filter, the demodulating phases, the transform's twiddles and the scales are computed once at export time and carried as numbers; the convolution, the analytic signal, the two magnitudes and the spectrum run as loops in the core. 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 two port boundaries: the two magnitudes are square roots, which a Q16.16 datapath does not carry. They are not offered as synthesizable.
Simulink bridge
None (Support::None). envspectrum is a Signal Processing
Toolbox function and that toolbox ships no Simulink library, and a search of 119
block libraries found no envelope-spectrum or bearing-analysis block. 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)): one shift register of N samples, zero at the start of the run. - ⚠ The window is its own record. The demodulating phase restarts at every window and the filter's zero-padding sits at the window's two ends, exactly as envspectrum treats a record of N samples; so this is envspectrum of the last N samples, not a filter run continuously over the stream. A filter order comparable to N makes those ends a large part of the window, as it does in MATLAB.
- Not Envelope Detector: that block follows the envelope sample by sample and publishes it; this one publishes the envelope's SPECTRUM, which is where a fault's rate is read.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Vibration/Envelope_Spectrum |
| family | Control_Systems/Vibration |
| solver environment class | ICoreBlock_0_Control_Systems_1_Vibration_2_Envelope_Spectrum |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Envelope_Spectrum/ICoreBlock_0_Control_Systems_1_Vibration_2_Envelope_Spectrum.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Vibration/Envelope_Spectrum/ICoreBlock_0_Control_Systems_1_Vibration_2_Envelope_Spectrum.h |
| default size on canvas | 140 × 76 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 | u |
| 2 | out | ICoreDouble | es |
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 |
|---|---|---|
Record Length | 32 | not crossed |
Sample Rate (Hz) | 1000 | not crossed |
Frequency Band | [250 375] | not crossed |
Method | Demodulation%~%Hilbert~~Demodulation | not crossed |
Filter Order | 50 | not 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.
Simulink bridge#
| support | Support::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| deliberately not crossed | Record Length, Sample Rate (Hz), Frequency Band, Method, Filter Order |
Caveat (shown to the user): envspectrum is a Signal Processing Toolbox function and that toolbox ships no Simulink library; a search of 119 block libraries (dsp, dsphdl, signal, simulink, hdlcoder, comm, audio, soc) found no envelope-spectrum or bearing-analysis block, so there is no path a diagram could name
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).
Envelope Spectrum -- MATLAB's envspectrum over a running window Over the last N samples x[0..N-1] (oldest first) at sample rate fs, with the band [f1, f2]:
xc = x - mean(x) demod: z = 2 * ( xc .* exp(-j 2 pi f0 n / fs) ) () b_low f0 = (f1 + f2)/2, b_low = fir1(order, (f2-f1)/2 / (fs/2)) hilbert: z = analytic( xc () b_band ) b_band = fir1(order, [f1 f2] / (fs/2)) env = |z| - mean(|z|) ES(f) = c(f) * |DFT(env)(f)| / N, c = 1 at DC and Nyquist, 2 between
where (*) is MATLAB's conv2(., b, 'same') -- the central N samples of the full convolution -- and analytic() is hilbert's: the DFT, weights 1, 2, ..., 2, 1 on bins 0..N/2 and 0 above, and the inverse DFT.
⚠ EVERY STEP WAS READ OUT OF R2026a's envspectrum.m AND THEN MEASURED, by a prototype that runs this block's loops -- the same-convolution index, the demodulation, the analytic signal by explicit DFT, the envelope, the spectrum -- against envspectrum over N = 8..64, filter orders 3..50 (odd and even), both methods: largest disagreement 8.5e-15 relative. What that pinned, each one a silent wrong answer if guessed:
- 'same' TAKES THE FULL CONVOLUTION FROM INDEX ceil(order/2): output i is SUM_j b[j] x[i +
ceil(order/2) - j]. floor(order/2) is right for an even order and 1.5 % wrong at order 17.
- THE TIME AXIS STARTS AT ZERO ON THE WINDOW'S OLDEST SAMPLE, so the demodulating phase is
2 pi f0 n / fs from n = 0 -- the window is its own record, as envspectrum sees one.
- THE DEFAULTS ARE 'demod', A BAND OF [fs/4, 3 fs/8] AND ORDER 50 -- measured identical to
those three written out. This block's defaults are exactly those at fs = 1000.
- THE AMPLITUDE IS |DFT| / N WITH THE INTERIOR BINS DOUBLED: an amplitude spectrum, not a
density, and the envelope's own mean is removed first so DC carries no offset.
⚠ A STREAM HAS NO RECORD, so the record is the window: the demodulating phase restarts at every window, and the convolution's zero-padding sits at the window's two ends, exactly as envspectrum treats a record of N samples. That is what makes the block envspectrum of the last N samples, and not a filter run continuously over the stream.
The window, the filter, the twiddles and the scales are computed once at export time and carried as numbers; the convolution, the analytic signal, the two magnitudes and the spectrum run as loops in every target. The HDL targets run them in simulation-only
real.
Sample results#
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 … 3.643e-17 |
ramp | Ramp: slope 1 from t = 0 | 0 … 2.949e-17 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 0 … 1.648e-17 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | 1.735e-18 … 1.856e-16 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit 93133d604 · produced by docsSample --out <folder> --blocks Gain_Scheduled_Lead_Lag Controller_1D Controller_Blend_1D Controller_2D Controller_3D Observer_Form_1D Self_Conditioned_1D Line_Of_Sight_Access Orbit_Propagator_Kepler Attitude_Dynamics Attitude_Profile_Nadir_Pointing Attitude_Profile_Geographic_Pointing Multitaper_PSD Cross_Power_Spectral_Density Transfer_Function_Estimate Envelope_Spectrum Compose_String Scan_String --steps 60 · data docs/generated/samples/Control_Systems__Vibration__Envelope_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).