Generated reference › Interpolate Matrix XYZ — Control Systems/Gain Scheduling
kind: generated#block#control-systems-gain-scheduling

Interpolate Matrix XYZ — Control Systems/Gain Scheduling

Control_Systems/Gain_Scheduling/Interpolate_Matrix_XYZ · 6 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.

Interpolate Matrix XYZ (x,y,z)

Control Systems / Gain Scheduling

Blends a stored three-dimensional grid of matrices and answers a single matrix: the trilinear blend of the eight matrices around the position (kx, fx, ky, fy, kz, fz), each corner weighted by the product of its three per-axis weights – 1−f on the low side of an axis and f on the high side. It is the three-scheduling-variable form of Interpolate Matrix(x).

Pair it with one Prelookup per scheduling variable: each turns a value into the (k, f) pair one axis of this block consumes.

It is registered as Interpolate Matrix XYZ; the Aerospace Blockset spells the same block Interpolate Matrix(x,y,z), and the title above carries both so either name finds it.

Ports

  • x_k – the interval index on the x axis, counted from zero, as a scalar. Truncated, not rounded, and the two slice indices it selects are clamped separately into [0, Px−1]: below zero and at or past the last index the blend goes flat along x.
  • x_f – the fraction across that interval, as a scalar. Not held in [0,1]: inside the grid a value outside it extrapolates.
  • y_k – the interval index on the y axis, same rules, over [0, Py−1].
  • y_f – the fraction across that interval, same rules.
  • z_k – the interval index on the z axis, same rules, over [0, Pz−1]. Every axis clamps on its own, so the blend can be flat along one or two axes while still interpolating along the rest.
  • z_f – the fraction across that interval, same rules.
  • Output – the blended matrix Y, of the shape of ONE matrix of the grid: Matrix Rows tall and as wide as the Matrix Table. Its size comes from the configuration and not from the inputs.

Parameters

  • Matrix Table – the grid, with the matrices stacked vertically, x varying fastest and z slowest: the matrix at (ix, iy, iz) occupies row block ix + Px·iy + PxPy·iz, so the table is PxPyPz·R rows by C columns. A matrix config cannot hold a five-dimensional array, so this is the one spelling available. From a MATLAB array M of size [R C Px Py Pz] the config is reshape(permute(M,[1 3 4 5 2]), R*Px*Py*Pz, C), whose column-major walk over (row, ix, iy, iz) is exactly that order.
  • Matrix Rows – R, how tall one matrix of the grid is. A whole-number scalar of at least 1; the table's height must be a whole multiple of it. Defaults to 2.
  • X Breakpoint Count – Px, how many matrices the grid holds along x. A whole-number scalar of at least 1. Defaults to 2.
  • Y Breakpoint Count – Py, the same along y. The product of the two must divide the number of slices the table holds; Pz is derived from what is left and is never stated. Defaults to 2.
  • 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 grid is resolved at export time into the constants of a decision chain – one branch per triple of regions, each carrying its eight corners folded into a nested blend – and inlined rather than exposed as a tunable parameter. It cannot be otherwise: the grid's shape decides how many branches the generated code has.

This is the block whose exported body gets large, and it is the one thing to plan for. Each axis contributes one branch per interval plus one for each of its two flat regions, so the emitted body grows as (Px+1)·(Py+1)·(Pz+1)·R·C: a 5×5×5 grid of 3×3 matrices is about 1900 branches per language, and a 10×10×10 grid of 4×4 is over 21000. A schedule that is comfortable in the simulator can still be a very large generated core. Prefer fewer breakpoints on the axes that matter least, or split the schedule across two blocks of fewer axes.

The three HDL targets are not simulation-only: each branch is seven multiplies and seven adds on constants known at export time, and no divider is emitted. The Q16.16 caveats are the one-axis block's – a matrix entry outside ±32767 cannot be represented, and an index arriving exactly on a whole number can be moved to the interval below by the port's own quantization.

Simulink bridge

None (Support::None). Simulink's counterpart is aerolibschedule/Interpolate Matrix(x,y,z) in the Aerospace Blockset and it computes the same trilinear blend – the measurements this block is written from, including which trailing dimension is which axis, were taken off it – but its one parameter, matrix, is a five-dimensional array, and neither MATLAB's matrix literal syntax nor an ICore matrix config has a five-dimensional form. So the grid cannot cross in either direction, and an exported model would carry the ports, the wiring and no schedule at all. It is reported rather than dropped silently, and it therefore has no parity testbench; code export verification still covers it across all ten languages.

The Simulink block defines no SampleTime parameter either – measured, its only parameter is the array.

Notes

  • Algebraic, with no state: the output depends only on the current inputs.
  • The third dimension of the array is x, the fourth is y and the fifth is z, measured rather than inferred. A permutation of the three is exactly right on the diagonal of a cubic grid and wrong elsewhere – and right everywhere on any grid whose axes have equal breakpoint counts, which is the shape a first test is most likely to have.
  • Each index truncates, its two slice indices clamp separately, and no fraction is clamped. Same rules as the one-axis block, applied per axis and independently – so the blend can be flat along one or two axes and still interpolating along the rest. Where an axis is flat, no multiply is emitted for it at all.
  • Not linear – selecting between stored matrices is a step function of the indices – so the block carries no state space and model reduction reports it as unmergeable.
  • All six inputs are scalars. One index and one fraction per axis select ONE matrix out of the grid.
  • For one or two scheduling variables, use Interpolate Matrix(x) or Interpolate Matrix(x,y) – and prefer them where they suffice, for the export size above.

Code facts#

