Skip to content

Commit 1dfd969

Browse files
committed
added : DAQP solver in LinMPC manual
1 parent 1f718b9 commit 1dfd969

File tree

6 files changed

+52
-24
lines changed

6 files changed

+52
-24
lines changed

docs/Project.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
[deps]
2-
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
32
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
3+
DAQP = "c47d62df-3981-49c8-9651-128b1cd08617"
4+
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
45
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
56
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
67

78
[compat]
89
ControlSystemsBase = "1"
9-
Documenter = "0.27"
10+
Documenter = "0.27"

docs/src/manual/linmpc.md

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ We design our [`LinMPC`](@ref) controllers by including the level constraint wit
6868
mpc = setconstraint!(LinMPC(model, Hp=15, Hc=2), ŷmin=[45, -Inf])
6969
```
7070

71-
By default, [`LinMPC`](@ref) controllers use a [`SteadyKalmanFilter`](@ref) to estimate the
72-
plant states. Before closing the loop, we call [`initstate!`](@ref) with the actual plant
73-
inputs and measurements to ensure a bumpless transfer. Since `model` simulates our plant
74-
here, its output will initialize the states. [`LinModel`](@ref) objects are callable for
75-
this purpose (an alias for [`evaloutput`](@ref)):
71+
By default, [`LinMPC`](@ref) controllers use [`OSQP`](https://osqp.org/) to solve the
72+
problem and a [`SteadyKalmanFilter`](@ref) to estimate the plant states. Before closing the
73+
loop, we call [`initstate!`](@ref) with the actual plant inputs and measurements to ensure a
74+
bumpless transfer. Since `model` simulates our plant here, its output will initialize the
75+
states. [`LinModel`](@ref) objects are callable for this purpose (an alias for
76+
[`evaloutput`](@ref)):
7677

7778
```@example 1
7879
u = model.uop
@@ -120,12 +121,34 @@ Lastly, we plot the closed-loop test with the `Plots` package:
120121

