Nonlinear.PadeDelay
Padé approximation of a fixed time delay.
Approximates y(t) = u(t - delayTime) by a rational transfer function whose Taylor expansion matches exp(-delayTime*s) up to order n + m, realized in controller canonical form as an n-state linear ODE:
Being a linear ODE, the block is continuous, differentiable, and linearizable — unlike a true history-based delay. Higher n gives a sharper approximation over a wider input-frequency range; m = n yields direct feedthrough (the characteristic initial undershoot).
The balance flag selects the state realization:
balance = true(default): a balancing state transformation (balance_abc) rescales the companion form to keep the system matrix well-conditioned. Highly recommended — the textbook form has coefficients spanning1 … (1/delayTime)^nand becomes numerically unreliable for largenor smalldelayTime.balance = false: the textbook controller canonical form (s = ones).
Input→output behavior is identical for both; balance only changes the internal state coordinates and their conditioning.
The coefficients b[:], a[:] are chosen so the Taylor expansion of the delay exp(-delayTime*s) around s = 0 matches b(s)/a(s) up to order n + m. States are initialized in steady state (der(x) = 0), so the block starts in equilibrium with the input at t = 0.
Reference: Otto Föllinger, Regelungstechnik, 8th ed., ch. 11.9, pp. 412–414, Hüthig Verlag Heidelberg, 1994.
Mirrors Modelica.Blocks.Nonlinear.PadeDelay.
Deviations from MSL:
delayTimeis a structural parameter here (fixed at compile time), because the Padé coefficients are computed from it at construction.Default is
balance = true(MSL defaultsfalseonly for backward compatibility, but documentstrueas strongly recommended).
This component extends from BlockComponents.Interfaces.SISO
Usage
BlockComponents.Nonlinear.PadeDelay(a1=BlockComponents.pade_a1(delayTime, n, m, balance), b11=BlockComponents.pade_b11(delayTime, n, m, balance), c_coeff=BlockComponents.pade_c(delayTime, n, m, balance), d_coeff=BlockComponents.pade_d(delayTime, n, m, balance), s=BlockComponents.pade_s(delayTime, n, m, balance))
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
n | Order of the Padé denominator (number of states) | – | 1 |
m | Order of the Padé numerator (usually m = n, or m = n-1) | – | n |
delayTime | Delay time of output with respect to input signal | s | 1.0 |
balance | Use a balanced state realization for better numerical conditioning | – | true |
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
| Name | Description | Units |
|---|---|---|
x | Controller-canonical-form states | – |
ax_sum | Partial sums for the dot product a1·x | – |
cy_sum | Partial sums for the dot product c·x | – |
Behavior
Source
"""
Padé approximation of a fixed time delay.
Approximates `y(t) = u(t - delayTime)` by a rational transfer function whose
Taylor expansion matches `exp(-delayTime*s)` up to order `n + m`, realized in
controller canonical form as an `n`-state linear ODE:
```math
\\dot{x}_1 = a_1 \\cdot x + b_{11}\\,u, \\quad
\\dot{x}_j = s_{j-1}\\,x_{j-1}\\ (j \\ge 2), \\quad
y = c \\cdot x + d\\,u
```
Being a linear ODE, the block is continuous, differentiable, and linearizable —
unlike a true history-based delay. Higher `n` gives a sharper approximation over
a wider input-frequency range; `m = n` yields direct feedthrough (the
characteristic initial undershoot).
The `balance` flag selects the state realization:
- `balance = true` (default): a balancing state transformation (`balance_abc`)
rescales the companion form to keep the system matrix well-conditioned. Highly
recommended — the textbook form has coefficients spanning `1 … (1/delayTime)^n`
and becomes numerically unreliable for large `n` or small `delayTime`.
- `balance = false`: the textbook controller canonical form (`s = ones`).
Input→output behavior is identical for both; `balance` only changes the internal
state coordinates and their conditioning.
The coefficients `b[:]`, `a[:]` are chosen so the Taylor expansion of the delay
`exp(-delayTime*s)` around `s = 0` matches `b(s)/a(s)` up to order `n + m`. States
are initialized in steady state (`der(x) = 0`), so the block starts in equilibrium
with the input at `t = 0`.
Reference: Otto Föllinger, *Regelungstechnik*, 8th ed., ch. 11.9, pp. 412–414,
Hüthig Verlag Heidelberg, 1994.
Mirrors `Modelica.Blocks.Nonlinear.PadeDelay`.
Deviations from MSL:
- `delayTime` is a structural parameter here (fixed at compile time), because the
Padé coefficients are computed from it at construction.
- Default is `balance = true` (MSL defaults `false` only for backward
compatibility, but documents `true` as strongly recommended).
"""
component PadeDelay
extends BlockComponents.Interfaces.SISO
"Order of the Padé denominator (number of states)"
structural parameter n::Integer = 1
"Order of the Padé numerator (usually m = n, or m = n-1)"
structural parameter m::Integer = n
"Delay time of output with respect to input signal"
structural parameter delayTime::Time = 1.0
"Use a balanced state realization for better numerical conditioning"
structural parameter balance::Boolean = true
"First row of the system matrix A"
final parameter a1::Real[n] = BlockComponents.pade_a1(delayTime, n, m, balance)
"Input coupling B[1]"
final parameter b11::Real = BlockComponents.pade_b11(delayTime, n, m, balance)
"Output coupling row C"
final parameter c_coeff::Real[n] = BlockComponents.pade_c(delayTime, n, m, balance)
"Direct feedthrough coefficient d (nonzero only when m = n)"
final parameter d_coeff::Real = BlockComponents.pade_d(delayTime, n, m, balance)
"Sub-diagonal state scalings (entry n is unused padding)"
final parameter s::Real[n] = BlockComponents.pade_s(delayTime, n, m, balance)
"Controller-canonical-form states"
variable x::Real[n]
"Partial sums for the dot product a1·x"
variable ax_sum::Real[n]
"Partial sums for the dot product c·x"
variable cy_sum::Real[n]
relations
# Steady-state initialization (der(x) = 0), matching MSL's balance=true init:
# the block starts in equilibrium with the input value at t = 0.
for j in 1:n
initial der(x[j]) = 0.0
end
# Dot product a1·x via a running partial sum
ax_sum[1] = a1[1] * x[1]
for j in 2:n
ax_sum[j] = ax_sum[j - 1] + a1[j] * x[j]
end
# First state (dense feedback row): der(x[1]) = a1·x + b11·u
der(x[1]) = ax_sum[n] + b11 * u
# Scaled integrator chain: der(x[j]) = s[j-1]·x[j-1]
for j in 2:n
der(x[j]) = s[j - 1] * x[j - 1]
end
# Output dot product c·x via a running partial sum
cy_sum[1] = c_coeff[1] * x[1]
for j in 2:n
cy_sum[j] = cy_sum[j - 1] + c_coeff[j] * x[j]
end
# Output: y = c·x + d·u
y = cy_sum[n] + d_coeff * u
metadata {
"Dyad": {
"labels": [{"label": "$(instance)", "x": 500, "y": 1100, "rot": 0}],
"icons": {"default": "dyad://BlockComponents/PadeDelay.svg"}
}
}
endFlattened Source
"""
Padé approximation of a fixed time delay.
Approximates `y(t) = u(t - delayTime)` by a rational transfer function whose
Taylor expansion matches `exp(-delayTime*s)` up to order `n + m`, realized in
controller canonical form as an `n`-state linear ODE:
```math
\\dot{x}_1 = a_1 \\cdot x + b_{11}\\,u, \\quad
\\dot{x}_j = s_{j-1}\\,x_{j-1}\\ (j \\ge 2), \\quad
y = c \\cdot x + d\\,u
```
Being a linear ODE, the block is continuous, differentiable, and linearizable —
unlike a true history-based delay. Higher `n` gives a sharper approximation over
a wider input-frequency range; `m = n` yields direct feedthrough (the
characteristic initial undershoot).
The `balance` flag selects the state realization:
- `balance = true` (default): a balancing state transformation (`balance_abc`)
rescales the companion form to keep the system matrix well-conditioned. Highly
recommended — the textbook form has coefficients spanning `1 … (1/delayTime)^n`
and becomes numerically unreliable for large `n` or small `delayTime`.
- `balance = false`: the textbook controller canonical form (`s = ones`).
Input→output behavior is identical for both; `balance` only changes the internal
state coordinates and their conditioning.
The coefficients `b[:]`, `a[:]` are chosen so the Taylor expansion of the delay
`exp(-delayTime*s)` around `s = 0` matches `b(s)/a(s)` up to order `n + m`. States
are initialized in steady state (`der(x) = 0`), so the block starts in equilibrium
with the input at `t = 0`.
Reference: Otto Föllinger, *Regelungstechnik*, 8th ed., ch. 11.9, pp. 412–414,
Hüthig Verlag Heidelberg, 1994.
Mirrors `Modelica.Blocks.Nonlinear.PadeDelay`.
Deviations from MSL:
- `delayTime` is a structural parameter here (fixed at compile time), because the
Padé coefficients are computed from it at construction.
- Default is `balance = true` (MSL defaults `false` only for backward
compatibility, but documents `true` as strongly recommended).
"""
component PadeDelay
"Input signal port"
u = RealInput() {
"Dyad": {
"placement": {
"icon": {"iconName": "input", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0},
"diagram": {"iconName": "input", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0}
}
}
}
"Output signal port"
y = RealOutput() {
"Dyad": {
"placement": {
"icon": {"iconName": "output", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0},
"diagram": {"iconName": "output", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
}
}
}
"Order of the Padé denominator (number of states)"
structural parameter n::Integer = 1
"Order of the Padé numerator (usually m = n, or m = n-1)"
structural parameter m::Integer = n
"Delay time of output with respect to input signal"
structural parameter delayTime::Time = 1.0
"Use a balanced state realization for better numerical conditioning"
structural parameter balance::Boolean = true
"First row of the system matrix A"
final parameter a1::Real[n] = BlockComponents.pade_a1(delayTime, n, m, balance)
"Input coupling B[1]"
final parameter b11::Real = BlockComponents.pade_b11(delayTime, n, m, balance)
"Output coupling row C"
final parameter c_coeff::Real[n] = BlockComponents.pade_c(delayTime, n, m, balance)
"Direct feedthrough coefficient d (nonzero only when m = n)"
final parameter d_coeff::Real = BlockComponents.pade_d(delayTime, n, m, balance)
"Sub-diagonal state scalings (entry n is unused padding)"
final parameter s::Real[n] = BlockComponents.pade_s(delayTime, n, m, balance)
"Controller-canonical-form states"
variable x::Real[n]
"Partial sums for the dot product a1·x"
variable ax_sum::Real[n]
"Partial sums for the dot product c·x"
variable cy_sum::Real[n]
relations
# Steady-state initialization (der(x) = 0), matching MSL's balance=true init:
# the block starts in equilibrium with the input value at t = 0.
for j in 1:n
initial der(x[j]) = 0.0
end
# Dot product a1·x via a running partial sum
ax_sum[1] = a1[1] * x[1]
for j in 2:n
ax_sum[j] = ax_sum[j - 1] + a1[j] * x[j]
end
# First state (dense feedback row): der(x[1]) = a1·x + b11·u
der(x[1]) = ax_sum[n] + b11 * u
# Scaled integrator chain: der(x[j]) = s[j-1]·x[j-1]
for j in 2:n
der(x[j]) = s[j - 1] * x[j - 1]
end
# Output dot product c·x via a running partial sum
cy_sum[1] = c_coeff[1] * x[1]
for j in 2:n
cy_sum[j] = cy_sum[j - 1] + c_coeff[j] * x[j]
end
# Output: y = c·x + d·u
y = cy_sum[n] + d_coeff * u
metadata {
"Dyad": {
"labels": [{"label": "$(instance)", "x": 500, "y": 1100, "rot": 0}],
"icons": {"default": "dyad://BlockComponents/PadeDelay.svg"}
}
}
endTest Cases
No test cases defined.