A B C D z DiscreteStateSpace DiscreteStateSpace Icon

DiscreteStateSpace

Discrete-time linear state-space system with operating point support.

Implements the standard discrete-time, linear, time-invariant state-space system

\[x(k+1) = A x(k) + B (u(k) - u_0)\]

\[y(k) = C x(k) + D (u(k) - u_0) + y_0\]

where:

  • A is the system matrix (nx × nx)
  • B is the input matrix (nx × nu)
  • C is the output matrix (ny × nx)
  • D is the feedthrough matrix (ny × nu)
  • x is the state vector (nx × 1)
  • u is the input vector (nu × 1)
  • y is the output vector (ny × 1)
  • u0 is the input operating point
  • y0 is the output operating point

The clock is inherited from the context the component is used in. The output at sample k depends on the input at sample k only through the feedthrough matrix D. The structural parameter with_D controls whether that term is present at all: with with_D = false the system is strictly proper, D is ignored, and the output no longer depends structurally on the current input, so the block can close a loop with a controller acting on the same clock without creating a same-tick algebraic loop (a numerically zero D still creates one).

The initial condition is selected through the initialization enum, using its array-valued variants. InitialStateArray(x0=...) sets the state at the first sample, so the free response (u = u0) follows A^k x0. InitialOutputArray(y0=...) instead selects the initial state so that the first output equals the requested vector; the remaining state freedom (wide C, ny < nx) zeroes as many initial output differences as possible, assuming the input is held constant at its first sample. The requested initial output is matched exactly whenever C has full row rank, including the feedthrough contribution of the first input sample. For a square invertible C (ny == nx) the state is fully determined. A tall C (ny > nx) is rejected. The scalar variants and SteadyState are not applicable to this MIMO component and raise an error.

Usage

DiscreteComponents.DiscreteStateSpace(A=fill(0.0, nx, nx), B=fill(1.0, nx, nu), C=fill(1.0, ny, nx), D=fill(0.0, ny, nu), u0=fill(0.0, nu), y0=fill(0.0, ny), x_init_q=_discrete_ss_init_q(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0), x_init_P=_discrete_ss_init_P(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0))

Parameters:

NameDescriptionUnitsDefault value
nxDimension of state vector–2
nuNumber of inputs–1
nyNumber of outputs–1
with_DInclude the feedthrough term D*(u - u0) in the output; false makes the system strictly proper and removes the structural dependence of y on the current input–true
initializationInitial-condition specification–DiscreteCom...l(0.0, nx))
ASystem matrix (nx × nx)–fill(0.0, nx, nx)
BInput matrix (nx × nu)–fill(1.0, nx, nu)
COutput matrix (ny × nx)–fill(1.0, ny, nx)
DFeedthrough matrix (ny × nu); ignored when with_D = false–fill(0.0, ny, nu)
u0Input operating point–fill(0.0, nu)
y0Output operating point–fill(0.0, ny)

Connectors

  • u - This connector represents a real signal as an input to a component (RealInput)
  • y - This connector represents a real signal as an output from a component (RealOutput)

Variables

NameDescriptionUnits
xState vector–

Behavior

using DiscreteComponents #hide
using ModelingToolkit #hide
@variables A #hide
@variables B #hide
@variables C #hide
@variables D #hide
@variables u0 #hide
@variables y0 #hide
@named sys = DiscreteComponents.DiscreteStateSpace(A=A, B=B, C=C, D=D, u0=u0, y0=y0) #hide
full_equations(sys) #hide

Source

