Skip to content

Commit 0c2c3bd

Browse files
committed
manual two sections
1 parent f023da8 commit 0c2c3bd

File tree

5 files changed

+102
-107
lines changed

5 files changed

+102
-107
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ using Pkg; Pkg.add("ModelPredictiveControl")
2121

2222
## Getting Started
2323

24-
To construct model predictive controllers, we must first specify a plant model that is
25-
typically extracted from input-output data using [system identification](https://github.com/baggepinnen/ControlSystemIdentification.jl).
24+
To construct model predictive controllers (MPCs), we must first specify a plant model that
25+
is typically extracted from input-output data using [system identification](https://github.com/baggepinnen/ControlSystemIdentification.jl).
2626
The model here is linear with one input, two outputs and a large time delay in the first
2727
channel:
2828

docs/make.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ makedocs(
2222
),
2323
pages = [
2424
"Home" => "index.md",
25-
"Manual" => "manual.md",
25+
"Manual" => [
26+
"Linear Designs" => "manual/linmpc.md",
27+
"Nonlinear Designs" => "manual/nonlinmpc.md",
28+
],
2629
"Functions" => [
2730
"Public" => [
2831
"Plant Models" => "public/sim_model.md",

docs/src/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ for the linear systems and [`JuMP.jl`](https://github.com/jump-dev/JuMP.jl) for
1111
```@contents
1212
Pages = [
1313
"index.md",
14-
"manual.md",
14+
"manual/linmpc.md",
15+
"manual/nonlinmpc.md",
1516
"public/sim_model.md",
1617
"public/state_estim.md",
1718
"public/predictive_control.md",

docs/src/manual.md renamed to docs/src/manual/linmpc.md

Lines changed: 3 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
11
# Manual
22

3-
## Installation
3+
## Linear model and controller
44

5-
To install the `ModelPredictiveControl` package, run this command in the Julia REPL:
6-
7-
```text
8-
using Pkg; Pkg.add("ModelPredictiveControl")
9-
```
10-
11-
## Predictive Controller Design
12-
13-
### Linear Model
14-
15-
The considered plant is well-stirred tank with a cold and hot water inlet. The water
16-
flows out of an opening at the bottom of the tank. The manipulated inputs are the cold
5+
The example considers a well-stirred tank with a cold and hot water inlet as a plant. The
6+
water flows out of an opening at the bottom of the tank. The manipulated inputs are the cold
177
``u_c`` and hot ``u_h`` water flow rate, and the measured outputs are the liquid level
188
``y_L`` and temperature ``y_T``:
199

@@ -136,93 +126,3 @@ p3 = plot(t_data,u_data[1,:],label="cold", linetype=:steppost); ylabel!("flow ra
136126
plot!(t_data,u_data[2,:],label="hot", linetype=:steppost); xlabel!("time (s)")
137127
p = plot(p1, p2, p3, layout=(3,1), fmt=:svg)
138128
```
139-
140-
### Nonlinear Model
141-
142-
In this example, the goal is to control the angular position ``θ`` of a pendulum
143-
attached to a motor. If the manipulated input is the motor torque ``τ``, the vectors
144-
are:
145-
146-
```math
147-
\begin{aligned}
148-
\mathbf{u} &= \begin{bmatrix} τ \end{bmatrix} \\
149-
\mathbf{y} &= \begin{bmatrix} θ \end{bmatrix}
150-
\end{aligned}
151-
```
152-
153-
The plant model is nonlinear:
154-
155-
```math
156-
\begin{aligned}
157-
\dot{θ}(t) &= ω(t) \\
158-
\dot{ω}(t) &= -\frac{g}{L}\sin\big( θ(t) \big) - \frac{K}{m} ω(t) + \frac{1}{m L^2} τ(t)
159-
\end{aligned}
160-
```
161-
162-
in which ``g`` is the gravitational acceleration, ``L``, the pendulum length, ``K``, the
163-
friction coefficient at the pivot point, and ``m``, the mass attached at the end of the
164-
pendulum. Here, the explicit Euler method discretizes the system to construct a
165-
[`NonLinModel`](@ref):
166-
167-
```@example 2
168-
using ModelPredictiveControl
169-
function pendulum(par, x, u)
170-
g, L, K, m = par # [m/s], [m], [kg/s], [kg]
171-
θ, ω = x[1], x[2] # [rad], [rad/s]
172-
τ = u[1] # [N m]
173-
dθ = ω
174-
dω = -g/L*sin(θ) - k/m*ω + τ/m/L^2
175-
return [dθ, dω]
176-
end
177-
Ts = 0.1 # [s]
178-
par = (9.8, 0.4, 1.2, 0.3)
179-
f(x, u, _ ) = x + Ts*pendulum(par, x, u) # Euler method
180-
h(x, _ ) = [180/π*x[1]] # [°]
181-
nu, nx, ny = 1, 2, 1
182-
model = NonLinModel(f, h, Ts, nu, nx, ny)
183-
```
184-
185-
The output function ``\mathbf{h}`` converts the angular position ``θ`` to degrees. It
186-
is good practice to first simulate `model` using [`sim!`](@ref) as a quick sanity check:
187-
188-
```@example 2
189-
using Plots
190-
u = [0.5] # τ = 0.5 N m
191-
plot(sim!(model, 60, u), plotu=false)
192-
```
193-
194-
An [`UnscentedKalmanFilter`](@ref) estimates the plant state :
195-
196-
```@example 2
197-
estim = UnscentedKalmanFilter(model, σQ=[0.5, 2.5], σQ_int=[0.5])
198-
```
199-
200-
The standard deviation of the angular velocity ``ω`` is higher here (`σQ` second value)
201-
since ``\dot{ω}(t)`` equation includes an uncertain parameter: the friction coefficient
202-
``K``. The estimator tuning is tested on a plant simulated with a different ``K``:
203-
204-
```@example 2
205-
par_plant = (par[1], par[2], par[3] + 0.25, par[4])
206-
f_plant(x, u, _) = x + Ts*pendulum(par_plant, x, u)
207-
plant = NonLinModel(f_plant, h, Ts, nu, nx, ny)
208-
res = sim!(estim, 30, [0.5], plant=plant, y_noise=[0.5]) # τ = 0.5 N m
209-
p2 = plot(res, plotu=false, plotx=true, plotx̂=true)
210-
```
211-
212-
The Kalman filter performance seems sufficient for control. As the motor torque is limited
213-
to -1.5 to 1.5 N m, we incorporate the input constraints in a [`NonLinMPC`](@ref):
214-
215-
```@example 2
216-
mpc = NonLinMPC(estim, Hp=20, Hc=2, Mwt=[0.1], Nwt=[1.0], Cwt=Inf)
217-
mpc = setconstraint!(mpc, umin=[-1.5], umax=[+1.5])
218-
```
219-
220-
We test `mpc` performance on `plant` by imposing an angular setpoint of 180° (inverted
221-
position):
222-
223-
```@example 2
224-
res = sim!(mpc, 30, [180.0], x̂0=zeros(mpc.estim.nx̂), plant=plant, x0=zeros(plant.nx))
225-
plot(res, plotŷ=true)
226-
```
227-
228-
The controller seems robust enough to variations on ``K`` coefficient.

docs/src/manual/nonlinmpc.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Manual
2+
3+
## Nonlinear model and controller
4+
5+
In this example, the goal is to control the angular position ``θ`` of a pendulum
6+
attached to a motor. If the manipulated input is the motor torque ``τ``, the vectors
7+
are:
8+
9+
```math
10+
\begin{aligned}
11+
\mathbf{u} &= \begin{bmatrix} τ \end{bmatrix} \\
12+
\mathbf{y} &= \begin{bmatrix} θ \end{bmatrix}
13+
\end{aligned}
14+
```
15+
16+
The plant model is nonlinear:
17+
18+
```math
19+
\begin{aligned}
20+
\dot{θ}(t) &= ω(t) \\
21+
\dot{ω}(t) &= -\frac{g}{L}\sin\big( θ(t) \big) - \frac{K}{m} ω(t) + \frac{1}{m L^2} τ(t)
22+
\end{aligned}
23+
```
24+
25+
in which ``g`` is the gravitational acceleration, ``L``, the pendulum length, ``K``, the
26+
friction coefficient at the pivot point, and ``m``, the mass attached at the end of the
27+
pendulum. Here, the explicit Euler method discretizes the system to construct a
28+
[`NonLinModel`](@ref):
29+
30+
```@example 2
31+
using ModelPredictiveControl
32+
function pendulum(par, x, u)
33+
g, L, K, m = par # [m/s], [m], [kg/s], [kg]
34+
θ, ω = x[1], x[2] # [rad], [rad/s]
35+
τ = u[1] # [N m]
36+
dθ = ω
37+
dω = -g/L*sin(θ) - k/m*ω + τ/m/L^2
38+
return [dθ, dω]
39+
end
40+
Ts = 0.1 # [s]
41+
par = (9.8, 0.4, 1.2, 0.3)
42+
f(x, u, _ ) = x + Ts*pendulum(par, x, u) # Euler method
43+
h(x, _ ) = [180/π*x[1]] # [°]
44+
nu, nx, ny = 1, 2, 1
45+
model = NonLinModel(f, h, Ts, nu, nx, ny)
46+
```
47+
48+
The output function ``\mathbf{h}`` converts the angular position ``θ`` to degrees. It
49+
is good practice to first simulate `model` using [`sim!`](@ref) as a quick sanity check:
50+
51+
```@example 2
52+
using Plots
53+
u = [0.5] # τ = 0.5 N m
54+
plot(sim!(model, 60, u), plotu=false)
55+
```
56+
57+
An [`UnscentedKalmanFilter`](@ref) estimates the plant state :
58+
59+
```@example 2
60+
estim = UnscentedKalmanFilter(model, σQ=[0.5, 2.5], σQ_int=[0.5])
61+
```
62+
63+
The standard deviation of the angular velocity ``ω`` is higher here (`σQ` second value)
64+
since ``\dot{ω}(t)`` equation includes an uncertain parameter: the friction coefficient
65+
``K``. The estimator tuning is tested on a plant simulated with a different ``K``:
66+
67+
```@example 2
68+
par_plant = (par[1], par[2], par[3] + 0.25, par[4])
69+
f_plant(x, u, _) = x + Ts*pendulum(par_plant, x, u)
70+
plant = NonLinModel(f_plant, h, Ts, nu, nx, ny)
71+
res = sim!(estim, 30, [0.5], plant=plant, y_noise=[0.5]) # τ = 0.5 N m
72+
p2 = plot(res, plotu=false, plotx=true, plotx̂=true)
73+
```
74+
75+
The Kalman filter performance seems sufficient for control. As the motor torque is limited
76+
to -1.5 to 1.5 N m, we incorporate the input constraints in a [`NonLinMPC`](@ref):
77+
78+
```@example 2
79+
mpc = NonLinMPC(estim, Hp=20, Hc=2, Mwt=[0.1], Nwt=[1.0], Cwt=Inf)
80+
mpc = setconstraint!(mpc, umin=[-1.5], umax=[+1.5])
81+
```
82+
83+
We test `mpc` performance on `plant` by imposing an angular setpoint of 180° (inverted
84+
position):
85+
86+
```@example 2
87+
res = sim!(mpc, 30, [180.0], x̂0=zeros(mpc.estim.nx̂), plant=plant, x0=zeros(plant.nx))
88+
plot(res, plotŷ=true)
89+
```
90+
91+
The controller seems robust enough to variations on ``K`` coefficient.

0 commit comments

Comments
 (0)