DiscretePIDStandard ​
Discrete-time PID controller on standard (ideal) form with anti-windup and set-point weighting.
The controller is implemented on standard form
Simplified:
Detailed:
where e_s = u - v is the saturated error signal, v is the unsaturated control signal and u is the saturated control signal.
An optional feed-forward signal with_ff = true and connecting the u_ff input. Its contribution v before saturation, so it participates in the anti-windup tracking.
The derivative is filtered to allow a maximum gain of
The integrator is discretized using the method specified by Imethod, options include
Imethod = DiscretizationMethod.Forward(default): Corresponding to the transfer function Imethod = DiscretizationMethod.Backward: Corresponding to the transfer function Imethod = DiscretizationMethod.Trapezoidal: Corresponding to the transfer function Â
The derivative is discretized using the method specified by Dmethod, options include
Dmethod = DiscretizationMethod.Forward: Corresponding to the transfer function .    Dmethod = DiscretizationMethod.Backward(default): Corresponding to the transfer function      Dmethod = DiscretizationMethod.Trapezoidal: Corresponding to the transfer function     Â
Anti windup is realized by tracking using the gain
To use the controller in 1DOF mode, i.e., with only the control error as input, connect the error signal to the u_s connector, connect a Constant(; k = 0) to the u_m connector and set wp = wd = 1.
Usage ​
DiscreteComponents.DiscretePIDStandard(K=1, Ti=1, Td=1, Ni=sqrt(max(Td / Ti, 1e-6)), Nd=10, y_max=Inf, y_min=ifelse(y_max > 0, -y_max, -Inf), wp=1, wd=1, k_ff=1)
Parameters: ​
| Name | Description | Units | Default value |
|---|---|---|---|
Imethod | Discretization method for the integrator | – | Discretizat...d.Forward() |
Dmethod | Discretization method for the derivative | – | Discretizat....Backward() |
with_I | Whether or not to include the integral part | – | true |
with_D | Whether or not to include the derivative part | – | true |
with_ff | Whether or not to include the feed-forward input | – | false |
Ts | – | SampleTime() | |
K | Proportional gain | – | 1 |
Ti | Integral time constant (only active if with_I = true) | – | 1 |
Td | Derivative time (only active if with_D = true) | – | 1 |
Ni | Anti-windup gain (only active if with_I = true) | – | sqrt(max(Td / Ti, 1e-6)) |
Nd | Maximum derivative gain (only active if with_D = true). Typically set to 10-100. | – | 10 |
y_max | Maximum output | – | Inf |
y_min | Minimum output | – | ifelse(y_ma..._max, -Inf) |
wp | Set-point weighting in the proportional part. Set to 0 to prevent step changes in the output due to step changes in the reference. | – | 1 |
wd | Set-point weighting in the derivative part. Set to 0 to prevent very large impulsive changes in the output due to step changes in the reference. | – | 1 |
k_ff | Gain of the feed-forward input (only active if with_ff = true) | – | 1 |
Connectors ​
u_s- This connector represents a real signal as an input to a component (RealInput)u_m- This connector represents a real signal as an input to a component (RealInput)u_ff- 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 |
|---|---|---|
I | State of Integrator | – |
D | State of filtered derivative | – |
wde | Setpoint-weighted error for derivative | – |
uff | Feed-forward contribution to the control signal | – |
v | Un-saturated output of the controller | – |
eI | Error signal input to integrator including anti-windup tracking signal | – |
e | Error signal | – |
Behavior ​
Source ​
"""
Discrete-time PID controller on standard (ideal) form with anti-windup and set-point weighting.
The controller is implemented on standard form
Simplified:
```math
u = K \\left( e + \\int \\frac{1}{T_i} e dt + T_d \\dfrac{de}{dt} \\right)
```
Detailed:
```math
u = K \\left( (w_p r - y) + \\int \\big( \\frac{1}{T_i} (r - y) + N_i e_s \\big ) dt + T_d \\dfrac{d}{dt}(w_d r - y) \\right) + k_{ff} u_{ff}
```
where `e_s = u - v` is the saturated error signal, `v` is the unsaturated control signal and `u` is the saturated control signal.
An optional feed-forward signal ``u_{ff}`` can be added to the control signal by setting `with_ff = true` and connecting the `u_ff` input. Its contribution ``k_{ff} u_{ff}`` is added to the unsaturated control signal `v` before saturation, so it participates in the anti-windup tracking.
The derivative is filtered to allow a maximum gain of ``N_d``.
The integrator is discretized using the method specified by `Imethod`, options include
- `Imethod = DiscretizationMethod.Forward` (default): Corresponding to the transfer function ``T_s / (z - 1)``
- `Imethod = DiscretizationMethod.Backward`: Corresponding to the transfer function ``T_s z / (z - 1)``
- `Imethod = DiscretizationMethod.Trapezoidal`: Corresponding to the transfer function ``(T_s / 2) (z + 1) / (z - 1)``
The derivative is discretized using the method specified by `Dmethod`, options include
- `Dmethod = DiscretizationMethod.Forward`: Corresponding to the transfer function ``\\dfrac{N (z-1)}{z - \\dfrac{T_d-N T_s}{T_d}}``.
- `Dmethod = DiscretizationMethod.Backward` (default): Corresponding to the transfer function ``\\dfrac{\\dfrac{NT_d}{T_d + N T_s}(z-1)}{z - \\dfrac{T_d}{T_d + N T_s}}``
- `Dmethod = DiscretizationMethod.Trapezoidal`: Corresponding to the transfer function ``\\dfrac{\\dfrac{2NT_d}{2T_d + N T_s}(z-1)}{z - \\dfrac{2T_d - N T_s}{2T_d + N T_s}}``
Anti windup is realized by tracking using the gain ``N_i`` on the error signal ``e_s`` when the output is saturated.
To use the controller in 1DOF mode, i.e., with only the control error as input, connect the error signal to the `u_s` connector, connect a `Constant(; k = 0)` to the `u_m` connector and set `wp = wd = 1`.
"""
component DiscretePIDStandard@[input clk extends Discrete]
"The reference signal to the controller (or the error signal if used in 1DOF mode)"
u_s = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 170, "x2": 0, "y2": 270, "rot": 0}
},
"tags": []
}
}
"The measurement feedback"
u_m = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 690, "x2": 0, "y2": 790, "rot": 0}
},
"tags": []
}
}
"The feed-forward signal (only active if `with_ff = true`)"
u_ff = RealInput@[clk]() if with_ff {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 430, "x2": 0, "y2": 530, "rot": 0}
},
"tags": []
}
}
"The control signal output"
y = RealOutput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Discretization method for the integrator"
structural parameter Imethod::DiscretizationMethod = DiscretizationMethod.Forward()
"Discretization method for the derivative"
structural parameter Dmethod::DiscretizationMethod = DiscretizationMethod.Backward()
"Whether or not to include the integral part"
structural parameter with_I::Boolean = true
"Whether or not to include the derivative part"
structural parameter with_D::Boolean = true
"Whether or not to include the feed-forward input"
structural parameter with_ff::Boolean = false
structural parameter Ts::Real = SampleTime()
"Proportional gain"
parameter K::Real = 1
"Integral time constant (only active if `with_I = true`)"
parameter Ti::Real = 1
"Derivative time (only active if `with_D = true`)"
parameter Td::Real = 1
"Anti-windup gain (only active if `with_I = true`)"
parameter Ni::Real = sqrt(max(Td / Ti, 1e-6))
"Maximum derivative gain (only active if `with_D = true`). Typically set to 10-100."
parameter Nd::Real = 10
"Maximum output"
parameter y_max::Real = Inf
"Minimum output"
parameter y_min::Real = ifelse(y_max > 0, -y_max, -Inf)
"Set-point weighting in the proportional part. Set to `0` to prevent step changes in the output due to step changes in the reference."
parameter wp::Real = 1
"Set-point weighting in the derivative part. Set to `0` to prevent very large impulsive changes in the output due to step changes in the reference."
parameter wd::Real = 1
"Gain of the feed-forward input (only active if `with_ff = true`)"
parameter k_ff::Real = 1
"State of Integrator"
variable I::Real if with_I
"State of filtered derivative"
variable D::Real if with_D
"Setpoint-weighted error for derivative"
variable wde::Real if with_D
"Feed-forward contribution to the control signal"
variable uff::Real
"Un-saturated output of the controller"
variable v::Real
"Error signal input to integrator including anti-windup tracking signal"
variable eI::Real if with_I
"Error signal"
variable e::Real
relations
y = clamp(v, y_min, y_max) # Saturated control signal (= controller output)
e = u_s - u_m
if with_ff
uff = k_ff * u_ff # Feed-forward added before saturation
else
uff = 0
end
if with_I
initial I@(clk-1) = 0
switch Imethod
case Forward
initial eI@(clk-1) = 0
eI = e + Ni * (y - v)
I@clk = I@(clk-1) + Ts / Ti * eI@(clk-1)
case Backward
initial y@(clk-1) = 0
initial v@(clk-1) = 0
eI = e + Ni * (y@(clk-1) - v@(clk-1))
I@clk = I@(clk-1) + Ts / Ti * eI@clk
case Trapezoidal
initial y@(clk-1) = 0
initial v@(clk-1) = 0
initial eI@(clk-1) = 0
eI = e + Ni * (y@(clk-1) - v@(clk-1))
I@clk = I@(clk-1) + Ts / Ti * (eI@clk + eI@(clk-1)) / 2
end
end
if with_D
initial D@(clk-1) = 0
initial wde@(clk-1) = 0
wde = wd * u_s - u_m
switch Dmethod
case Forward
D@clk = (Td - Nd * Ts) / Td * D@(clk-1) + Nd * (wde@clk - wde@(clk-1))
case Backward
D@clk = Td / (Td + Nd * Ts) * D@(clk-1) + Nd * Td / (Td + Nd * Ts) * (wde@clk - wde@(clk-1))
case Trapezoidal
D@clk = (2 * Td - Nd * Ts) / (2 * Td + Nd * Ts) * D@(clk-1) + 2 * Nd * Td / (2 * Td + Nd * Ts) * (wde@clk - wde@(clk-1))
end
end
if with_I and with_D
v = K * ((wp * u_s - u_m) + I + D) + uff # Unsaturated control signal
elseif with_I
v = K * ((wp * u_s - u_m) + I) + uff # Unsaturated control signal
elseif with_D
v = K * ((wp * u_s - u_m) + D) + uff # Unsaturated control signal
else
v = K * (wp * u_s - u_m) + uff # Unsaturated control signal (pure proportional)
end
metadata {
"Dyad": {"icons": {"default": "dyad://DiscreteComponents/DiscretePIDStandard.svg"}}
}
endFlattened Source
"""
Discrete-time PID controller on standard (ideal) form with anti-windup and set-point weighting.
The controller is implemented on standard form
Simplified:
```math
u = K \\left( e + \\int \\frac{1}{T_i} e dt + T_d \\dfrac{de}{dt} \\right)
```
Detailed:
```math
u = K \\left( (w_p r - y) + \\int \\big( \\frac{1}{T_i} (r - y) + N_i e_s \\big ) dt + T_d \\dfrac{d}{dt}(w_d r - y) \\right) + k_{ff} u_{ff}
```
where `e_s = u - v` is the saturated error signal, `v` is the unsaturated control signal and `u` is the saturated control signal.
An optional feed-forward signal ``u_{ff}`` can be added to the control signal by setting `with_ff = true` and connecting the `u_ff` input. Its contribution ``k_{ff} u_{ff}`` is added to the unsaturated control signal `v` before saturation, so it participates in the anti-windup tracking.
The derivative is filtered to allow a maximum gain of ``N_d``.
The integrator is discretized using the method specified by `Imethod`, options include
- `Imethod = DiscretizationMethod.Forward` (default): Corresponding to the transfer function ``T_s / (z - 1)``
- `Imethod = DiscretizationMethod.Backward`: Corresponding to the transfer function ``T_s z / (z - 1)``
- `Imethod = DiscretizationMethod.Trapezoidal`: Corresponding to the transfer function ``(T_s / 2) (z + 1) / (z - 1)``
The derivative is discretized using the method specified by `Dmethod`, options include
- `Dmethod = DiscretizationMethod.Forward`: Corresponding to the transfer function ``\\dfrac{N (z-1)}{z - \\dfrac{T_d-N T_s}{T_d}}``.
- `Dmethod = DiscretizationMethod.Backward` (default): Corresponding to the transfer function ``\\dfrac{\\dfrac{NT_d}{T_d + N T_s}(z-1)}{z - \\dfrac{T_d}{T_d + N T_s}}``
- `Dmethod = DiscretizationMethod.Trapezoidal`: Corresponding to the transfer function ``\\dfrac{\\dfrac{2NT_d}{2T_d + N T_s}(z-1)}{z - \\dfrac{2T_d - N T_s}{2T_d + N T_s}}``
Anti windup is realized by tracking using the gain ``N_i`` on the error signal ``e_s`` when the output is saturated.
To use the controller in 1DOF mode, i.e., with only the control error as input, connect the error signal to the `u_s` connector, connect a `Constant(; k = 0)` to the `u_m` connector and set `wp = wd = 1`.
"""
component DiscretePIDStandard
"The reference signal to the controller (or the error signal if used in 1DOF mode)"
u_s = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 170, "x2": 0, "y2": 270, "rot": 0}
},
"tags": []
}
}
"The measurement feedback"
u_m = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 690, "x2": 0, "y2": 790, "rot": 0}
},
"tags": []
}
}
"The feed-forward signal (only active if `with_ff = true`)"
u_ff = RealInput@[clk]() if with_ff {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 430, "x2": 0, "y2": 530, "rot": 0}
},
"tags": []
}
}
"The control signal output"
y = RealOutput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Discretization method for the integrator"
structural parameter Imethod::DiscretizationMethod = DiscretizationMethod.Forward()
"Discretization method for the derivative"
structural parameter Dmethod::DiscretizationMethod = DiscretizationMethod.Backward()
"Whether or not to include the integral part"
structural parameter with_I::Boolean = true
"Whether or not to include the derivative part"
structural parameter with_D::Boolean = true
"Whether or not to include the feed-forward input"
structural parameter with_ff::Boolean = false
structural parameter Ts::Real = SampleTime()
"Proportional gain"
parameter K::Real = 1
"Integral time constant (only active if `with_I = true`)"
parameter Ti::Real = 1
"Derivative time (only active if `with_D = true`)"
parameter Td::Real = 1
"Anti-windup gain (only active if `with_I = true`)"
parameter Ni::Real = sqrt(max(Td / Ti, 1e-6))
"Maximum derivative gain (only active if `with_D = true`). Typically set to 10-100."
parameter Nd::Real = 10
"Maximum output"
parameter y_max::Real = Inf
"Minimum output"
parameter y_min::Real = ifelse(y_max > 0, -y_max, -Inf)
"Set-point weighting in the proportional part. Set to `0` to prevent step changes in the output due to step changes in the reference."
parameter wp::Real = 1
"Set-point weighting in the derivative part. Set to `0` to prevent very large impulsive changes in the output due to step changes in the reference."
parameter wd::Real = 1
"Gain of the feed-forward input (only active if `with_ff = true`)"
parameter k_ff::Real = 1
"State of Integrator"
variable I::Real if with_I
"State of filtered derivative"
variable D::Real if with_D
"Setpoint-weighted error for derivative"
variable wde::Real if with_D
"Feed-forward contribution to the control signal"
variable uff::Real
"Un-saturated output of the controller"
variable v::Real
"Error signal input to integrator including anti-windup tracking signal"
variable eI::Real if with_I
"Error signal"
variable e::Real
relations
y = clamp(v, y_min, y_max) # Saturated control signal (= controller output)
e = u_s - u_m
if with_ff
uff = k_ff * u_ff # Feed-forward added before saturation
else
uff = 0
end
if with_I
initial I@(clk-1) = 0
switch Imethod
case Forward
initial eI@(clk-1) = 0
eI = e + Ni * (y - v)
I@clk = I@(clk-1) + Ts / Ti * eI@(clk-1)
case Backward
initial y@(clk-1) = 0
initial v@(clk-1) = 0
eI = e + Ni * (y@(clk-1) - v@(clk-1))
I@clk = I@(clk-1) + Ts / Ti * eI@clk
case Trapezoidal
initial y@(clk-1) = 0
initial v@(clk-1) = 0
initial eI@(clk-1) = 0
eI = e + Ni * (y@(clk-1) - v@(clk-1))
I@clk = I@(clk-1) + Ts / Ti * (eI@clk + eI@(clk-1)) / 2
end
end
if with_D
initial D@(clk-1) = 0
initial wde@(clk-1) = 0
wde = wd * u_s - u_m
switch Dmethod
case Forward
D@clk = (Td - Nd * Ts) / Td * D@(clk-1) + Nd * (wde@clk - wde@(clk-1))
case Backward
D@clk = Td / (Td + Nd * Ts) * D@(clk-1) + Nd * Td / (Td + Nd * Ts) * (wde@clk - wde@(clk-1))
case Trapezoidal
D@clk = (2 * Td - Nd * Ts) / (2 * Td + Nd * Ts) * D@(clk-1) + 2 * Nd * Td / (2 * Td + Nd * Ts) * (wde@clk - wde@(clk-1))
end
end
if with_I and with_D
v = K * ((wp * u_s - u_m) + I + D) + uff # Unsaturated control signal
elseif with_I
v = K * ((wp * u_s - u_m) + I) + uff # Unsaturated control signal
elseif with_D
v = K * ((wp * u_s - u_m) + D) + uff # Unsaturated control signal
else
v = K * (wp * u_s - u_m) + uff # Unsaturated control signal (pure proportional)
end
metadata {
"Dyad": {"icons": {"default": "dyad://DiscreteComponents/DiscretePIDStandard.svg"}}
}
endTest Cases ​
No test cases defined.
Related ​
Examples
Experiments
Analyses