"""
Discrete-time linear state-space system with operating point support.

Implements the standard discrete-time, linear, time-invariant state-space system

```math
x(k+1) = A x(k) + B (u(k) - u_0)
```
```math
y(k) = C x(k) + D (u(k) - u_0) + y_0
```

where:
- `A` is the system matrix (nx × nx)
- `B` is the input matrix (nx × nu)
- `C` is the output matrix (ny × nx)
- `D` is the feedthrough matrix (ny × nu)
- `x` is the state vector (nx × 1)
- `u` is the input vector (nu × 1)
- `y` is the output vector (ny × 1)
- `u0` is the input operating point
- `y0` is the output operating point

The clock is inherited from the context the component is used in. The output at
sample `k` depends on the input at sample `k` only through the feedthrough matrix
`D`. The structural parameter `with_D` controls whether that term is present at all:
with `with_D = false` the system is strictly proper, `D` is ignored, and the output no
longer depends structurally on the current input, so the block can close a loop with a
controller acting on the same clock without creating a same-tick algebraic loop (a
numerically zero `D` still creates one).

The initial condition is selected through the `initialization` enum, using its
array-valued variants. `InitialStateArray(x0=...)` sets the state at the first sample,
so the free response (`u = u0`) follows `A^k x0`. `InitialOutputArray(y0=...)` instead
selects the initial state so that the first output equals the requested vector; the
remaining state freedom (wide `C`, `ny < nx`) zeroes as many initial output differences
as possible, assuming the input is held constant at its first sample. The requested
initial output is matched exactly whenever `C` has full row rank, including the
feedthrough contribution of the first input sample. For a square invertible `C`
(`ny == nx`) the state is fully determined. A tall `C` (`ny > nx`) is rejected. The
scalar variants and `SteadyState` are not applicable to this MIMO component and raise
an error.
"""
component DiscreteStateSpace@[input clk extends Discrete]
  "Input connectors"
  u = [RealInput@[clk]() for i in 1:nu] {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Output connectors"
  y = [RealOutput@[clk]() for i in 1:ny] {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Dimension of state vector"
  structural parameter nx::Integer = 2
  "Number of inputs"
  structural parameter nu::Integer = 1
  "Number of outputs"
  structural parameter ny::Integer = 1
  "System matrix (nx × nx)"
  parameter A::Real[nx, nx] = fill(0.0, nx, nx)
  "Input matrix (nx × nu)"
  parameter B::Real[nx, nu] = fill(1.0, nx, nu)
  "Output matrix (ny × nx)"
  parameter C::Real[ny, nx] = fill(1.0, ny, nx)
  "Include the feedthrough term D*(u - u0) in the output; false makes the system strictly proper and removes the structural dependence of y on the current input"
  structural parameter with_D::Boolean = true
  "Feedthrough matrix (ny × nu); ignored when with_D = false"
  parameter D::Real[ny, nu] = fill(0.0, ny, nu)
  "Initial-condition specification"
  structural parameter initialization::InitialCondition = DiscreteComponents.InitialCondition.InitialStateArray(x0 = fill(0.0, nx))
  "Input operating point"
  parameter u0::Real[nu] = fill(0.0, nu)
  "Output operating point"
  parameter y0::Real[ny] = fill(0.0, ny)
  "Constant part of the affine initial-state split x_init = x_init_q + x_init_P*(u - u0)"
  final parameter x_init_q::Real[nx] = _discrete_ss_init_q(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0)
  "Input-linear part of the affine initial-state split x_init = x_init_q + x_init_P*(u - u0)"
  final parameter x_init_P::Real[nx, nu] = _discrete_ss_init_P(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0)
  "State vector"
  variable x::Real[nx]
relations
  "State update: x(k+1) = A*x(k) + B*(u(k) - u0)"
  x@clk = A * x@(clk-1) + B * (u@clk - u0)
  if with_D
    # Output: y(k) = C*x(k) + D*(u(k) - u0) + y0
    y@clk = C * x@(clk-1) + D * (u@clk - u0) + y0
  else
    # Strictly proper output: y(k) = C*x(k) + y0
    y@clk = C * x@(clk-1) + y0
  end
  switch initialization
    case InitialOutputArray
      initial x@(clk-1) = _ss_scalarize(x_init_q + x_init_P * (u@clk - u0))
    case InitialStateArray
      initial x@(clk-1) = x_init_q
  end
metadata {
  "Dyad": {"icons": {"default": "dyad://DiscreteComponents/DiscreteStateSpace.svg"}}
}
end
Flattened Source
"""
Discrete-time linear state-space system with operating point support.

Implements the standard discrete-time, linear, time-invariant state-space system

```math
x(k+1) = A x(k) + B (u(k) - u_0)
```
```math
y(k) = C x(k) + D (u(k) - u_0) + y_0
```

where:
- `A` is the system matrix (nx × nx)
- `B` is the input matrix (nx × nu)
- `C` is the output matrix (ny × nx)
- `D` is the feedthrough matrix (ny × nu)
- `x` is the state vector (nx × 1)
- `u` is the input vector (nu × 1)
- `y` is the output vector (ny × 1)
- `u0` is the input operating point
- `y0` is the output operating point

The clock is inherited from the context the component is used in. The output at
sample `k` depends on the input at sample `k` only through the feedthrough matrix
`D`. The structural parameter `with_D` controls whether that term is present at all:
with `with_D = false` the system is strictly proper, `D` is ignored, and the output no
longer depends structurally on the current input, so the block can close a loop with a
controller acting on the same clock without creating a same-tick algebraic loop (a
numerically zero `D` still creates one).

The initial condition is selected through the `initialization` enum, using its
array-valued variants. `InitialStateArray(x0=...)` sets the state at the first sample,
so the free response (`u = u0`) follows `A^k x0`. `InitialOutputArray(y0=...)` instead
selects the initial state so that the first output equals the requested vector; the
remaining state freedom (wide `C`, `ny < nx`) zeroes as many initial output differences
as possible, assuming the input is held constant at its first sample. The requested
initial output is matched exactly whenever `C` has full row rank, including the
feedthrough contribution of the first input sample. For a square invertible `C`
(`ny == nx`) the state is fully determined. A tall `C` (`ny > nx`) is rejected. The
scalar variants and `SteadyState` are not applicable to this MIMO component and raise
an error.
"""
component DiscreteStateSpace
  "Input connectors"
  u = [RealInput@[clk]() for i in 1:nu] {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Output connectors"
  y = [RealOutput@[clk]() for i in 1:ny] {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Dimension of state vector"
  structural parameter nx::Integer = 2
  "Number of inputs"
  structural parameter nu::Integer = 1
  "Number of outputs"
  structural parameter ny::Integer = 1
  "System matrix (nx × nx)"
  parameter A::Real[nx, nx] = fill(0.0, nx, nx)
  "Input matrix (nx × nu)"
  parameter B::Real[nx, nu] = fill(1.0, nx, nu)
  "Output matrix (ny × nx)"
  parameter C::Real[ny, nx] = fill(1.0, ny, nx)
  "Include the feedthrough term D*(u - u0) in the output; false makes the system strictly proper and removes the structural dependence of y on the current input"
  structural parameter with_D::Boolean = true
  "Feedthrough matrix (ny × nu); ignored when with_D = false"
  parameter D::Real[ny, nu] = fill(0.0, ny, nu)
  "Initial-condition specification"
  structural parameter initialization::InitialCondition = DiscreteComponents.InitialCondition.InitialStateArray(x0 = fill(0.0, nx))
  "Input operating point"
  parameter u0::Real[nu] = fill(0.0, nu)
  "Output operating point"
  parameter y0::Real[ny] = fill(0.0, ny)
  "Constant part of the affine initial-state split x_init = x_init_q + x_init_P*(u - u0)"
  final parameter x_init_q::Real[nx] = _discrete_ss_init_q(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0)
  "Input-linear part of the affine initial-state split x_init = x_init_q + x_init_P*(u - u0)"
  final parameter x_init_P::Real[nx, nu] = _discrete_ss_init_P(initialization, nx, nu, A, B, C, _ss_feedthrough(with_D, D), y0)
  "State vector"
  variable x::Real[nx]
relations
  "State update: x(k+1) = A*x(k) + B*(u(k) - u0)"
  x@clk = A * x@(clk-1) + B * (u@clk - u0)
  if with_D
    # Output: y(k) = C*x(k) + D*(u(k) - u0) + y0
    y@clk = C * x@(clk-1) + D * (u@clk - u0) + y0
  else
    # Strictly proper output: y(k) = C*x(k) + y0
    y@clk = C * x@(clk-1) + y0
  end
  switch initialization
    case InitialOutputArray
      initial x@(clk-1) = _ss_scalarize(x_init_q + x_init_P * (u@clk - u0))
    case InitialStateArray
      initial x@(clk-1) = x_init_q
  end
metadata {
  "Dyad": {"icons": {"default": "dyad://DiscreteComponents/DiscreteStateSpace.svg"}}
}
end


Test Cases

No test cases defined.

  • Examples
  • Experiments
  • Analyses