Detrend — Control Systems/Signal Smoothing
Control_Systems/Signal_Smoothing/Detrend · 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.
Detrend
Control Systems / Signal Smoothing
Removes the trend from a stream: it fits a least-squares constant or
least-squares straight line to the last N samples and outputs what
the newest sample has left over after that fit is subtracted –
y = u − fit(u), the streaming counterpart of MATLAB's
detrend.
The residual of a least-squares fit is a linear function of the window, so the block is one FIR filter: N weights, derived once from the two parameters, applied to a shift register. In constant mode the weights are δ − 1/N, which is the input minus the window mean; in linear mode they additionally remove the fitted slope.
Ports
- u – the trending signal. Scalar – see Notes.
- y – the residual at the newest sample. Same size as the input, so scalar.
Parameters
- Window Length – N, how many samples the fit sees. A whole number from 2 to 256. Larger N follows a slower trend and leaves more of the signal; smaller N tracks the signal itself and leaves less.
- Trend Order – what is fitted and removed:
- constant – the window mean, so the output is a zero-mean
residual. This is
detrend(x, 0). - linear – a straight line through the window by least squares,
so a constant ramp is removed as well as a constant offset. This is
detrend(x, 1), and it is the default.
- constant – the window mean, so the output is a zero-mean
residual. This is
- 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 N weights are structural and are inlined into the arithmetic at export time rather than exposed as tunable parameters – they follow from Window Length and Trend Order, and changing either changes how many multiplies the core contains, which no runtime parameter can do. Re-export after changing them.
The three HDL targets are genuine synthesizable Q16.16: a shift register and a fixed multiply-accumulate, with the products accumulated at full width and shifted back once at the end rather than per term.
Simulink bridge
No equivalent (Support::None). The Signal Processing
Toolbox ships no Simulink library at all – detrend is a
MATLAB function, and no block in the Simulink standard library or in DSP System
Toolbox removes a least-squares trend over a sliding window. 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)): the window advances once per sample. - The window is zero-prefilled, and the zeros count. Before N samples
have arrived the buffer still holds its initial zeros and they take part in the
fit, so the first N−1 outputs of a run are a startup transient rather than
a detrended signal. MATLAB's
detrendis a batch function with the whole vector in hand and has no transient; a streaming block cannot avoid one. The convention matches Moving Median, whose zero-prefill was measured against Simulink. - Verified against MATLAB. With N set to a whole 9-sample vector's
length, this block's output at that vector's last sample matches
detrend(x, 0)anddetrend(x, 1)in R2026a to within 1e−15. - Scalar only. One channel and its own history; wire one block per channel. The size is checked rather than silently detrending the first element.
- No state space. The block is linear in its input, but its output depends on N past samples through a fixed FIR rather than through an A/B/C/D pair seeded here, so it carries none and model reduction correctly declines to merge it.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Signal_Smoothing/Detrend |
| family | Control_Systems/Signal_Smoothing |
| solver environment class | ICoreBlock_0_Control_Systems_1_Signal_Smoothing_2_Detrend |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Smoothing/Detrend/ICoreBlock_0_Control_Systems_1_Signal_Smoothing_2_Detrend.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Signal_Smoothing/Detrend/ICoreBlock_0_Control_Systems_1_Signal_Smoothing_2_Detrend.h |
| default size on canvas | 124 × 72 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 | y |
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 |
|---|---|---|
Window Length | 32 | — |
Trend Order | constant%~%linear~~linear | — |
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: detrend() is a MATLAB function and the Signal Processing Toolbox ships no Simulink library at all, while nothing in the Simulink standard library or in DSP System Toolbox removes a least-squares trend over a sliding window. 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).
Detrend -- the residual of a least-squares constant or straight line over the last N samples ONE WEIGHT VECTOR, TEN IDENTICAL DOT PRODUCTS. The residual of a least-squares fit is a LINEAR functional of the window, so the fit is never recomputed per sample: the weights are derived once when the configuration is read, and every target emits the same multiply-accumulate over a shift register. The emitted core has no division and no branch, which is what keeps the three hardware targets a fixed-latency pipeline.
MEASURED AGAINST MATLAB R2026a rather than asserted. Driven with the window set to a whole 9-sample vector, this block's output at that vector's last sample equals detrend(x, 0) to 4e-16 and detrend(x, 1) to 7e-16. The probe is recorded in the notes of the toolbox-blocks plan, Family B.
⚠ THE WINDOW IS ZERO-PREFILLED AND THE ZEROS COUNT -- the same convention Moving Median carries, which was itself measured against Simulink. The first N-1 outputs of a run are a startup transient. MATLAB's detrend() has the whole vector in hand and has no transient at all; a streaming block cannot avoid one, so the choice is which one to document.
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.1136 … 0.8807 |
ramp | Ramp: slope 1 from t = 0 | -1.513e-15 … 0.4375 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -1.298 … 1.292 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -2.665 … 2.545 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit 6db3032c0 · produced by docsSample --out <folder> --blocks Detrend Savitzky_Golay_Filter Hampel_Filter Envelope_Detector --steps 60 · data docs/generated/samples/Control_Systems__Signal_Smoothing__Detrend.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).