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

Interpolate Matrix XY — Control Systems/Gain Scheduling

Control_Systems/Gain_Scheduling/Interpolate_Matrix_XY · 4 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(x,y)

Control Systems / Gain Scheduling

Blends a stored grid of matrices along two axes and answers a single matrix: the bilinear blend of the four matrices around the position (kx, fx, ky, fy), weighted (1−fx)(1−fy), fx(1−fy), (1−fx)fy and fxfy. It is the two-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.

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]. Each axis clamps on its own, so the blend can be flat along one axis while still interpolating along the other.
  • y_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 and x varying fastest: the matrix at (ix, iy) occupies row block ix + Px·iy, so the table is Px·Py·R rows by C columns. A matrix config cannot hold a four-dimensional array, so this is the one spelling available. From a MATLAB array M of size [R C Px Py] the config is reshape(permute(M,[1 3 4 2]), R*Px*Py, C), whose column-major walk over (row, ix, iy) 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, and it must divide the number of slices the table holds. Py 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 pair of intervals, each carrying its four 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. The emitted body grows as (Px+1)·(Py+1)·R·C – each axis has one branch per interval plus one for each of its two flat regions – which is the one thing to watch on this block: a 10×10 grid of 4×4 matrices is about 1900 branches per language.

The three HDL targets are not simulation-only: each branch is three multiplies and three 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) in the Aerospace Blockset and it computes the same bilinear 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 four-dimensional array, and neither MATLAB's matrix literal syntax nor an ICore matrix config has a four-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 and the fourth is y, measured rather than inferred. Reading them the other way round gives a block that is exactly right on the diagonal of a square grid and wrong elsewhere – and right everywhere on any grid whose two axes have the same breakpoint count, which is the shape a first test is most likely to have.
  • Each index truncates, its two slice indices clamp separately, and neither fraction is clamped. Same rules as the one-axis block, applied per axis and independently – so the blend can be flat along x and still interpolating along y. 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 four inputs are scalars. One index and one fraction per axis select ONE matrix out of the grid.
  • For one or three scheduling variables, use Interpolate Matrix(x) or Interpolate Matrix(x,y,z).

Code facts#

FactValue
registered typeControl_Systems/Gain_Scheduling/Interpolate_Matrix_XY
familyControl_Systems/Gain_Scheduling
solver environment classICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XY
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Gain_Scheduling/Interpolate_Matrix_XY/ICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XY.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Gain_Scheduling/Interpolate_Matrix_XY/ICoreBlock_0_Control_Systems_1_Gain_Scheduling_2_Interpolate_Matrix_XY.h
default size on canvas120 × 100 px
ports at insert4 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
5outICoreDouble—

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 Table[1 0; 0 1; 2 0; 0 2; 3 0; 0 3; 4 0; 0 4]—
Matrix Rows2—
X 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) computes the same bilinear blend -- this block's index rules and its axis-to-dimension order were measured off it -- but its ONE parameter, matrix, is a FOUR-DIMENSIONAL array, and neither MATLAB's matrix literal syntax nor an ICore matrix config has a four-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) — blend a stored grid of matrices along TWO axes Y = bilinear blend of M[lo_x,lo_y], M[hi_x,lo_y], M[lo_x,hi_y], M[hi_x,hi_y] per axis: lo = clamp(floor(k), 0, P-1), hi = clamp(floor(k)+1, 0, P-1) the fraction across each interval arrives on its own port

Two scheduling variables, one schedule. The grid, the index rule, every diagnostic and all ten code generators live in ICoreScheduleMatrixBlockBase, shared with the one- and three-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 grid of 2x2 matrices whose (1,1) entry is 1 + 10*ix + 100*iy:

x_k=0 x_f=0 y_k=0 y_f=0 -> 1 M[0,0] x_k=1 x_f=0 y_k=0 y_f=0 -> 11 M[1,0] -- the THIRD dimension is X x_k=0 x_f=0 y_k=1 y_f=0 -> 101 M[0,1] -- the FOURTH is Y x_k=0 x_f=0.5 y_k=0 y_f=0 -> 6 halfway along x x_k=0 x_f=0 y_k=0 y_f=0.5 -> 51 halfway along y x_k=1 x_f=0.25 y_k=2 y_f=0.75 -> 288.5 the full bilinear blend

⚠ THE SECOND AND THIRD ROWS ARE WHY THEY WERE MEASURED RATHER THAN ASSUMED. Nothing in the block's dialog says which trailing dimension of the array is which axis, and getting the two the wrong way round produces a block that is exactly right on the diagonal of a square grid and wrong everywhere else -- including right on any grid whose two axes happen to have the same breakpoint count, which is the shape a first test is most likely to use.

⚠ AND THE LAST ROW IS THE ONE THAT DISTINGUISHES A BLEND FROM A NEAREST-NEIGHBOUR PICK. All four corners contribute: 0.1875, 0.0625, 0.5625 and 0.1875 of them, which sums to 288.5 and which no single corner is near.

⚠⚠ THE PER-AXIS CLAMP IS THE ONE THIS FAMILY GOT WRONG FIRST, and it is worse here than on one axis because it can be wrong on one axis while being right on the other. 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 it -- taking hi as lo + 1 instead blends the first two slices of that axis and answers something no corner holds. The full 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 a 3x4 grid -- both clamped regions on both axes, every interval, fractions well outside [0,1] -- agree to a worst 3.6e-15.

Sample results#

Interpolate Matrix XY — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sampleInterpolate Matrix XY — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-2024012345t (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[2.5, 0, 0, 2.5]
0.8-2-2-2[1, 0, 0, 1]
1.20.50.50.5[2.5, 0, 0, 2.5]
1.6-2-2-2[1, 0, 0, 1]
20.50.50.5[2.5, 0, 0, 2.5]
2.4-2-2-2[1, 0, 0, 1]
2.80.50.50.5[2.5, 0, 0, 2.5]
3.2-2-2-2[1, 0, 0, 1]
3.60.50.50.5[2.5, 0, 0, 2.5]
4-2-2-2[1, 0, 0, 1]
4.40.50.50.5[2.5, 0, 0, 2.5]
4.8-2-2-2[1, 0, 0, 1]
5.20.50.50.5[2.5, 0, 0, 2.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 … 4
rampRamp: slope 1 from t = 01 … 4
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias1 … 3.999
stepStep: 0 -> 1 at t = 1 s1 … 4

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