IDCT — Control Systems/Transforms
Control_Systems/Transforms/IDCT · 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.
IDCT
Control Systems / Transforms
The inverse of the orthonormal type-II cosine transform – the
type-III transform – of the window on its input, which is MATLAB's
idct(u):
y[n] = Σₖ w[k]·u[k]·cos(π(2n+1)k / 2N), with
w[0] = √(1/N) and w[k] = √(2/N) for every other k.
Where the weight sits is the whole difference from the DCT block. Forward, w[k] scales the output entry; here it scales the input entry it multiplies. The coefficient matrix is therefore the forward one transposed, which is what the inverse of an orthonormal transform is, so feeding a DCT block's output straight into this one returns the original window exactly.
Ports
- u – the cosine coefficients to invert, a vector: an [N,1] column or a [1,N] row, N from 1 to 32. Entry k is u[k] in the sum above, and entry 0 is the DC term.
- y – the reconstructed window, the same size and orientation as the input.
Parameters
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
There is nothing else to set, deliberately: N is the width of the input port, not a configuration value, so the block and the signal reaching it cannot disagree about the transform length. Simulink's own IDCT dialog carries no semantic parameter either – only a table-lookup implementation switch.
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.
The N×N cosine coefficients are structural and are inlined into the generated arithmetic: they follow from the window length alone, so every target emits one dot product per output entry and computes no cosine and no square root at run time – those happened at export. The coefficients are the DCT block's transposed, so the two blocks emit cores of exactly the same shape and cost.
The three HDL targets are genuine synthesizable Q16.16: only multiplies and adds, accumulated at double width and shifted back once per entry. Every coefficient has magnitude at most √(2/N) ≤ 1, comfortably inside the format, so no part of the matrix quantizes away.
Simulink bridge
Both directions, mapping to dspxfrm3/IDCT from the DSP
System Toolbox. There are no parameters to map: the block's dialog carries
a trigonometric-versus-table implementation switch and an output-framing choice,
and neither changes the answer – both framing values were simulated and
returned the same numbers. The transform length is inherited from the frame on
both sides.
Two measured caveats. Simulink's IDCT requires the window length to be a power of two – a 5-point frame stops the simulation with "The length of the dimension being transformed must be a power of two" – while this block accepts any length from 1 to 32, so a window of 5, 6 or 12 entries has no counterpart to cross to. And the Simulink block has no SampleTime parameter, so an explicit rate set here stays on the ICore side and is reported rather than written into the generated script.
Notes
- Algebraic, with no state. The whole window arrives on the port, so one step is one transform and nothing carries over.
- Measured against R2026a. Over an 8-point window the coefficients here
reproduce
idctto 2.2e−15, anddspxfrm3/IDCTsimulated on the same window agreed withidctto 2.2e−16. - The exact inverse is the DCT block, whose coefficient matrix this one is the transpose of. Chaining the two in either order returns the original signal.
- No state space. The map is linear in the window, but a fixed matrix over N presented samples is not an A/B/C/D pair evolving in time, so the block carries none and model reduction correctly declines to merge it.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Transforms/IDCT |
| family | Control_Systems/Transforms |
| solver environment class | ICoreBlock_0_Control_Systems_1_Transforms_2_IDCT |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Transforms/IDCT/ICoreBlock_0_Control_Systems_1_Transforms_2_IDCT.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Transforms/IDCT/ICoreBlock_0_Control_Systems_1_Transforms_2_IDCT.h |
| default size on canvas | 130 × 80 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#
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 | dspxfrm3/IDCT |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
Caveat (shown to the user): maps to the DSP System Toolbox's IDCT, which computes the same orthonormal type-III transform (simulated on an 8-point window and agreeing with MATLAB's idct to 2.2e-16). The transform length is not a parameter on either side: it is inherited from the frame in Simulink exactly as it is taken from the input port here. Two measured caveats -- Simulink's IDCT requires a POWER-OF-TWO window and stops the simulation on any other length, while this block accepts 1 to 32; and the Simulink block has no SampleTime parameter, so an explicit rate does not cross the bridge
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).
IDCT -- the orthonormal type-III discrete cosine transform of a window (MATLAB idct) y[n] = SUM over k of w[k] * u[k] * cos( pi * (2n+1) * k / (2N) ), n = 0 .. N-1 w[0] = sqrt(1/N), w[k] = sqrt(2/N) for k > 0
WHICH INDEX CARRIES THE WEIGHT IS THE WHOLE DIFFERENCE from the DCT block. Forward, w[k] scales the OUTPUT entry; here it scales the INPUT entry it multiplies. The coefficient matrix is the forward one TRANSPOSED, which is what the inverse of an orthonormal transform is. Leaving the weight on the output index instead produces a plausible cosine sum that is wrong on every entry but the first, and wrong by a DIFFERENT factor on each -- so it does not read as a scale error, and a rig whose window happened to be flat would not catch it.
ONE MATRIX PRODUCT. A[n][k] depends on the window LENGTH and on nothing else: no config variable, no signal. So the N*N coefficients are derived once, when the input port's size settles, and each of the ten targets inlines them as one dot product per output entry. No emitted core computes a cosine or a square root; it multiplies and adds.
⚠ MEASURED AGAINST R2026a rather than asserted. Over the rig's window [0.9 -0.35 1.25 0.4 -0.8 0.15 0.55 -1.1] the coefficients derived here reproduce idct() to 2.2e-15, and dspxfrm3/IDCT was SIMULATED on the same window (From Workspace frame, fixed-step discrete) and agreed with idct() to 2.2e-16. Neither number was taken from a doc page.
⚠ SIMULINK'S IDCT NEEDS A POWER-OF-TWO WINDOW AND THIS ONE DOES NOT. Measured: a 5-point frame stops the simulation with "The length of the dimension being transformed must be a power of two". A sum has no radix, so this block accepts 1 .. 32 and the catalog entry says in as many words that a non-power-of-two window has nothing to cross to.
⚠ AND THE SIMULINK BLOCK HAS NO SampleTime PARAMETER. Measured with set_param, which is the only way to know: "IDCT block (mask) does not have a parameter named 'SampleTime'". The entry therefore sets hasSampleTimeParam = false -- a set_param on a name a block does not define is a hard MATLAB error that aborts the whole generated script.
ALGEBRAIC: the whole window is presented on the input port, so one step completes one transform and nothing is held between samples. No state space -- the map is linear in the input, but a fixed matrix over a WINDOW is not an A/B/C/D pair evolving in time, which is the same reason Chirp-Z Transform carries none.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|
| 0 | -2 | -2 |
| 0.4 | 0.5 | 0.5 |
| 0.8 | -2 | -2 |
| 1.2 | 0.5 | 0.5 |
| 1.6 | -2 | -2 |
| 2 | 0.5 | 0.5 |
| 2.4 | -2 | -2 |
| 2.8 | 0.5 | 0.5 |
| 3.2 | -2 | -2 |
| 3.6 | 0.5 | 0.5 |
| 4 | -2 | -2 |
| 4.4 | 0.5 | 0.5 |
| 4.8 | -2 | -2 |
| 5.2 | 0.5 | 0.5 |
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 … 1 |
ramp | Ramp: slope 1 from t = 0 | 0 … 5.9 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -1 … 0.9996 |
step | Step: 0 -> 1 at t = 1 s | 0 … 1 |
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 3c100aff6f27235305db4ad4d572f32e342718ad · produced by docsSample --out <folder> --blocks DCT IDCT FFT IFFT --steps 60 · data docs/generated/samples/Control_Systems__Transforms__IDCT.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).