Deconvolution — Control Systems/Correlation And Convolution
Control_Systems/Correlation_And_Convolution/Deconvolution · 1 input / 2 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.
Deconvolution
Control Systems / Correlation And Convolution
Divides the last N samples of a stream, read as polynomial
coefficients, by a fixed denominator d of length M taken from
configuration, and reports both halves of the division:
a = conv(d, q) + r. It is the streaming counterpart of MATLAB's
[q, r] = deconv(a, d), which is the inverse-filtering
direction – divide a measured signal by a known kernel.
The exported core performs no division. With d fixed the long division is linear in the window, so the quotient and the remainder are each a constant matrix times the window. Those weights are derived once when the configuration is read; every target then emits the same multiply-accumulates.
Ports
- u – the stream being divided. Scalar; the block keeps its own window of the last N samples – see Notes.
- q – the quotient, a column of N − M + 1 entries.
- r – the remainder, a column of N entries, of which the leading N − M + 1 are exact zeros.
Parameters
- Window Length – N, how many samples are divided. A whole number from 2 to 64. The bound is a code-size bound: both weight matrices are unrolled in every target.
- Denominator – d, the divisor's coefficients as a row or column vector, first element first, exactly as MATLAB reads them. Its length M must be at least 1 and at most N, and its first entry must be non-zero: every weight carries 1/d[0].
- 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 weights are structural and are inlined into the arithmetic at export time rather than exposed as tunable parameters – they follow from Window Length and Denominator, and changing either changes how many multiplies the core contains and how wide its outputs are, which no runtime parameter can do. Re-export after changing them.
The three HDL targets are genuine synthesizable Q16.16: a shift register and two fixed multiply-accumulate trees, with the products accumulated at full width and shifted back once per output entry. There is no divider in the emitted core, because every division happened at export time.
Simulink bridge
No equivalent (Support::None). The Signal Processing
Toolbox ships no Simulink library at all, and nothing in the Simulink
standard library or in DSP System Toolbox performs a polynomial division and
reports a remainder. 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 denominator is configuration, not a second input, on purpose. Long division divides by d[0] at every step, so a denominator arriving on a wire could pass within a rounding error of zero at any sample and send the quotient to infinity for the rest of the window. From configuration it is checked once, at load, and the run either starts or reports why.
- Oldest-first is the published order. a[0] is the oldest sample still in the window, and the denominator is read first element first, both as MATLAB reads them.
- The leading remainder entries are exact zeros. Subtracting q[k]·d[0] from r[k] does not leave a floating-point zero behind, but MATLAB reports zeros there and so does this block.
- The window is zero-prefilled, and the zeros count. The first
N−1 outputs of a run are a startup transient rather than a division of
real data. MATLAB's
deconvis a batch function with the whole vector in hand and has no transient. - Verified against MATLAB. On a = [0.7 −1.3 0.45 2.1 −0.6] divided by d = [1.4 −0.5 0.9], this block's weights reproduce R2026a's quotient to 1.1e−16 and its remainder exactly.
- Scalar input. One channel and its own window; wire one block per channel.
- No state space. The outputs depend on N past inputs through two fixed matrices rather than through an A/B/C/D pair seeded here, so the block carries none and model reduction correctly declines to merge it.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Correlation_And_Convolution/Deconvolution |
| family | Control_Systems/Correlation_And_Convolution |
| solver environment class | ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Deconvolution |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Deconvolution/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Deconvolution.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Correlation_And_Convolution/Deconvolution/ICoreBlock_0_Control_Systems_1_Correlation_And_Convolution_2_Deconvolution.h |
| default size on canvas | 136 × 80 px |
| ports at insert | 1 in, 2 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 | q |
| 3 | out | ICoreDouble | r |
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 | 8 | — |
Denominator | [1 -0.6 0.25] | — |
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: deconv() is a MATLAB function and the Signal Processing Toolbox ships no Simulink library at all. Nothing in the Simulink standard library or in DSP System Toolbox performs a polynomial division and reports a remainder -- DSP System Toolbox's Convolution block is the forward direction only. 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).
Deconvolution -- polynomial long division of a windowed stream by a configured denominator ONE WEIGHT MATRIX PER OUTPUT, TEN IDENTICAL SETS OF DOT PRODUCTS. With the denominator fixed, long division is LINEAR in the window: the quotient and the remainder are each a constant matrix times the window. So the division is never performed at run time in any target -- the weights are derived once when the configuration is read, by dividing the N unit windows, and every backend emits multiply-accumulates over a shift register. The emitted core contains no division at all, which is what lets the three hardware targets carry it as a fixed-latency pipeline rather than as an iterative unit.
WHY THE DENOMINATOR IS CONFIG AND NOT A SECOND INPUT. Long division divides by d[0] at every step. A denominator arriving on a wire may pass within a rounding error of zero at any sample, and the quotient then runs to infinity for the remainder of the window -- a block well posed only for inputs nobody can promise, and one whose export-verification rig would diverge on whichever random stimulus it happened to draw. Taken from configuration, d[0] is checked ONCE at config load and the run either starts or reports why. That also matches what the operation is used for: dividing a measured signal by a KNOWN kernel.
MEASURED AGAINST MATLAB R2026a rather than asserted. On a = [0.7 -1.3 0.45 2.1 -0.6] divided by d = [1.4 -0.5 0.9], R2026a returns q = [0.5 -0.75 -0.267857142857143] and r = [0 0 0 2.64107142857143 -0.358928571428571]; the weight matrices above reproduce them to 1.1e-16 and exactly, respectively. The probe is recorded in the notes of the toolbox-blocks plan, Family B.
⚠ THE LEADING N-M+1 REMAINDER ENTRIES ARE EXACT ZEROS. Subtracting q[k]*d[0] from r[k] does not leave a floating-point zero behind, but MATLAB reports zeros there and so does this block: the weight rows for those entries are set to zero rather than to the residue.
⚠ THE WINDOW IS ZERO-PREFILLED AND THE ZEROS COUNT -- the convention Detrend and Moving Median carry. The first N - 1 outputs of a run are a startup transient.
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 … 1 |
ramp | Ramp: slope 1 from t = 0 | 0 … 5.2 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.9962 … 0.9996 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -2 … 3 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit 3c100aff6f27235305db4ad4d572f32e342718ad · produced by docsSample --out <folder> --blocks Convolution Circular_Convolution Convolution_Matrix Deconvolution Cross_Correlation Cross_Covariance --steps 60 · data docs/generated/samples/Control_Systems__Correlation_And_Convolution__Deconvolution.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).