Generated reference › Varying State Space — Control Systems/Linear Parameter Varying
kind: generated#block#control-systems-linear-parameter-varying

Varying State Space — Control Systems/Linear Parameter Varying

A B C D

Control_Systems/Linear_Parameter_Varying/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.

Varying State Space

Control Systems / Linear Parameter Varying

A continuous state-space system whose matrices are signals, not settings:

dx/dt = A(t)·x + B(t)·u
y = C(t)·x + D(t)·u

A, B, C and D are read afresh at every step, 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 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].
  • dx – the state derivative dx/dt, [n,1] – the same quantity the solver integrates, published so a schedule can see it.

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. It does not cross to Simulink (that block has no rate parameter at all), but it is the step the exported core integrates with – see Code export.

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.

The exported core integrates with forward Euler, x ← x + Ts·(A·x + B·u), at the block's sampling period. This is not a shortcut chosen for simplicity: a system whose A/B/C/D are signals cannot be discretized ahead of time the way the fixed-coefficient blocks are, because the matrices are not known until the step runs. An exact per-step discretization would need a matrix exponential inside the core, which is not something the HDL or PLC targets can carry. The consequence is worth stating plainly: the exported core is first-order accurate in Ts where the in-app simulation runs Runge-Kutta, so the two agree to O(Ts) rather than exactly. Choose a period short against the fastest mode you intend to schedule.

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/Varying State Space, with "Initial State Vector" going to InitialCondition as a pass-through value.

The rate does not cross at all. Unlike its Discrete sibling, which carries a Ts parameter, this block defines no rate parameter of any name – it is continuous and takes its step from the surrounding Simulink solver. "Sampling Time (s)" therefore stays on the ICore side. Emitting either SampleTime or Ts would be a hard set_param 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

  • Continuous and stateful: the state is the [n,1] vector x, integrated by the solver.
  • 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 State Space, which carries a real one.
  • dx is the real derivative, computed from the current state and the current coefficients – the same quantity the solver integrates, not a separately estimated one, so it cannot disagree with the state it produces.

Code facts#

FactValue
registered typeControl_Systems/Linear_Parameter_Varying/Varying_State_Space
familyControl_Systems/Linear_Parameter_Varying
solver environment classICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Varying_State_Space
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Linear_Parameter_Varying/Varying_State_Space/ICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Varying_State_Space.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Linear_Parameter_Varying/Varying_State_Space/ICoreBlock_0_Control_Systems_1_Linear_Parameter_Varying_2_Varying_State_Space.h
default size on canvas150 × 120 px
ports at insert5 in, 3 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleu
2inICoreDoubleA
3inICoreDoubleB
4inICoreDoubleC
5inICoreDoubleD
6outICoreDoubley
7outICoreDoublex
8outICoreDoublex+

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
Initial State Vector0InitialCondition

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::Both
Simulink pathcstblocks/Linear Parameter Varying/Varying State Space
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setFeedthrough = on, OutputX = on, OutputDX = on, InitialConditionSource = internal, InputX0 = off, InputDX0 = off, InputU0 = off, InputY0 = off
ICore configSimulink parameterValue translation
Initial State VectorInitialConditionpasses 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:

  • B0 1 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).

Varying State Space block -- the CONTINUOUS 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/Varying State Space port for port and label for label.

Why this is not just 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 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 the in-app model, integrated with FORWARD EULER because a varying system cannot be pre-discretized (see the description). Like 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#

Varying State Space — Step: 0 -> 1 at t = 1 sVarying State Space — Step: 0 -> 1 at t = 1 s050100012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreDouble-Out-0out ICoreDouble-Out-1out ICoreDouble-Out-2

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)0 … 1.034
rampRamp: slope 1 from t = 00 … 1.461e8
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias-2.054 … 3.389
tableRepeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-79.03 … 126.8

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