You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- $U(s)$ is the Laplace transform of the *control variable* (also called *manipulated variable*) $u(t)$,
11
-
- $Y(s)$ is the Laplace transform of the *measured output variable* (also called *process variable*) $y(t)$,
12
-
- $R(s)$ is the Laplace transform of the *reference variable* (also called *set point*) $r(t)$,
13
-
- $U_\textrm{ff}(s)$ is the Laplace transform of the *feedforward* contribution to the control variable $u_\textrm{ff}(t)$,
14
-
- $K$ is the *proportional gain*,
15
-
- $T_\mathrm{i}$ is the *integral time*,
16
-
- $T_\mathrm{d}$ is the *derivative time*,
10
+
- $u(t) \leftrightarrow U(s)$ is the control signal
11
+
- $y(t) \leftrightarrow Y(s)$ is the measurement signal
12
+
- $r(t) \leftrightarrow R(s)$ is the reference / set point
13
+
- $u_\textrm{ff}(t) \leftrightarrow U_\textrm{ff}(s)$ is the feed-forward contribution
14
+
- $K$ is the proportional gain
15
+
- $T_i$ is the integral time
16
+
- $T_d$ is the derivative time
17
17
- $N$ is a parameter that limits the gain of the derivative term at high frequencies, typically ranges from 2 to 20,
18
18
- $b \in [0, 1]$ is a parameter that gives the proportion of the reference signal that appears in the proportional term.
19
19
@@ -25,7 +25,7 @@ Construct a controller by
25
25
```julia
26
26
pid =DiscretePID(; K =1, Ti =false, Td =false, Tt =√(Ti*Td), N =10, b =1, umin =-Inf, umax =Inf, Ts, I =0, D =0, yold =0)
27
27
```
28
-
and compute the control (the controller output) at a given time using
28
+
and compute the control signal at a given time using
29
29
```julia
30
30
u =pid(r, y, uff)
31
31
```
@@ -34,11 +34,11 @@ or
34
34
u =calculate_control!(pid, r, y, uff)
35
35
```
36
36
37
-
The parameters $K$, $T_\mathrm{i}$, and $T_\mathrm{d}$ may be updated using the functions `set_K!`, `set_Ti!`, and `set_Td!`, respectively.
37
+
The parameters $K$, $T_i$, and $T_d$ may be updated using the functions `set_K!`, `set_Ti!`, and `set_Td!`, respectively.
38
38
39
39
The numeric type used by the controller (the `T` in `DiscretePID{T}`) is determined by the types of the parameters. To use a custom number type, e.g., a fixed-point number type, simply pass the parameters as that type, see example below. The controller will automatically convert measurements and references to this type before performing the control calculations.
40
40
41
-
The *internal state* of the controller can be reset to zero using the function `reset_state!(pid)`. If repeated simulations using the same controller object are performed, the state should be reset between simulations.
41
+
The **internal state** of the controller can be reset to zero using the function `reset_state!(pid)`. If repeated simulations using the same controller object are performed, the state should likely be reset between simulations.
42
42
43
43
## Examples
44
44
@@ -48,24 +48,24 @@ The following example simulates a feedback control system containing a PID contr
48
48
49
49
```julia
50
50
using DiscretePIDs, ControlSystemsBase, Plots
51
-
Tf =15# Simulation time
52
-
K =1# Proportional gain
53
-
Ti =1# Integral time
54
-
Td =1# Derivative time
55
-
Ts =0.01# Sample time
51
+
Tf =15# Simulation time
52
+
K =1# Proportional gain
53
+
Ti =1# Integral time
54
+
Td =1# Derivative time
55
+
Ts =0.01# sample time
56
56
57
-
P =c2d(ss(tf(1, [1, 1])), Ts) # Plant to be controlled, discretized using zero-order hold
57
+
P =c2d(ss(tf(1, [1, 1])), Ts) # Process to be controlled, discretized using zero-order hold
58
58
pid =DiscretePID(; K, Ts, Ti, Td)
59
59
60
60
ctrl =function(x,t)
61
-
y = (P.C*x)[] # Measured output
62
-
d =1# Disturbance
63
-
r =0# Reference
64
-
u =pid(r, y) # Control
65
-
u + d # Plant input is control + disturbance
61
+
y = (P.C*x)[] # measurement
62
+
d =1# disturbance
63
+
r =0# reference
64
+
u =pid(r, y) # control signal
65
+
u + d # Plant input is control signal + disturbance
66
66
end
67
67
68
-
res =lsim(P, ctrl, Tf)# Simulate the closed-loop system
68
+
res =lsim(P, ctrl, Tf)
69
69
70
70
plot(res, plotu=true); ylabel!("u + d", sp=2)
71
71
```
@@ -79,52 +79,51 @@ This example is identical to the one above except for using [DifferentialEquatio
79
79
80
80
There are several different ways one could go about including a discrete-time controller in a continuous-time simulation, in particular, we must choose a way to store the computed control variable. Two common approaches are
81
81
82
-
1. We use a global variable into which we write the control variable at each discrete time step.
82
+
1. We use a global variable into which we write the control signal at each discrete time step.
83
83
2. We add an extra state variable to the system, and use it to store the control variable.
84
84
85
85
In this example we choose the latter approach, since it has the added benefit of adding the computed control variable to the solution object.
86
86
87
-
We use `DiffEqCallbacks.PeriodicCallback`, with which we perform the PID-controller update, and store the computed control variable in the extra state variable.
87
+
We use `DiffEqCallbacks.PeriodicCallback`, in which we perform the PID-controller update, and store the computed control signal in the extra state variable.
88
88
89
89
```julia
90
90
using DiscretePIDs, ControlSystemsBase, OrdinaryDiffEq, DiffEqCallbacks, Plots
91
91
92
-
Tf =15# Simulation time
93
-
K =1# Proportional gain
94
-
Ti =1# Integral time
95
-
Td =1# Derivative time
96
-
Ts =0.01# Sample time
92
+
Tf =15# Simulation time
93
+
K =1# Proportional gain
94
+
Ti =1# Integral time
95
+
Td =1# Derivative time
96
+
Ts =0.01# sample time
97
97
98
-
P =ss(tf(1, [1, 1])) # Plant to be controlled in continuous time
99
-
A, B, C, D =ssdata(P) # Extract the system matrices
98
+
P =ss(tf(1, [1, 1])) # Process to be controlled in continuous time
99
+
A, B, C, D =ssdata(P) # Extract the system matrices
100
100
pid =DiscretePID(; K, Ts, Ti, Td)
101
101
102
102
functiondynamics!(dxu, xu, p, t)
103
-
A, B, C, r, d = p # Store the reference and disturbance in the parameter object
104
-
x = xu[1:P.nx] # Extract the state
105
-
u = xu[P.nx+1:end] # Extract the control variable
106
-
dxu[1:P.nx] .= A*x .+ B*(u .+ d)# Plant input is control variable + disturbance
107
-
dxu[P.nx+1:end] .=0# Control variable has no dynamics, it's updated by the callback
103
+
A, B, C, r, d = p # We store the reference and disturbance in the parameter object
104
+
x = xu[1:P.nx] # Extract the state
105
+
u = xu[P.nx+1:end] # Extract the control signal
106
+
dxu[1:P.nx] .= A*x .+ B*(u .+ d)# Plant input is control signal + disturbance
107
+
dxu[P.nx+1:end] .=0# The control signal has no dynamics, it's updated by the callback
108
108
end
109
109
110
110
cb =PeriodicCallback(Ts) do integrator
111
-
p = integrator.p # Extract the parameter object from the integrator
112
-
(; C, r, d) = p # Extract the reference and disturbance from the parameter object
113
-
x = integrator.u[1:P.nx] # Extract the state (the integrator uses `u` to refer to the state, in control theory we typically name it `x`)
114
-
y = (C*x)[] # Simulated measurement
115
-
u =pid(r, y) # Compute the control variable
116
-
integrator.u[P.nx+1:end] .= u # Update the control-signal state variable
111
+
p = integrator.p # Extract the parameter object from the integrator
112
+
(; C, r, d) = p # Extract the reference and disturbance from the parameter object
113
+
x = integrator.u[1:P.nx] # Extract the state (the integrator uses the variable name `u` to refer to the state, in control theory we typically use the variable name `x`)
114
+
y = (C*x)[] # Simulated measurement
115
+
u =pid(r, y) # Compute the control signal
116
+
integrator.u[P.nx+1:end] .= u # Update the control-signal state variable
The figure should look more or less identical to the previous one, except that we plot the control variable $u$ instead of the combined input $u + d$ like we did above. Due to the fast sample rate $T_\mathrm{s}$, the control variable looks continuous, however, increase $T_s$ and you'll notice the zero-order-hold nature of $u$.
126
+
The figure should look more or less identical to the one above, except that we plot the control signal $u$ instead of the combined input $u + d$ like we did above. Due to the fast sample rate $T_s$, the control signal looks continuous, however, increase $T_s$ and you'll notice the zero-order-hold nature of $u$.
128
127
129
128
### Example using SeeToDee.jl
130
129
@@ -137,59 +136,58 @@ considers the continuous-time dynamical system modelled by
137
136
```math
138
137
\dot x(t) = f(x(t), u(t), p(t), t)
139
138
```
140
-
and at a given state $x$ and time $t$ and for a given control $u$, it computes an approximation $x^+$ to the state $x(t+T_\mathrm{s})$ at the next time step $t+T_\mathrm{s}$
139
+
and at a given state $x$ and time $t$ and for a given control $u$, it computes an approximation $x^+$ to the state $x(t+T_s)$ at the next time step $t+T_s$
Once again, the output looks identical and is therefore omitted here.
188
186
189
187
## Details
190
-
- The derivative term only acts on the (filtered) measurement and not the command signal. It is thus safe to pass step changes in the reference to the controller. The parameter $b$ can further be set to zero to avoid step changes in the control variable in response to step changes in the reference.
188
+
- The derivative term only acts on the (filtered) measurement and not the command signal. It is thus safe to pass step changes in the reference to the controller. The parameter $b$ can further be set to zero to avoid step changes in the control signal in response to step changes in the reference.
191
189
- Bumpless transfer when updating `K` is realized by updating the state `I`. See the docs for `set_K!` for more details.
192
-
- The total control variable $u(t)$ (PID + feedforward) is limited by the integral anti-windup.
190
+
- The total control signal $u(t)$ (PID + feedforward) is limited by the integral anti-windup.
193
191
- The integrator is discretized using a forward difference (no direct term between the input and output through the integral state) while the derivative is discretized using a backward difference.
194
192
- This particular implementation of a discrete-time PID controller is detailed in Chapter 8 of [Wittenmark, Björn, Karl-Erik Årzén, and Karl Johan Åström. ‘Computer Control: An Overview’. IFAC Professional Brief. International Federation of Automatic Control, 2002](https://www.ifac-control.org/publications/list-of-professional-briefs/pb_wittenmark_etal_final.pdf/view).
195
193
- When used with input arguments of standard types, such as `Float64` or `Float32`, the controller is guaranteed not to allocate any memory or contain any dynamic dispatches. This analysis is carried out in the tests, and is performed using [AllocCheck.jl](https://github.com/JuliaLang/AllocCheck.jl).
@@ -198,7 +196,7 @@ Once again, the output looks identical and is therefore omitted here.
198
196
If the controller is ultimately to be implemented on a platform without floating-point hardware, we can simulate how it will behave with fixed-point arithmetics using the [FixedPointNumbers.jl](https://github.com/francescoalemanno/FixedPoint.jl) package. The following example modifies the first example above and shows how to simulate the controller using 16-bit fixed-point arithmetics with 10 bits for the fractional part:
199
197
```julia
200
198
using FixedPointNumbers
201
-
T = Fixed{Int16, 10} # 16-bit fixed-point with 10 bits for the fractional part
199
+
T = Fixed{Int16, 10} # 16-bit fixed-point with 10 bits for the fractional part
202
200
pid =DiscretePID(; K =T(K), Ts =T(Ts), Ti =T(Ti), Td =T(Td))
-[TrajectoryLimiters.jl](https://github.com/baggepinnen/TrajectoryLimiters.jl) To generate dynamically feasible reference trajectories with bounded velocity and acceleration given an instantaneous reference $r(t)$ which may change abruptly.
243
245
-[SymbolicControlSystems.jl](https://github.com/JuliaControl/SymbolicControlSystems.jl) For C-code generation of LTI systems.
0 commit comments