Lookup Table nD — Control Systems/Lookup Tables
Control_Systems/Lookup_Tables/Lookup_Table_nD · 0 input / 0 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.
n-D Lookup Table
Control Systems / Lookup Tables
Maps three inputs through a rectangular volume: y = table(u1, u2, u3). The three axes are searched independently and the eight surrounding entries are blended – which for the Linear rule is ordinary trilinear interpolation.
Three dimensions is Simulink's own default for this block, and it is what this one is. For one or two axes use 1-D Lookup Table or 2-D Lookup Table, which are cheaper and read more clearly.
Ports
- Input u1 – the first axis' coordinate, a scalar.
- Input u2 – the second axis' coordinate, a scalar.
- Input u3 – the third axis' coordinate, a scalar.
- Output – the table's value y, a scalar.
All four ports are scalar: a triple of matrix inputs has no single sensible reading, so this block does not run elementwise.
Parameters
- Breakpoints 1, Breakpoints 2, Breakpoints 3 – the three axes, each a row or column vector of at least two strictly increasing values.
- Table Data – the volume, as a flat vector holding exactly
n1×n2×n3 values in column-major order: entry (i, j, k) sits at
index i + j·n1 + k·n1·n2, counting from zero. That is
MATLAB's own
reshapeorder, soreshape(TableData, [n1 n2 n3])in MATLAB and this parameter are the same numbers in the same order. It is flat because an ICore configuration value is a matrix, and a matrix has no third dimension to write. - Interpolation Method – what the table says between the points.
- Linear point-slope – trilinear across the surrounding eight entries.
- Flat – the entry at the breakpoint at or below each input, on all three axes independently.
- Nearest – the entry at the nearer breakpoint on each axis; an exact tie takes the higher one.
- Extrapolation Method – what the table says outside its own range.
- Linear – continue off the edge along the slopes of the edge cell. Off an edge, a face or a corner, one, two or all three axes extrapolate at once.
- Clip – hold each input inside its own axis.
- 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 table and both rules are baked in at export time: the generated code is a three-level chain of comparisons with one expression per cell, so the table's shape decides its size. A large volume produces a large core – this is the block in the family where that matters most, since the cell count is the product of all three axes.
The three HDL targets are not simulation-only. Each cell's eight coefficients and each interval's reciprocal width are folded into constants, so a cell is a handful of multiplies and adds with no divider. The caveat is range – a signal is carried in Q16.16 there, so a breakpoint or table value outside ±32767 cannot be represented, and the trilinear cross term is where a large table value meets a large coordinate.
Simulink bridge
None, and the reason is structural rather than a gap in this block. Simulink's
n-D Lookup Table requires its Table parameter to be a genuine
3-D array; a flat vector is rejected when the model is compiled. Crossing would
therefore mean writing reshape([…],[n1 n2 n3]) rather than the
config's own text – and the bridge passes parameter text through unchanged,
while an ICore configuration value is a matrix and cannot hold that call either. Neither
side can spell the other's shape, so the block reports itself as unsupported instead of
carrying a mapping that would fail in front of a user.
Worth knowing if you go looking: Simulink's set_param accepts the
flat vector without complaint. The failure appears only at compile time, so a bridge
built on what set_param allows would look correct and break later.
1-D Lookup Table and 2-D Lookup Table have no such problem – a vector and a matrix are both directly expressible – and are mapped in full. This block is still covered by code export verification, which compares the ten generated languages against ICore's own solver and needs no Simulink counterpart.
Notes
- Algebraic, with no state.
- Not linear, and so deliberately carries no state space.
- See 2-D Lookup Table for two axes and Direct Lookup Table (n-D) for selection by index with no axis at all.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Lookup_Tables/Lookup_Table_nD |
| family | Control_Systems/Lookup_Tables |
| solver environment class | ICoreBlock_0_Control_Systems_1_Lookup_Tables_2_Lookup_Table_nD |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Lookup_Tables/Lookup_Table_nD/ICoreBlock_0_Control_Systems_1_Lookup_Tables_2_Lookup_Table_nD.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Lookup_Tables/Lookup_Table_nD/ICoreBlock_0_Control_Systems_1_Lookup_Tables_2_Lookup_Table_nD.h |
| default size on canvas | 90 × 85 px |
| ports at insert | ? in, ? 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 | u1 |
| 2 | in | ICoreDouble | u2 |
| 3 | in | ICoreDouble | u3 |
| 4 | 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#
| Config variable | Default | Simulink parameter |
|---|---|---|
Breakpoints 1 | [10 22 31] | — |
Breakpoints 2 | [10 22 31] | — |
Breakpoints 3 | [5 7] | — |
Table Data | [4 16 10 5 19 18 6 20 23 4 16 10 5 19 18 6 20 23] | — |
Interpolation Method | LUT::interpComboSpec() | — |
Extrapolation Method | LUT::extrapComboSpec() | — |
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): a 3-D table cannot cross as a parameter VALUE. Simulink's n-D Lookup Table requires Table to be a genuine 3-D array and rejects a flat vector when the model is compiled ('the number of dimensions of Table data is 1, but ... Number of table dimensions is 3'), while an ICore config value is a matrix and the bridge passes parameter text through unchanged - so neither side can spell the other's shape. Crossing would need the bridge to synthesize a reshape() call, which no ParamRule can do. The 1-D and 2-D Lookup Tables have no such problem and are mapped fully; this block is still covered by code export verification, which compares against ICore's own solver and needs no Simulink counterpart
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).
n-D Lookup Table block — y = table(u1, u2, u3) Three axes searched independently, then the eight surrounding entries blended. Algebraic, stateless, scalar in and out. No state space (see header).
THE EMITTED CODE IS A THREE-LEVEL NESTED CHAIN with one expression per cell, so the table's SHAPE decides the size of the generated code - (n1-1)(n2-1)(n3-1) leaves for the Linear rule. That is the same trade every table in this family makes, and the reason the table cannot be a tunable parameter.
THE FRACTIONS ARE INLINE EXPRESSIONS, NOT VARIABLES, and Clip is spelled as extra branches at each end of each axis rather than as a clamp. Three fractions are live at once inside the innermost cell and VHDL has only TWO fixed-point process variables, so latching them was never an option - and once they are inline, an end branch carrying the constant 0 or 1 is a cheaper way to say "clip" than a min/max would be in any of the ten targets.
NO DIVIDER IS EMITTED: each interval's reciprocal width and each cell's eight coefficients are constants folded at export time.
Sample results#
| t | in ICoreDouble-Out-0 | in ICoreDouble-Out-0 | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 |
|---|---|---|---|---|
| 0 | -2 | -2 | -2 | -7 |
| 0.4 | 0.5 | 0.5 | 0.5 | -5.038 |
| 0.8 | -2 | -2 | -2 | -7 |
| 1.2 | 0.5 | 0.5 | 0.5 | -5.038 |
| 1.6 | -2 | -2 | -2 | -7 |
| 2 | 0.5 | 0.5 | 0.5 | -5.038 |
| 2.4 | -2 | -2 | -2 | -7 |
| 2.8 | 0.5 | 0.5 | 0.5 | -5.038 |
| 3.2 | -2 | -2 | -2 | -7 |
| 3.6 | 0.5 | 0.5 | 0.5 | -5.038 |
| 4 | -2 | -2 | -2 | -7 |
| 4.4 | 0.5 | 0.5 | 0.5 | -5.038 |
| 4.8 | -2 | -2 | -2 | -7 |
| 5.2 | 0.5 | 0.5 | 0.5 | -5.038 |
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) | -5.444 … -4.625 |
ramp | Ramp: slope 1 from t = 0 | -5.444 … -0.305 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -6.236 … -4.625 |
step | Step: 0 -> 1 at t = 1 s | -5.444 … -4.625 |
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 ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Lookup_Tables__Lookup_Table_nD.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).