121122
```@example 1
122123
using Plots
123-
p1 = plot(t_data, y_data[1,:], label="level"); ylabel!("level")
124-
plot!(t_data, ry_data[1,:], label="setpoint", linestyle=:dash, linetype=:steppost)
125-
plot!(t_data, fill(45,size(t_data)), label="min", linestyle=:dot, linetype=:steppost)
126-
p2 = plot(t_data, y_data[2,:], label="temp."); ylabel!("temp.")
127-
plot!(t_data, ry_data[2,:],label="setpoint", linestyle=:dash, linetype=:steppost)
128-
p3 = plot(t_data,u_data[1,:],label="cold", linetype=:steppost); ylabel!("flow rate")
129-
plot!(t_data,u_data[2,:],label="hot", linetype=:steppost); xlabel!("time (s)")
130-
p = plot(p1, p2, p3, layout=(3,1), fmt=:svg)
124+
function plot_data(t_data, u_data, y_data, ry_data)
125+
p1 = plot(t_data, y_data[1,:], label="level"); ylabel!("level")
126+
plot!(t_data, ry_data[1,:], label="setpoint", linestyle=:dash, linetype=:steppost)
127+
plot!(t_data, fill(45,size(t_data)), label="min", linestyle=:dot, linewidth=1.5)
128+
p2 = plot(t_data, y_data[2,:], label="temp."); ylabel!("temp.")
129+
plot!(t_data, ry_data[2,:],label="setpoint", linestyle=:dash, linetype=:steppost)
130+
p3 = plot(t_data,u_data[1,:],label="cold", linetype=:steppost); ylabel!("flow rate")
131+
plot!(t_data,u_data[2,:],label="hot", linetype=:steppost); xlabel!("time (s)")
132+
return plot(p1, p2, p3, layout=(3,1), fmt=:svg)
133+
end
134+
plot_data(t_data, u_data, y_data, ry_data)
135+
```
136+
137+
For some situations, when [`LinMPC`](@ref) matrices are small/medium and dense, [`DAQP`](https://darnstrom.github.io/daqp/)
138+
optimizer may be more efficient. To install it, run:
139+
140+
```julia
141+
using Pkg; Pkg.add("DAQP")
142+
```
143+
144+
Constructing a [`LinMPC`](@ref) with `DAQP` leads to identical results here:
145+
146+
```@example 1
147+
using JuMP, DAQP
148+
daqp = Model(DAQP.Optimizer)
149+
mpc2 = setconstraint!(LinMPC(model, Hp=15, Hc=2, optim=daqp), ŷmin=[45, -Inf])
150+
setstate!(model, zeros(model.nx))
151+
initstate!(mpc2, model.uop, model())
152+
u_data2, y_data2, ry_data2 = test_mpc(mpc2, model)
153+
plot_data(t_data, u_data2, y_data2, ry_data2)
131154
```

example/juMPC.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ setconstraint!(nmpc2, Δumin=[-Inf,-Inf],Δumax=[+Inf,+Inf])
100100
nx = linModel4.nx
101101
kf = KalmanFilter(linModel4, σP0=10*ones(nx), σQ=0.01*ones(nx), σR=[0.1, 0.1], σQ_int=0.05*ones(2), σP0_int=10*ones(2))
102102

103-
mpc = LinMPC(kf, Hp=15, Hc=1, Mwt=[1, 1] , Nwt=[0.1, 0.1], Cwt=1e5)#, optim=Model(DAQP.Optimizer))#, optim=Model(HiGHS.Optimizer))#, optim=Model(DAQP.Optimizer))
103+
mpc = LinMPC(kf, Hp=15, Hc=1, Mwt=[1, 1] , Nwt=[0.1, 0.1], Cwt=1e5)#, optim=Model(HiGHS.Optimizer))#, optim=Model(DAQP.Optimizer))
104104

105105
setconstraint!(mpc, c_umin=[0,0], c_umax=[0,0])
106106
setconstraint!(mpc, c_ŷmin=[1,1], c_ŷmax=[1,1])
@@ -164,9 +164,11 @@ using PlotThemes, Plots
164164
theme(:dark)
165165
default(fontfamily="Computer Modern"); scalefontsizes(1.1)
166166

167-
test_mpc(linModel4 , mpc)
168-
@time u_data, y_data, r_data, d_data = test_mpc(linModel4, mpc)
167+
using BenchmarkTools
169168

169+
test_mpc(linModel4 , mpc)
170+
@btime u_data, y_data, r_data, d_data = test_mpc(linModel4, mpc)
171+
#=
170172
resM = sim!(nonLinModel2, mpc.Hp+10, [1,-1])
171173
psM = plot(resM)
172174
display(psM)
@@ -205,3 +207,4 @@ display(pd)
205207
display(pu)
206208
display(py)
207209
210+
=#

src/controller/linmpc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ arguments.
134134
julia> model = LinModel([tf(3, [30, 1]); tf(-2, [5, 1])], 4);
135135
136136
julia> mpc = LinMPC(model, Mwt=[0, 1], Nwt=[0.5], Hp=30, Hc=1)
137-
LinMPC controller with a sample time Ts = 4.0 s, SteadyKalmanFilter estimator and:
137+
LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, SteadyKalmanFilter estimator and:
138138
30 prediction steps Hp
139139
1 control steps Hc
140140
1 manipulated inputs u
@@ -164,7 +164,7 @@ Use custom state estimator `estim` to construct `LinMPC`.
164164
julia> estim = KalmanFilter(LinModel([tf(3, [30, 1]); tf(-2, [5, 1])], 4), i_ym=[2]);
165165
166166
julia> mpc = LinMPC(estim, Mwt=[0, 1], Nwt=[0.5], Hp=30, Hc=1)
167-
LinMPC controller with a sample time Ts = 4.0 s, KalmanFilter estimator and:
167+
LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, KalmanFilter estimator and:
168168
30 prediction steps Hp
169169
1 control steps Hc
170170
1 manipulated inputs u

src/controller/nonlinmpc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ This method uses the default state estimator :
134134
julia> model = NonLinModel((x,u,_)->0.5x+u, (x,_)->2x, 10.0, 1, 1, 1);
135135
136136
julia> mpc = NonLinMPC(model, Hp=20, Hc=1, Cwt=1e6)
137-
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter estimator and:
137+
NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedKalmanFilter estimator and:
138138
20 prediction steps Hp
139139
1 control steps Hc
140140
1 manipulated inputs u
@@ -171,7 +171,7 @@ julia> model = NonLinModel((x,u,_)->0.5x+u, (x,_)->2x, 10.0, 1, 1, 1);
171171
julia> estim = UnscentedKalmanFilter(model, σQ_int=[0.05]);
172172
173173
julia> mpc = NonLinMPC(estim, Hp=20, Hc=1, Cwt=1e6)
174-
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter estimator and:
174+
NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedKalmanFilter estimator and:
175175
20 prediction steps Hp
176176
1 control steps Hc
177177
1 manipulated inputs u

src/predictive_control.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ julia> mpc = LinMPC(setop!(LinModel(tf(3, [30, 1]), 4), uop=[50], yop=[25]));
9393
julia> mpc = setconstraint!(mpc, umin=[0], umax=[100], c_umin=[0.0], c_umax=[0.0]);
9494
9595
julia> mpc = setconstraint!(mpc, Δumin=[-10], Δumax=[+10], c_Δumin=[1.0], c_Δumax=[1.0])
96-
LinMPC controller with a sample time Ts = 4.0 s, SteadyKalmanFilter estimator and:
96+
LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, SteadyKalmanFilter estimator and:
9797
10 prediction steps Hp
9898
2 control steps Hc
9999
1 manipulated inputs u
@@ -1009,7 +1009,8 @@ function Base.show(io::IO, mpc::PredictiveController)
10091009
nx̂, nym, nyu = mpc.estim.nx̂, mpc.estim.nym, mpc.estim.nyu
10101010
n = maximum(ndigits.((Hp, Hc, nu, nx̂, nym, nyu, nd))) + 1
10111011
println(io, "$(typeof(mpc).name.name) controller with a sample time Ts = "*
1012-
"$(mpc.estim.model.Ts) s, $(typeof(mpc.estim).name.name) estimator and:")
1012+
"$(mpc.estim.model.Ts) s, $(solver_name(mpc.optim)) optimizer, "*
1013+
"$(typeof(mpc.estim).name.name) estimator and:")
10131014
println(io, "$(lpad(Hp, n)) prediction steps Hp")
10141015
println(io, "$(lpad(Hc, n)) control steps Hc")
10151016
println(io, "$(lpad(nu, n)) manipulated inputs u")

0 commit comments

Comments
 (0)