Discrete Varying State Space — Control Systems/Linear Parameter Varying
Control_Systems/Linear_Parameter_Varying/Discrete_Varying_State_Space · 5 input / 3 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.
Discrete Varying State Space
Control Systems / Linear Parameter Varying
A discrete state-space system whose matrices are signals, not settings:
x[k+1] = A[k]·x[k] + B[k]·u[k]
y[k] = C[k]·x[k] + D[k]·u[k]
A, B, C and D are read afresh on every sample, so a scheduling signal can move the system while it runs – the linear parameter-varying (LPV) realization. At any one instant the block is exactly the ordinary Discrete State Space; across instants it is not, which is what the varying matrices buy and what the Notes below say the cost of is.
Ports
- u – the input vector, [m,1].
- A – the state matrix, [n,n]. Its size is what defines n: the state count is taken from this port, not from any parameter.
- B – the input matrix, [n,m].
- C – the output matrix, [p,n].
- D – the feedthrough matrix, [p,m].
- y – the output vector, [p,1], from the current state.
- x – the current state x[k], [n,1].
- x+ – the next state x[k+1], [n,1], the same value this block will use itself on the following sample.
The five sizes must agree with one another exactly – A square, B and D sharing u's width m, C and D sharing y's height p – and a disagreement is reported with the two offending shapes once the model's port sizes have settled. Nothing is scalar-expanded here: these are matrices with a meaning, and a silent expansion would hide a mis-wired schedule.
Parameters
- Initial State Vector – x[0]. A scalar is used for every
state, which is how Simulink's own initial condition behaves and the only form
that can be written before n is known; an [n,1] vector sets each state
separately. Defaults to
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.
Nothing about the system is baked into the generated core except its dimensions: n, m and p are fixed at export time, so every loop is statically sized, while A, B, C and D are read from their input signals on every step exactly as they are in simulation. There is consequently no tunable parameter on the exported core – retuning is what the coefficient ports are for, and they remain live on the deployed core. Only the initial state is emitted as a constant, since it is consumed once before the first sample.
The three HDL targets carry the recursion in Q16.16 fixed point and are fully synthesizable. Note that a coefficient arriving on a port is already quantized to one Q16.16 quantum (1.5×10-5) before the block sees it, so a schedule that relies on finer coefficient resolution than that will not survive an HDL export, however exactly the software targets reproduce it.
Simulink bridge
Import and export, mapped to cstblocks/Linear Parameter Varying/Discrete
Varying State Space, with "Initial State Vector" going to
InitialCondition as a pass-through value.
The rate crosses under a different name. This Simulink block calls its
rate parameter Ts, not SampleTime, so the catalog entry
names it explicitly. Emitting the usual name would not degrade gracefully: a
set_param for a parameter a block does not define is a hard MATLAB
error that aborts the entire generated script.
Four Simulink parameters are always implied rather than offered as a choice,
because each of them moves ports and no config value here can add or
remove one: Feedthrough = on (the D input),
OutputX = on and OutputDX = on (the x and
x+ outputs), and InitialConditionSource = internal. The four
external-initial-value inputs (InputX0, InputDX0,
InputU0, InputY0) stay off for the same
reason.
Notes
- Discrete only, and stateful: the state is the [n,1] vector x.
- No state space, deliberately. The block is linear at every instant but time-varying overall, so there is no single A/B/C/D to hand to model reduction or the linear-analysis commands, and they report it as unmergeable. That is the correct answer rather than a limitation: a state space seeded from whatever the coefficient ports happened to carry would be a snapshot, and merging it into a neighbouring plant would produce a model that is wrong the moment the schedule moves. For a system that genuinely does not vary, use Discrete State Space, which carries a real one.
- x+ is not a preview of a re-read. The x+ output is the same value the block stores, computed from the current state and the current coefficients, so feeding it back into a schedule cannot disagree with what the block does next.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Linear_Parameter_Varying/Discrete_Varying_State_Space |
| family | Control_Systems/Linear_Parameter_Varying |
| solver environment class | ICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Discrete_Varying_State_Space |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Linear_Parameter_Varying/Discrete_Varying_State_Space/ICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Discrete_Varying_State_Space.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Linear_Parameter_Varying/Discrete_Varying_State_Space/ICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Discrete_Varying_State_Space.h |
| default size on canvas | 150 × 120 px |
| ports at insert | 5 in, 3 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 | in | ICoreDouble | A |
| 3 | in | ICoreDouble | B |
| 4 | in | ICoreDouble | C |
| 5 | in | ICoreDouble | D |
| 6 | out | ICoreDouble | y |
| 7 | out | ICoreDouble | x |
| 8 | out | ICoreDouble | x+ |
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 |
|---|---|---|
Initial State Vector | 0 | InitialCondition |
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 | cstblocks/Linear Parameter Varying/Discrete Varying State Space |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
| rate parameter name | Ts |
| always set | Feedthrough = on, OutputX = on, OutputDX = on, InitialConditionSource = internal, InputX0 = off, InputDX0 = off, InputU0 = off, InputY0 = off |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
Initial State Vector | InitialCondition | passes through |
Caveat (shown to the user): the coefficient matrices are signals on both sides, so nothing about them is a parameter to carry; the four external initial-value inputs (InputX0, InputDX0, InputU0, InputY0) are not supported, since each adds an input port in Simulink and no config value here can add or remove a port
Catalog contract: src/ICoreSDK/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h
Description vs code#
The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:
B01 port label(s) this tool cannot resolve
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).
Discrete Varying State Space block -- the discrete LPV realization x[k+1] = A[k] x[k] + B[k] u[k], y[k] = C[k] x[k] + D[k] u[k], where A, B, C and D arrive on INPUT PORTS instead of living in config. Five inputs (u, A, B, C, D), three outputs (y, x[k], x[k+1]), matching cstblocks/Linear Parameter Varying/Discrete Varying State Space port for port and label for label.
Why this is not just Discrete State Space with a different config The DIMENSIONS are fixed at build time and the VALUES are not. n, m and p come off the coefficient ports once the port-size convergence loop settles, so every generated loop is still statically sized -- but the coefficients themselves are read fresh on every step, which is the whole difference from Discrete State Space and the reason none of the ten generators can bake a literal into the arithmetic.
That also decides the state space question: see the header. The block is linear at every instant and time-varying overall, so it carries NO ICoreStateSpace at all rather than a snapshot that model reduction would merge as if it were the system.
Code export (all ten targets) Structurally identical to the in-app simulation, and to Discrete State Space's exports except that A/B/C/D are read from the input signals rather than emitted as constants: y[k] = C x[k] + D u[k] (output from the CURRENT state) x[k+1] = A x[k] + B u[k] (state update, from that same x[k]) x is the only persistent state, seeded from "Initial State Vector".
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.695e24 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.004824 … 5.322 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -53 … 54 |
Plotted: step — Step: 0 -> 1 at t = 1 s
Category dynamic · sample time 0.1 · 60 steps · commit ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Control_Systems__Linear_Parameter_Varying__Discrete_Varying_State_Space.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).