Descriptor State Space — Control Systems/Continues
Control_Systems/Continues/Descriptor_State_Space · 1 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.
Descriptor State Space
Control Systems / Continues
A continuous-time linear system in descriptor (generalized, implicit) form, where a mass matrix E multiplies the derivative:
E·dx/dt = A·x + B·u
y = C·x + D·u
with n states, m inputs and p outputs, so E and A are [n,n], B is [n,m], C is [p,n] and D is [p,m]. The block solves the mass matrix away once, and runs the equivalent explicit system dx/dt = (E\A)·x + (E\B)·u. With E = I it is exactly the State Space block.
Ports
- Input – the input vector u, [m,1], sized from the B and D column count.
- Output – the output vector y, [p,1], sized from C's row count.
Parameters
- E – the mass matrix, [n,n]. It must be square and nonsingular; see the note below on why a singular E is refused rather than approximated.
- A, B, C, D – the system matrices. Their dimensions must agree with each other, with E, and with the connected input; a mismatch stops the run with a message naming the block.
- Initial State Vector – x at the start of the run, [n,1]. This is the state itself, not E·x.
- 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. A deployable target runs a discrete model, so the export carries the reduced system discretized by the run's method, and the generated code matches the in-app simulation. E is solved away at export time – the generated core carries the reduced A and B as constants and performs no matrix inversion at run time, so a descriptor block costs a target exactly what a plain state space costs.
Simulink bridge
Import and export, mapped to
simulink/Continuous/Descriptor State-Space. "E", "A", "B", "C" and "D" to
E, A, B, C and D;
"Initial State Vector" to InitialCondition – note the
parameter is not called X0 here, as it is on the plain
State-Space block. "Sampling Time (s)" does NOT cross: this Simulink block
defines no SampleTime parameter, so the rate stays on the ICore side
and an explicitly set one is reported rather than written. The solver-tuning
parameters DirectFeedthrough, LinearizeToSparse,
ParameterTunability, AbsoluteTolerance and
ContinuousStateAttributes have no ICore counterpart and are left at
their Simulink defaults.
Notes
- Stateful and continuous: the solver integrates the reduced state between steps.
- E must be nonsingular. With a singular E the system is a genuine
differential-algebraic equation – part of the state is fixed by algebraic
constraints instead of being integrated – and it needs a DAE solver.
Simulink itself refuses
ode4/ode45on this block and demandsode15s,ode23torode14x. ICore's solver integrates ODEs, so a singular E is reported rather than quietly approximated into a system the user did not write. - Being linear, the reduced block is directly usable by the model reduction and linear-analysis commands.
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Continues/Descriptor_State_Space |
| family | Control_Systems/Continues |
| solver environment class | ICoreBlock_0_Control_Systems_1_Continues_2_Descriptor_State_Space |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Continues/Descriptor_State_Space/ICoreBlock_0_Control_Systems_1_Continues_2_Descriptor_State_Space.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Control_Systems/Continues/Descriptor_State_Space/ICoreBlock_0_Control_Systems_1_Continues_2_Descriptor_State_Space.h |
| default size on canvas | 140 × 90 px |
| ports at insert | 1 in, 1 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 | — |
| 2 | 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 |
|---|---|---|
E | [1 0; 0 1] | E |
A | [0 1;-1 -1] | A |
B | [0; 1] | B |
C | [1 0] | C |
D | [0] | D |
Initial State Vector | [0; 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 | simulink/Continuous/Descriptor State-Space |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
E | E | passes through |
A | A | passes through |
B | B | passes through |
C | C | passes through |
D | D | passes through |
Initial State Vector | InitialCondition | passes through |
Caveat (shown to the user): the block runs at the surrounding Simulink rate; "Sampling Time (s)" does not cross. ICore requires a nonsingular E and integrates the reduced explicit system, so a singular E - a true DAE, which Simulink runs only under ode15s/ode23t/ode14x - does not cross either and is reported instead
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).
Descriptor State Space block — E*dx/dt = A*x + B*u, y = C*x + D*u The descriptor (generalized / implicit) form puts a mass matrix E in front of the derivative. ICore carries it as the EXPLICIT system it is equivalent to whenever E is invertible: dx/dt = (E\A) x + (E\B) u, y = C x + D u and everything downstream — the RK solver, discretization, model reduction, all ten code generators — sees only that explicit pair. E is reduced away exactly once, in loadBlockConfig(), so no target ever has to carry a matrix solve.
WHY E MUST BE NONSINGULAR. With singular E the system is a true differential-ALGEBRAIC equation: part of the state is pinned by algebraic constraints rather than integrated, and it needs a DAE solver (Simulink itself refuses ode4/ode45 on this block and demands ode15s/ode23t/ode14x). ICore's solver integrates ODEs, so a singular E is REPORTED at verifyInitializedPortSignals() rather than silently producing a system that is not the one the user wrote. With E = I the block is exactly the plain State Space block.
Verified against Simulink R2026a: the descriptor block under ode14x and a State-Space block carrying E\A and E\B under the same solver agree to 1.5e-14 over a 500-sample run, which is what licenses the reduction above.
Simulation: identical to the plain State Space block once reduced — compute_f/compute_h run the products on the continuous SS, the discrete pair runs them on the discretized SS.
Code export: targets cannot integrate an ODE, so every generator realizes the DISCRETIZED recursion y[k] = C x[k] + D u[k], x[k+1] = A x[k] + B u[k] with A,B already the reduced and discretized pair. See ssDiscreteExport() and the per-language sections below.
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.008893 … 0.05458 |
ramp | Ramp: slope 1 from t = 0 | 0 … 4.847 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.3041 … 0.4966 |
table | Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample | -0.162 … 0.4821 |
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__Continues__Descriptor_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).