Skip to content

Commit e815aa3

Browse files
committed
added getinfo doc
1 parent dabd036 commit e815aa3

File tree

7 files changed

+69
-43
lines changed

7 files changed

+69
-43
lines changed

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"feedforward",
2929
"franckgaga",
3030
"getestimates",
31+
"getinfo",
3132
"Hodouin",
3233
"initpred",
3334
"initstate",

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelPredictiveControl"
22
uuid = "61f9bdb8-6ae4-484a-811f-bbf86720c31c"
33
authors = ["Francis Gagnon"]
4-
version = "0.4.1"
4+
version = "0.5.0"
55

66
[deps]
77
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"

docs/src/index.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,15 @@ Pages = [
6060
- ✅ optimization based on `JuMP.jl`:
6161
- ✅ quickly compare multiple optimizers
6262
- ✅ nonlinear solvers relying on automatic differentiation (exact derivative)
63-
- ⬜ additional information about the optimum to ease troubleshooting:
64-
- ⬜ optimal input increments over control horizon
65-
- ⬜ slack variable optimum
66-
- ⬜ objective function optimum
67-
- ⬜ output predictions at optimum
68-
- ⬜ current stochastic output predictions
69-
- ⬜ optimal economic costs
63+
- ✅ additional information about the optimum to ease troubleshooting:
64+
- ✅ optimal input increments over control horizon
65+
- ✅ slack variable optimum
66+
- ✅ objective function optimum
67+
- ✅ output predictions at optimum
68+
- ✅ current stochastic output predictions
69+
- ✅ current deterministic output predictions
70+
- ✅ optimal economic costs
71+
- ✅ optimizer solution summary
7072

7173
### State Estimation Features
7274

docs/src/public/predictive_control.md

+6
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,9 @@ setconstraint!
4545
```@docs
4646
moveinput!
4747
```
48+
49+
## Get Additional Information
50+
51+
```@docs
52+
getinfo
53+
```

src/controller/nonlinmpc.jl

+5
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ function NonLinMPC(
188188
return NonLinMPC{S, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, ru, optim)
189189
end
190190

191+
"""
192+
getinfo(mpc::NonLinMPC)
193+
194+
Invoke [`getinfo(::PredictiveController)`](@ref) and add `:JE` the economic optimum ``J_E``.
195+
"""
191196
function getinfo(mpc::NonLinMPC)
192197
info, sol_summary = invoke(getinfo, Tuple{PredictiveController}, mpc)
193198
U, Ŷ, D̂ = info[:U], info[:Ŷ], info[:D̂]

src/predictive_control.jl

+32-29
Original file line numberDiff line numberDiff line change
@@ -263,36 +263,39 @@ function moveinput!(
263263
return u
264264
end
265265

266-
#=
267-
268-
269-
"Include the additional information about the optimum to ease troubleshooting."
270-
mutable struct OptimInfo
271-
ΔŨ::Vector{Float64}
272-
ϵ ::Float64
273-
J ::Float64
274-
u ::Vector{Float64}
275-
U ::Vector{Float64}
276-
ŷ ::Vector{Float64}
277-
Ŷ ::Vector{Float64}
278-
ŷs::Vector{Float64}
279-
Ŷs::Vector{Float64}
280-
end
281-
=#
282-
283-
#=
284-
function write_info!(mpc::LinMPC, ΔŨ, J, ŷs, Ŷs)
285-
mpc.info.ΔŨ = ΔŨ
286-
mpc.info.ϵ = isinf(mpc.C) ? NaN : ΔŨ[end]
287-
mpc.info.J = J
288-
mpc.info.U = mpc.S̃_Hp*ΔŨ + mpc.T_Hp*(mpc.estim.lastu0 + mpc.estim.model.uop)
289-
mpc.info.u = mpc.info.U[1:mpc.estim.model.nu]
290-
mpc.info.ŷ = mpc.ŷ
291-
mpc.info.Ŷ = mpc.Ẽ*ΔŨ + mpc.F
292-
mpc.info.ŷs, mpc.info.Ŷs = ŷs, Ŷs
293-
end
294-
=#
266+
@doc raw"""
267+
getinfo(mpc::PredictiveController)
268+
269+
Get additional information about `mpc` controller optimum.
270+
271+
Return the dictionary `info` with the additional information, and `sol_summary`, the
272+
optimizer solution summary that can be printed. The dictionary `info` has the following
273+
fields:
274+
275+
- `:ΔU` : optimal manipulated input increments over `Hc` ``(\mathbf{ΔU})``
276+
- `:ϵ` : optimal slack variable ``(ϵ)``
277+
- `:J` : objective value optimum ``(J)``
278+
- `:U` : optimal manipulated inputs over `Hp` ``(\mathbf{U})``
279+
- `:u` : current optimal manipulated input ``(\mathbf{u})``
280+
- `:d` : current measured disturbance ``(\mathbf{d})``
281+
- `:D̂` : predicted measured disturbances over `Hp` ``(\mathbf{D̂})``
282+
- `:ŷ` : current estimated output ``(\mathbf{ŷ})``
283+
- `:Ŷ` : predicted outputs over `Hp` ``(\mathbf{Ŷ = Ŷ_d + Ŷ_s})``
284+
- `:Ŷd` : predicted deterministic output over `Hp` ``(\mathbf{Ŷ_d})``
285+
- `:Ŷs` : predicted stochastic output over `Hp` ``(\mathbf{Ŷ_s})``
286+
- `:R̂y` : predicted output setpoint over `Hp` ``(\mathbf{R̂_y})``
287+
- `:R̂u` : predicted manipulated input setpoint over `Hp` ``(\mathbf{R̂_u})``
288+
289+
# Examples
290+
```jldoctest
291+
julia> mpc = LinMPC(LinModel(tf(5, [2, 1]), 3), Nwt=[0], Hp=1000, Hc=1);
292+
293+
julia> u = moveinput!(mpc, [5]);
295294
295+
julia> info, sol_summary = getinfo(mpc); round.(info[:Ŷ][end], digits=2)
296+
5.0
297+
```
298+
"""
296299
function getinfo(mpc::PredictiveController)
297300
sol_summary = solution_summary(mpc.optim)
298301
info = Dict{Symbol, InfoDictType}()

test/test_predictive_control.jl

+15-6
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,16 @@ end
5656
@test all((-mpc.con.A_Ŷmin[:, end], -mpc.con.A_Ŷmax[:, end]) .≈ ([1.0,1.1], [1.2,1.3]))
5757
end
5858

59-
@testset "LinMPC moves" begin
59+
@testset "LinMPC moves and getinfo" begin
6060
mpc = LinMPC(LinModel(tf(5, [2, 1]), 3), Nwt=[0], Hp=1000, Hc=1)
6161
r = [5]
6262
u = moveinput!(mpc, r)
63-
@test u [1] atol=1e-3
63+
@test u [1] atol=1e-2
6464
u = mpc(r)
65-
@test u [1] atol=1e-3
65+
@test u [1] atol=1e-2
66+
info, _ = getinfo(mpc)
67+
@test info[:u] u
68+
@test info[:Ŷ][end] 5 atol=1e-2
6669
end
6770

6871
@testset "LinMPC other methods" begin
@@ -126,24 +129,30 @@ end
126129
@test all((nmpc.con.c_Ŷmin, nmpc.con.c_Ŷmax) .≈ ([1.0,1.1], [1.2,1.3]))
127130
end
128131

129-
@testset "NonLinMPC moves" begin
132+
@testset "NonLinMPC moves and getinfo" begin
130133
linmodel = LinModel(tf(5, [2, 1]), 3)
131134
nmpc_lin = NonLinMPC(linmodel, Nwt=[0], Hp=1000, Hc=1)
132135
r = [5]
133136
u = moveinput!(nmpc_lin, r)
134137
@test u [1] atol=1e-3
135138
u = nmpc_lin(r)
136139
@test u [1] atol=1e-3
140+
info, _ = getinfo(nmpc_lin)
141+
@test info[:u] u
142+
@test info[:Ŷ][end] 5 atol=1e-2
137143

138144
f(x,u,_) = linmodel.A*x + linmodel.Bu*u
139145
h(x,_) = linmodel.C*x
140146
nonlinmodel = NonLinModel(f, h, 3, 1, 1, 1)
141147
nmpc_nonlin = NonLinMPC(nonlinmodel, Nwt=[0], Hp=1000, Hc=1)
142148
r = [5]
143149
u = moveinput!(nmpc_nonlin, r)
144-
@test u [1] atol=1e-3
150+
@test u [1] atol=1e-2
145151
u = nmpc_nonlin(r)
146-
@test u [1] atol=1e-3
152+
@test u [1] atol=1e-2
153+
info, _ = getinfo(nmpc_nonlin)
154+
@test info[:u] u
155+
@test info[:Ŷ][end] 5 atol=1e-2
147156
end
148157

149158
@testset "NonLinMPC other methods" begin

0 commit comments

Comments
 (0)