FactValue
registered typeControl_Systems/Gain_Scheduling/Interpolate_Matrix_XYZ
familyControl_Systems/Gain_Scheduling
solver environment classICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XYZ
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Gain_Scheduling/Interpolate_Matrix_XYZ/ICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XYZ.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Gain_Scheduling/Interpolate_Matrix_XYZ/ICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XYZ.h
default size on canvas130 × 130 px
ports at insert6 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublex_k
2inICoreDoublex_f
3inICoreDoubley_k
4inICoreDoubley_f
5inICoreDoublez_k
6inICoreDoublez_f
7outICoreDouble—

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 variableDefaultSimulink parameter
Matrix Table1 0; 0 1; 2 0; 0 2; 3 0; 0 3; 4 0; 0 4; 5 0; 0 5; 6 0; 0…—
Matrix Rows2—
X Breakpoint Count2—
Y Breakpoint Count2—

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.

supportSupport::None
Simulink path—
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): aerolibschedule/Interpolate Matrix(x,y,z) computes the same trilinear blend -- this block's index rules and its axis-to-dimension order were measured off it -- but its ONE parameter, matrix, is a FIVE-DIMENSIONAL array, and neither MATLAB's matrix literal syntax nor an ICore matrix config has a five-dimensional form. So the grid itself cannot cross in either direction, and an exported model would carry the ports, the wiring and no table at all. Reported rather than exported to a counterpart that would come up with an undefined schedule. The Simulink block also defines no SampleTime parameter, measured with set_param

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).

Interpolate Matrix(x,y,z) — blend a stored grid of matrices along THREE axes Y = trilinear blend of the eight matrices around (kx,fx, ky,fy, kz,fz) per axis: lo = clamp(floor(k), 0, P-1), hi = clamp(floor(k)+1, 0, P-1)

Three scheduling variables, one schedule. The grid, the index rule, every diagnostic and all ten code generators live in ICoreScheduleMatrixBlockBase, shared with the one- and two-axis siblings; this file is what is genuinely this block's: its axis count, its ports, its configs, its description, its icon and its Simulink entry.

MEASURED IN R2026a on the real aerolibschedule block, over a 2x3x2 grid of 2x2 matrices whose (1,1) entry is 1 + 10*ix + 100*iy + 1000*iz:

all six inputs 0 -> 1 M[0,0,0] x_k = 1, rest 0 -> 11 -- the THIRD dimension is X y_k = 1, rest 0 -> 101 -- the FOURTH is Y z_k = 1, rest 0 -> 1001 -- the FIFTH is Z x_f = 0.5, rest 0 -> 6 halfway along x y_f = 0.5, rest 0 -> 51 halfway along y z_f = 0.5, rest 0 -> 501 halfway along z (0,0.25, 1,0.5, 2,0.75) -> 2903.5 the full trilinear blend

⚠ THE FOUR IDENTIFYING ROWS WERE MEASURED RATHER THAN ASSUMED. Nothing in the block's dialog says which trailing dimension of the array is which axis, and a permutation of the three is exactly right on the diagonal of a cubic grid and wrong elsewhere -- and right EVERYWHERE on any grid whose axes have equal breakpoint counts, which is the shape a first test is most likely to have.

⚠⚠ AND THE PER-AXIS CLAMP IS THE ONE THIS FAMILY GOT WRONG FIRST. Both slice indices of EVERY axis are clamped independently, so below an axis's table its two indices collapse and the blend goes flat along that axis alone; taking hi as lo + 1 instead blends that axis's first two slices and answers something no corner holds. The account, the measured rows and the sweep that caught it are on the one-axis sibling's banner and in ICoreScheduleMatrixSupport.h. After the fix, 150 samples against the real block over this grid agree to a worst 7.1e-15.

⚠ THE EXPORTED BODY IS THIS BLOCK'S ONE REAL COST. (Px+1)(Py+1)(Pz+1) branches per output entry, each carrying eight constants folded into a nested blend. The default configuration is deliberately the smallest grid that blends along all three axes.

Algebraic and stateless. No state space -- see the header.

Sample results#

Interpolate Matrix XYZ — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sampleInterpolate Matrix XYZ — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample05012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [2x2] entry 0
tin ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0 [2x2] entry 0
0-2-2-2[1, 0, 0, 1]
0.40.50.50.5[4.5, 0, 0, 4.5]
0.8-2-2-2[1, 0, 0, 1]
1.20.50.50.5[4.5, 0, 0, 4.5]
1.6-2-2-2[1, 0, 0, 1]
20.50.50.5[4.5, 0, 0, 4.5]
2.4-2-2-2[1, 0, 0, 1]
2.80.50.50.5[4.5, 0, 0, 4.5]
3.2-2-2-2[1, 0, 0, 1]
3.60.50.50.5[4.5, 0, 0, 4.5]
4-2-2-2[1, 0, 0, 1]
4.40.50.50.5[4.5, 0, 0, 4.5]
4.8-2-2-2[1, 0, 0, 1]
5.20.50.50.5[4.5, 0, 0, 4.5]

Every 4th of 60 samples, from the table stimulus.

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)1 … 8
rampRamp: slope 1 from t = 01 … 8
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias1 … 7.997
stepStep: 0 -> 1 at t = 1 s1 … 8

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 acb91cb2cdfb90f6fc9d13f8bab94cd95d7dd9d5 · produced by docsSample --out <folder> --blocks Interpolate_Matrix_X Interpolate_Matrix_XY Interpolate_Matrix_XYZ --steps 60 · data docs/generated/samples/Control_Systems__Gain_Scheduling__Interpolate_Matrix_XYZ.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).