Skip to content

Commit 1ccfe12

Browse files
committed
doc: details on internal predict!, con_nonlinprog! and con_nonlinprogeq!
1 parent 4b11e91 commit 1ccfe12

File tree

5 files changed

+67
-30
lines changed

5 files changed

+67
-30
lines changed

docs/src/internals/predictive_control.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,8 @@ ModelPredictiveControl.linconstrainteq!
4141
```@docs
4242
ModelPredictiveControl.optim_objective!(::PredictiveController)
4343
ModelPredictiveControl.set_warmstart!
44+
ModelPredictiveControl.predict!
45+
ModelPredictiveControl.con_nonlinprog!
46+
ModelPredictiveControl.con_nonlinprogeq!
4447
ModelPredictiveControl.getinput!
4548
```

docs/src/internals/state_estim.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ ModelPredictiveControl.linconstraint!(::MovingHorizonEstimator, ::LinModel)
4040
```@docs
4141
ModelPredictiveControl.optim_objective!(::MovingHorizonEstimator)
4242
ModelPredictiveControl.set_warmstart_mhe!
43+
ModelPredictiveControl.predict_mhe!
44+
ModelPredictiveControl.con_nonlinprog_mhe!
4345
```
4446

4547
## Remove Operating Points

src/controller/transcription.jl

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,8 +1119,14 @@ getU0!(U0, mpc::PredictiveController, Z̃) = (mul!(U0, mpc.P̃u, Z̃) .+ mpc.Tu_
11191119
Compute the predictions `Ŷ0`, terminal states `x̂0end` if model is a [`LinModel`](@ref).
11201120
11211121
The method mutates `Ŷ0` and `x̂0end` vector arguments. The `x̂end` vector is used for
1122-
the terminal constraints applied on ``\mathbf{x̂}_{k-1}(k+H_p)``. The computations are
1123-
identical for any [`TranscriptionMethod`](@ref) if the model is linear.
1122+
the terminal constraints applied on ``\mathbf{x̂_0}(k+H_p)``. The computations are
1123+
identical for any [`TranscriptionMethod`](@ref) if the model is linear:
1124+
```math
1125+
\begin{aligned}
1126+
\mathbf{Ŷ_0} &= \mathbf{Ẽ Z̃} + \mathbf{F} \\
1127+
\mathbf{x̂_0}(k+H_p) &= \mathbf{ẽ_x̂ Z̃} + \mathbf{f_x̂}
1128+
\end{aligned}
1129+
```
11241130
"""
11251131
function predict!(
11261132
Ŷ0, x̂0end, _, _, _,
@@ -1142,7 +1148,8 @@ end
11421148
11431149
Compute vectors if `model` is a [`NonLinModel`](@ref) and for [`SingleShooting`](@ref).
11441150
1145-
The method mutates `Ŷ0`, `x̂0end`, `X̂0`, `Û0` and `K0` arguments.
1151+
The method mutates `Ŷ0`, `x̂0end`, `X̂0`, `Û0` and `K0` arguments. The augmented model of
1152+
[`f̂!`](@ref) and [`ĥ!`](@ref) is called recursively in a `for` loop.
11461153
"""
11471154
function predict!(
11481155
Ŷ0, x̂0end, X̂0, Û0, K0,
@@ -1174,17 +1181,18 @@ end
11741181
predict!(
11751182
Ŷ0, x̂0end, _ , _ , _ ,
11761183
mpc::PredictiveController, model::NonLinModel, transcription::TranscriptionMethod,
1177-
U0, Z̃
1184+
_ , Z̃
11781185
) -> Ŷ0, x̂0end
11791186
11801187
Compute vectors if `model` is a [`NonLinModel`](@ref) and other [`TranscriptionMethod`](@ref).
11811188
1182-
The method mutates `Ŷ0` and `x̂0end` arguments.
1189+
The method mutates `Ŷ0` and `x̂0end` arguments. The states `X̂0` are extracted from the
1190+
decisions variables `Z̃` and the augmented output function [`ĥ!`](@ref) is applied on them.
11831191
"""
11841192
function predict!(
11851193
Ŷ0, x̂0end, _, _, _,
11861194
mpc::PredictiveController, model::NonLinModel, ::TranscriptionMethod,
1187-
U0, Z̃
1195+
_ , Z̃
11881196
)
11891197
nu, ny, nd, nx̂, Hp, Hc = model.nu, model.ny, model.nd, mpc.estim.nx̂, mpc.Hp, mpc.Hc
11901198
X̂0 = @views Z̃[(nu*Hc+1):(nu*Hc+nx̂*Hp)] # Z̃ = [ΔU; X̂0; ϵ]
@@ -1209,7 +1217,7 @@ end
12091217
Nonlinear constrains when `model` is a [`LinModel`](@ref).
12101218
12111219
The method mutates the `g` vectors in argument and returns it. Only the custom constraints
1212-
are include in the `g` vector.
1220+
`gc` are include in the `g` vector.
12131221
"""
12141222
function con_nonlinprog!(
12151223
g, ::PredictiveController, ::LinModel, ::TranscriptionMethod, _ , _ , gc, ϵ
@@ -1286,7 +1294,7 @@ function con_nonlinprog!(
12861294
return g
12871295
end
12881296

1289-
"""
1297+
@doc raw"""
12901298
con_nonlinprogeq!(
12911299
geq, X̂0, Û0, K0
12921300
mpc::PredictiveController, model::NonLinModel, transcription::MultipleShooting,
@@ -1295,7 +1303,12 @@ end
12951303
12961304
Nonlinear equality constrains for [`NonLinModel`](@ref) and [`MultipleShooting`](@ref).
12971305
1298-
The method mutates the `geq`, `X̂0`, `Û0` and `K0` vectors in argument.
1306+
The method mutates the `geq`, `X̂0`, `Û0` and `K0` vectors in argument. The defects are
1307+
updated with:
1308+
```math
1309+
\mathbf{ŝ}(k+1) = \mathbf{f̂}\Big(\mathbf{x̂_0}(k), \mathbf{u_0}(k), \mathbf{d_0}(k)\Big)
1310+
+ \text{TODO}
1311+
```
12991312
"""
13001313
function con_nonlinprogeq!(
13011314
geq, X̂0, Û0, K0,
@@ -1394,4 +1407,6 @@ function con_nonlinprogeq!(
13941407
end
13951408
return geq
13961409
end
1410+
1411+
"No equality constraints for other cases e.g. [`SingleShooting`](@ref), returns `geq` unchanged."
13971412
con_nonlinprogeq!(geq,_,_,_,::PredictiveController,::SimModel,::TranscriptionMethod,_,_)=geq

src/estimator/construct.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,14 @@ end
356356
"""
357357
default_nint(model::SimModel, i_ym=1:model.ny, nint_u=0)
358358
359-
One integrator on each measured output by default if `model` is not a [`LinModel`](@ref).
359+
One integrator on each measured output by default for other cases e.g. [`NonLinModel`](@ref).
360360
361-
Theres is no verification the augmented model remains observable. If the integrator quantity
362-
per manipulated input `nint_u ≠ 0`, the method returns zero integrator on each measured
363-
output.
361+
If the integrator quantity per manipulated input `nint_u ≠ 0`, the method returns zero
362+
integrator on each measured output.
363+
364+
!!! warning
365+
Theres is no verification the augmented model remains observable. The resulting
366+
[`StateEstimator`](@ref) object should be assessed separately with e.g.: [`sim!`](@ref).
364367
"""
365368
function default_nint(model::SimModel, i_ym=1:model.ny, nint_u=0)
366369
validate_ym(model, i_ym)

src/estimator/mhe/execute.jl

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function getinfo(estim::MovingHorizonEstimator{NT}) where NT<:Real
115115
info = Dict{Symbol, Any}()
116116
V̂, X̂0 = similar(estim.Y0m[1:nym*Nk]), similar(estim.X̂0[1:nx̂*Nk])
117117
û0, k0, ŷ0 = buffer.û, buffer.k, buffer.
118-
V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, estim.Z̃)
118+
V̂, X̂0 = predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim, model, estim.Z̃)
119119
x̂0arr = @views estim.Z̃[nx̃-nx̂+1:nx̃]
120120
= estim.x̂0arr_old - x̂0arr
121121
X̂0 = [x̂0arr; X̂0]
@@ -418,7 +418,7 @@ function optim_objective!(estim::MovingHorizonEstimator{NT}) where NT<:Real
418418
# --------- update estimate -----------------------
419419
û0, ŷ0, k0 = buffer.û, buffer.ŷ, buffer.k
420420
estim.Ŵ[1:nŵ*Nk] .= @views estim.Z̃[nx̃+1:nx̃+nŵ*Nk] # update Ŵ with optimum for warm-start
421-
V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, estim.Z̃)
421+
V̂, X̂0 = predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim, model, estim.Z̃)
422422
x̂0next = @views X̂0[end-nx̂+1:end]
423423
estim.x̂0 .= x̂0next
424424
return estim.
@@ -461,7 +461,7 @@ function set_warmstart_mhe!(V̂, X̂0, estim::MovingHorizonEstimator{NT}, Z̃var
461461
# --- process noise estimates Ŵ ---
462462
Z̃s[nx̃+1:end] = estim.
463463
# verify definiteness of objective function:
464-
V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃s)
464+
V̂, X̂0 = predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃s)
465465
Js = obj_nonlinprog!(x̄, estim, model, V̂, Z̃s)
466466
if !isfinite(Js)
467467
Z̃s[nx̃+1:end] = 0
@@ -578,16 +578,22 @@ function obj_nonlinprog!(
578578
return dot(x̄, invP̄, x̄) + dot(Ŵ, invQ̂_Nk, Ŵ) + dot(V̂, invR̂_Nk, V̂) +
579579
end
580580

581-
"""
582-
predict!(V̂, X̂0, û0, k0, ŷ0, estim::MovingHorizonEstimator, model::LinModel, Z̃) -> V̂, X̂0
581+
@doc raw"""
582+
predict_mhe!(V̂, X̂0, _, _, _, estim::MovingHorizonEstimator, model::LinModel, Z̃) -> V̂, X̂0
583583
584584
Compute the `V̂` vector and `X̂0` vectors for the `MovingHorizonEstimator` and `LinModel`.
585585
586-
The function mutates `V̂`, `X̂0`, `û0` and `ŷ0` vector arguments. The vector `V̂` is the
587-
estimated sensor noises from ``k-N_k+1`` to ``k``. The `X̂0` vector is estimated states from
588-
``k-N_k+2`` to ``k+1``.
586+
The function mutates `V̂` and `X̂0` vector arguments. The vector `V̂` is the estimated sensor
587+
noises from ``k-N_k+1`` to ``k``. The `X̂0` vector is estimated states from ``k-N_k+2`` to
588+
``k+1``. The computations are (by truncating the matrices when `N_k < H_e`):
589+
```math
590+
\begin{aligned}
591+
\mathbf{V̂} &= \mathbf{Ẽ Z̃} + \mathbf{F} \\
592+
\mathbf{X̂_0} &= \mathbf{Ẽ_x̂ Z̃} + \mathbf{F_x̂}
593+
\end{aligned}
594+
```
589595
"""
590-
function predict!(V̂, X̂0, _ , _ , _ , estim::MovingHorizonEstimator, ::LinModel, Z̃)
596+
function predict_mhe!(V̂, X̂0, _ , _ , _ , estim::MovingHorizonEstimator, ::LinModel, Z̃)
591597
nϵ, Nk = estim.nϵ, estim.Nk[]
592598
nX̂, nŴ, nYm = estim.nx̂*Nk, estim.nx̂*Nk, estim.nym*Nk
593599
nZ̃ =+ estim.nx̂ + nŴ
@@ -596,8 +602,16 @@ function predict!(V̂, X̂0, _ , _ , _ , estim::MovingHorizonEstimator, ::LinMod
596602
return V̂, X̂0
597603
end
598604

599-
"Compute the two vectors when `model` is not a `LinModel`."
600-
function predict!(V̂, X̂0, û0, k0, ŷ0, estim::MovingHorizonEstimator, model::SimModel, Z̃)
605+
@doc raw"""
606+
predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim::MovingHorizonEstimator, model::SimModel, Z̃) -> V̂, X̂0
607+
608+
Compute the vectors when `model` is *not* a [`LinModel`](@ref).
609+
610+
The function mutates `V̂`, `X̂0`, `û0` and `ŷ0` vector arguments. The augmented model of
611+
[`f̂!`](@ref) and [`ĥ!`](@ref) is called recursively in a `for` loop from ``j=1`` to ``N_k``,
612+
and by adding the estimated process noise ``\mathbf{ŵ}``.
613+
"""
614+
function predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim::MovingHorizonEstimator, model::SimModel, Z̃)
601615
nϵ, Nk = estim.nϵ, estim.Nk[]
602616
nu, nd, nx̂, nŵ, nym = model.nu, model.nd, estim.nx̂, estim.nx̂, estim.nym
603617
nx̃ =+ nx̂
@@ -646,18 +660,18 @@ The method mutates all the arguments before `estim` argument.
646660
"""
647661
function update_prediction!(V̂, X̂0, û0, k0, ŷ0, g, estim::MovingHorizonEstimator, Z̃)
648662
model = estim.model
649-
V̂, X̂0 = predict!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃)
663+
V̂, X̂0 = predict_mhe!(V̂, X̂0, û0, k0, ŷ0, estim, model, Z̃)
650664
ϵ = getϵ(estim, Z̃)
651-
g = con_nonlinprog!(g, estim, model, X̂0, V̂, ϵ)
665+
g = con_nonlinprog_mhe!(g, estim, model, X̂0, V̂, ϵ)
652666
return nothing
653667
end
654668

655669
"""
656-
con_nonlinprog!(g, estim::MovingHorizonEstimator, model::SimModel, X̂0, V̂, ϵ)
670+
con_nonlinprog_mhe!(g, estim::MovingHorizonEstimator, model::SimModel, X̂0, V̂, ϵ) -> g
657671
658-
Nonlinear constrains for [`MovingHorizonEstimator`](@ref).
672+
Compute nonlinear constrains `g` in-place for [`MovingHorizonEstimator`](@ref).
659673
"""
660-
function con_nonlinprog!(g, estim::MovingHorizonEstimator, ::SimModel, X̂0, V̂, ϵ)
674+
function con_nonlinprog_mhe!(g, estim::MovingHorizonEstimator, ::SimModel, X̂0, V̂, ϵ)
661675
nX̂con, nX̂ = length(estim.con.X̂0min), estim.nx̂ *estim.Nk[]
662676
nV̂con, nV̂ = length(estim.con.V̂min), estim.nym*estim.Nk[]
663677
for i in eachindex(g)
@@ -684,7 +698,7 @@ function con_nonlinprog!(g, estim::MovingHorizonEstimator, ::SimModel, X̂0, V̂
684698
end
685699

686700
"No nonlinear constraints if `model` is a [`LinModel`](@ref), return `g` unchanged."
687-
con_nonlinprog!(g, ::MovingHorizonEstimator, ::LinModel, _ , _ , _ ) = g
701+
con_nonlinprog_mhe!(g, ::MovingHorizonEstimator, ::LinModel, _ , _ , _ ) = g
688702

689703
"Throw an error if P̂ != nothing."
690704
function setstate_cov!(::MovingHorizonEstimator, P̂)

0 commit comments

Comments
 (0)