Derivative — Control Systems/Continues
Control_Systems/Continues/Derivative · 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.
Derivative
Control Systems / Continues
Differentiates its input with respect to time – y = du/dt – as the backward difference quotient over the block's own sampling period dt:
- y[0] = 0 – the first sample has no predecessor to difference against.
- y[k] = (u[k] − u[k−1]) / dt thereafter.
Applied entry by entry, so a [m,n] signal is differentiated element-wise.
Ports
- Input – the signal u to differentiate, of any size [m,n].
- Output – the rate of change y, of the SAME size [m,n]. The block never reshapes a signal.
Parameters
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period. It is the dt the difference is divided by, so it is part of the arithmetic and not merely a schedule: halving the period doubles the gain the block applies to a given step.
The block has no other parameters. In particular there is no ICore counterpart to Simulink's linearization coefficient – see the bridge note below.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. 1/dt is baked in as a constant and the body multiplies by it, so a generated core never divides by a time step and the three fixed-point HDL targets need no divider. The exported state is the previous input sample, one value per entry, plus a first-sample flag so a generated core emits the same leading zero the in-app block does.
Note that differentiation amplifies by 1/dt – at dt = 0.01 that is a factor of 100. On the fixed-point HDL targets the input's quantization is amplified by the same factor, so a signal that is noisy at the sample scale will show a correspondingly larger absolute error there than on the software targets. That is the block's arithmetic, not a defect of those backends.
Simulink bridge
Import and export, mapped to simulink/Continuous/Derivative. There are
no parameters to pair: the Simulink block's only dialog parameter is
CoefficientInTFapproximation, the coefficient c in the
approximation s / (c·s + 1) that Simulink uses when
linearizing the block. It never affects the simulated output, on either
side, so ICore implements the ideal derivative and always writes
inf – Simulink's own default, meaning the exact derivative.
Importing a block with a finite c is reported rather than silently
accepted, because ICore does not carry that approximation. "Sampling Time (s)"
does NOT cross: this Simulink block defines no SampleTime
parameter, so the rate stays on the ICore side. That matters here – dt
divides the difference, so two sides stepping at different rates do not merely
run out of schedule, they compute different gains.
Notes
- Stateful: one previous-input sample per entry.
- Discrete by nature – the difference is taken per sample, so the block always runs at its own rate rather than being pushed through a continuous solver's stages, where it would difference a sample against itself.
- Not linear in the state-space sense, and so deliberately carries no state space: the ideal derivative is the improper transfer function s, which has no A/B/C/D realization. The model reduction commands therefore decline to merge it, rather than silently substituting the proper approximation s/(c·s+1), which is not what this block simulates.
- Differentiating a noisy signal amplifies the noise by 1/dt. That is inherent to the operation; if the input is not smooth at the sample scale, filter it first.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Continues/Derivative |
| family | Control_Systems/Continues |
| solver environment class | ICoreBlock_0_Control_Systems_1_Continues_2_Derivative |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Continues/Derivative/ICoreBlock_0_Control_Systems_1_Continues_2_Derivative.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Continues/Derivative/ICoreBlock_0_Control_Systems_1_Continues_2_Derivative.h |
| default size on canvas | 80 × 70 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 | — |
| 2 | out | ICoreDouble | — |
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#
No config variable beyond the Sampling Time (s) every block carries.
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::Both |
| Simulink path | simulink/Continuous/Derivative |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| always set | CoefficientInTFapproximation = inf |
Caveat (shown to the user): ICore implements the IDEAL derivative. Simulink's only parameter, CoefficientInTFapproximation, is the coefficient c in the approximation s/(c*s+1) that Simulink uses when LINEARIZING the block; it never affects the simulated output on either side, so it is always written as "inf" (Simulink's own default, meaning the exact derivative) and a finite value on import is reported rather than silently accepted. "Sampling Time (s)" does not cross, and it divides the difference
Catalog contract: src/ICoreSDK/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).
Derivative block — y = du/dt, as the backward difference quotient With dt the block's own sampling period: y[0] = 0 (no earlier sample to difference against) y[k] = (u[k] - u[k-1]) / dt thereafter applied entry by entry to a [m,n] signal. This is exactly what Simulink's Derivative block computes over its major time steps -- verified against the R2026a block under FixedStepDiscrete at dt: the two agree to 4e-13 absolute on outputs of order 500, which is double rounding in the workspace round trip and nothing else.
Stateful: the previous input sample IS the state, and it lives in a member rather than in the solver's state vector -- there is nothing here for Runge-Kutta to integrate. Same contract as Rate Limiter and Backlash.
DISCRETE BY NATURE. The difference quotient is a step per SAMPLE: dt must be the block's own rate, not whatever sub-step a continuous solver happens to be evaluating at. Pushed through RK stages the same input would be differenced against itself at spacing 0, so the block declares setDiscreteOnlyBlock(true) and always runs at its own period.
NO STATE SPACE, deliberately. The ideal derivative y = du/dt is the improper transfer function s: it has no A/B/C/D realization, and fabricating the proper approximation s/(c*s+1) would hand the reduction commands a system this block does not actually simulate. Simulink draws the same line -- its coefficient c is used for LINEARIZATION ONLY and never affects the simulated output.
Code export: 1/dt is inlined as a constant, so no target divides by a time step and the three fixed-point HDL targets need no divider.
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) | -10 … 10 |
ramp | Ramp: slope 1 from t = 0 | 0 … 1 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -1.995 … 1.996 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -50 … 10 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Continues__Derivative.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).