Skip to content

Commit d05ab60

Browse files
committed
doc: internals, quadprog update equations (MHE and MPC)
1 parent ebc9c97 commit d05ab60

File tree

6 files changed

+82
-51
lines changed

6 files changed

+82
-51
lines changed

docs/src/internals/predictive_control.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,20 @@ The prediction methodology of this module is mainly based on Maciejowski textboo
1212
## Controller Construction
1313

1414
```@docs
15-
ModelPredictiveControl.init_predmat
1615
ModelPredictiveControl.init_ΔUtoU
17-
ModelPredictiveControl.init_quadprog
18-
ModelPredictiveControl.init_stochpred
19-
ModelPredictiveControl.init_matconstraint_mpc
20-
```
21-
22-
## Constraint Relaxation
23-
24-
```@docs
16+
ModelPredictiveControl.init_predmat
2517
ModelPredictiveControl.relaxU
2618
ModelPredictiveControl.relaxΔU
2719
ModelPredictiveControl.relaxŶ
2820
ModelPredictiveControl.relaxterminal
21+
ModelPredictiveControl.init_quadprog
22+
ModelPredictiveControl.init_stochpred
23+
ModelPredictiveControl.init_matconstraint_mpc
2924
```
3025

31-
## Constraints
26+
## Update Quadratic Optimization
3227

3328
```@docs
29+
ModelPredictiveControl.initpred!(::PredictiveController, ::LinModel, ::Any, ::Any, ::Any, ::Any, ::Any)
3430
ModelPredictiveControl.linconstraint!(::PredictiveController, ::LinModel)
3531
```

docs/src/internals/state_estim.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ ModelPredictiveControl.f̂
1111
ModelPredictiveControl.ĥ
1212
```
1313

14+
## Constraint Relaxation
15+
16+
```@docs
17+
18+
```
19+
1420
## Estimator Construction
1521

1622
```@docs
@@ -20,21 +26,17 @@ ModelPredictiveControl.augment_model
2026
ModelPredictiveControl.init_ukf
2127
ModelPredictiveControl.init_internalmodel
2228
ModelPredictiveControl.init_predmat_mhe
23-
ModelPredictiveControl.init_matconstraint_mhe
24-
```
25-
26-
## Constraint Relaxation
27-
28-
```@docs
2929
ModelPredictiveControl.relaxarrival
3030
ModelPredictiveControl.relaxX̂
3131
ModelPredictiveControl.relaxŴ
3232
ModelPredictiveControl.relaxV̂
33+
ModelPredictiveControl.init_matconstraint_mhe
3334
```
3435

35-
## Constraints
36+
## Update Quadratic Optimization
3637

3738
```@docs
39+
ModelPredictiveControl.initpred!(::MovingHorizonEstimator, ::LinModel)
3840
ModelPredictiveControl.linconstraint!(::MovingHorizonEstimator, ::LinModel)
3941
```
4042

src/controller/construct.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,16 +523,21 @@ end
523523
@doc raw"""
524524
init_quadprog(model::LinModel, Ẽ, S, M_Hp, N_Hc, L_Hp) -> H̃, q̃, p
525525
526-
Init the quadratic programming optimization matrix `H̃` and `q̃` for MPC.
526+
Init the quadratic programming optimization matrix `H̃` and `q̃` and scalar `p` for MPC.
527527
528528
The matrices appear in the quadratic general form :
529529
```math
530530
J = \min_{\mathbf{ΔŨ}} \frac{1}{2}\mathbf{(ΔŨ)'H̃(ΔŨ)} + \mathbf{q̃'(ΔŨ)} + p
531531
```
532-
``\mathbf{H̃}`` is constant if the model and weights are linear and time invariant (LTI). The
533-
vector ``\mathbf{q̃}`` and scalar ``p`` need recalculation each control period ``k``. ``p``
534-
does not impact the minima position. It is thus useless at optimization but required to
535-
evaluate the minimal ``J`` value.
532+
The Hessian matrix is constant if the model and weights are linear and time invariant (LTI):
533+
```math
534+
\mathbf{H̃} = 2 ( \mathbf{Ẽ}'\mathbf{M}_{H_p}\mathbf{Ẽ} + \mathbf{Ñ}_{H_c}
535+
+ \mathbf{S̃}'\mathbf{L}_{H_p}\mathbf{S̃} )
536+
```
537+
The vector ``\mathbf{q̃}`` and scalar ``p`` need recalculation each control period ``k`` (init
538+
with zeros, the method [`initpred!`](@ref) compute the real values). ``p`` does not impact
539+
the minima position. It is thus useless at optimization but required to evaluate the minimal
540+
``J`` value.
536541
"""
537542
function init_quadprog(::LinModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:Real}
538543
= Hermitian(convert(Matrix{NT}, 2*(Ẽ'*M_Hp*+ Ñ_Hc +'*L_Hp*S̃)), :L)

src/controller/execute.jl

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,21 @@ end
135135

136136

137137
@doc raw"""
138-
initpred!(mpc, model::LinModel, d, ym, D̂, R̂y, R̂u)
138+
initpred!(mpc, model::LinModel, d, ym, D̂, R̂y, R̂u) -> nothing
139139
140140
Init linear model prediction matrices `F, q̃, p` and current estimated output `ŷ`.
141141
142142
See [`init_predmat`](@ref) and [`init_quadprog`](@ref) for the definition of the matrices.
143+
They are computed with:
144+
```math
145+
\begin{aligned}
146+
\mathbf{F} &= \mathbf{G d}(k) + \mathbf{J D̂} + \mathbf{K x̂}_{k-1}(k) + \mathbf{V u}(k-1) \\
147+
\mathbf{C_y} &= \mathbf{F} - \mathbf{R̂_y} \\
148+
\mathbf{C_u} &= \mathbf{T} \mathbf{u}(k-1) - \mathbf{R̂_u} \\
149+
\mathbf{q̃} &= 2[(\mathbf{M}_{H_p} \mathbf{Ẽ})' \mathbf{C_y} + (\mathbf{L}_{H_p} \mathbf{S̃})' \mathbf{C_u}] \\
150+
p &= \mathbf{C_y}' \mathbf{M}_{H_p} \mathbf{C_y} + \mathbf{C_u}' \mathbf{L}_{H_p} \mathbf{C_u}
151+
\end{aligned}
152+
```
143153
"""
144154
function initpred!(mpc::PredictiveController, model::LinModel, d, ym, D̂, R̂y, R̂u)
145155
mpc.ŷ[:] = evalŷ(mpc.estim, ym, d)
@@ -151,15 +161,15 @@ function initpred!(mpc::PredictiveController, model::LinModel, d, ym, D̂, R̂y,
151161
mpc.F[:] = mpc.F + mpc.G * mpc.d0 + mpc.J * mpc.D̂0
152162
end
153163
mpc.R̂y[:] = R̂y
154-
= mpc.F - mpc.R̂y
155-
mpc.q̃[:] = 2(mpc.M_Hp*mpc.Ẽ)'*
156-
mpc.p[] = dot(, mpc.M_Hp, )
164+
C_y = mpc.F - mpc.R̂y
165+
mpc.q̃[:] = 2(mpc.M_Hp*mpc.Ẽ)'*C_y
166+
mpc.p[] = dot(C_y, mpc.M_Hp, C_y)
157167
if ~mpc.noR̂u
158168
mpc.R̂u[:] = R̂u
159169
lastu = mpc.estim.lastu0 + model.uop
160-
= mpc.T*lastu - mpc.R̂u
161-
mpc.q̃[:] = mpc.+ 2(mpc.L_Hp*mpc.S̃)'*
162-
mpc.p[] = mpc.p[] + dot(, mpc.L_Hp, )
170+
C_u = mpc.T*lastu - mpc.R̂u
171+
mpc.q̃[:] = mpc.+ 2(mpc.L_Hp*mpc.S̃)'*C_u
172+
mpc.p[] = mpc.p[] + dot(C_y, mpc.L_Hp, C_u)
163173
end
164174
return nothing
165175
end
@@ -216,7 +226,8 @@ predictstoch!(::PredictiveController, ::StateEstimator, _ , _ ) = nothing
216226
217227
Set `b` vector for the linear model inequality constraints (``\mathbf{A ΔŨ ≤ b}``).
218228
219-
Also init ``\mathbf{f_x̂}`` vector for the terminal constraints, see [`init_predmat`](@ref).
229+
Also init ``\mathbf{f_x̂} = \mathbf{g_x̂ d}(k) + \mathbf{j_x̂ D̂} + \mathbf{k_x̂ x̂}_{k-1}(k) + \mathbf{v_x̂ u}(k-1)``
230+
vector for the terminal constraints, see [`init_predmat`](@ref).
220231
"""
221232
function linconstraint!(mpc::PredictiveController, model::LinModel)
222233
mpc.con.fx̂[:] = mpc.con.kx̂ * mpc.estim.+ mpc.con.vx̂ * mpc.estim.lastu0

src/estimator/mhe/construct.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -777,30 +777,29 @@ end
777777
778778
Construct the MHE prediction matrices for [`LinModel`](@ref) `model`.
779779
780-
Introducing the vector ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{x̂}_k(k-H_e+1)
780+
Introducing the vector ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{x̂}_k(k-N_k+1)
781781
\\ \mathbf{Ŵ} \end{smallmatrix}]`` with the decision variables, the estimated sensor
782-
noises from time ``k-H_e+1`` to ``k`` are computed by:
782+
noises from time ``k-N_k+1`` to ``k`` are computed by:
783783
```math
784784
\begin{aligned}
785785
\mathbf{V̂} = \mathbf{Y^m - Ŷ^m} &= \mathbf{E Z + G U + J D + Y^m} \\
786786
&= \mathbf{E Z + F}
787787
\end{aligned}
788788
```
789789
in which ``\mathbf{U, D}`` and ``\mathbf{Y^m}`` contains respectively the manipulated
790-
inputs, measured disturbances and measured outputs from time ``k-H_e+1`` to ``k``. The
790+
inputs, measured disturbances and measured outputs from time ``k-N_k+1`` to ``k``. The
791791
method also returns similar matrices but for the estimation error at arrival:
792792
```math
793-
\mathbf{x̄} = \mathbf{x̂}_{k-H_e}(k-H_e+1) - \mathbf{x̂}_{k}(k-H_e+1) = \mathbf{e_x̄ Z + f_x̄}
793+
\mathbf{x̄} = \mathbf{x̂}_{k-N_k}(k-N_k+1) - \mathbf{x̂}_{k}(k-N_k+1) = \mathbf{e_x̄ Z + f_x̄}
794794
```
795-
Lastly, the estimated states from time ``k-H_e+2`` to ``k+1`` are given by the equation:
795+
Lastly, the estimated states from time ``k-N_k+2`` to ``k+1`` are given by the equation:
796796
```math
797797
\begin{aligned}
798798
\mathbf{X̂} &= \mathbf{E_x̂ Z + G_x̂ U + J_x̂ D} \\
799799
&= \mathbf{E_x̂ Z + F_x̂}
800800
\end{aligned}
801801
```
802-
All these equations omit the operating points ``\mathbf{u_{op}, y_{op}, d_{op}}``. These
803-
matrices are truncated when ``N_k < H_e`` (at the beginning).
802+
All these equations omit the operating points ``\mathbf{u_{op}, y_{op}, d_{op}}``.
804803
805804
# Extended Help
806805
!!! details "Extended Help"
@@ -850,6 +849,7 @@ matrices are truncated when ``N_k < H_e`` (at the beginning).
850849
\mathbf{Â}^{H_e-1}\mathbf{B̂_d} & \mathbf{Â}^{H_e-2}\mathbf{B̂_d} & \cdots & \mathbf{Â}^{0}\mathbf{B̂_d} \end{bmatrix}
851850
\end{aligned}
852851
```
852+
All these matrices are truncated when ``N_k < H_e`` (at the beginning).
853853
"""
854854
function init_predmat_mhe(model::LinModel{NT}, He, i_ym, Â, B̂u, Ĉ, B̂d, D̂d) where {NT<:Real}
855855
nu, nd = model.nu, model.nd

src/estimator/mhe/execute.jl

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,30 @@ function add_data_windows!(estim::MovingHorizonEstimator, u, d, ym)
183183
end
184184

185185
@doc raw"""
186-
initpred!(estim::MovingHorizonEstimator, model::LinModel)
186+
initpred!(estim::MovingHorizonEstimator, model::LinModel) -> nothing
187187
188-
Init linear model prediction matrices `F, fx̄, H̃, q̃, p` for [`MovingHorizonEstimator`](@ref).
188+
Init quadratic optimization matrices `F, fx̄, H̃, q̃, p` for [`MovingHorizonEstimator`](@ref).
189189
190-
Also init `estim.optim` objective function. See [`init_predmat_mhe`](@ref) for the
191-
definition of the matrices. The Hessian ``H̃`` matrix of the quadratic general form is not
192-
constant here because of the time-varying ``\mathbf{P̄}`` weight (the estimation error
193-
covariance at arrival).
190+
See [`init_predmat_mhe`](@ref) for the definition of the vectors ``\mathbf{F, f_x̄}``. It
191+
also inits `estim.optim` objective function, expressed as the quadratic general form:
192+
```math
193+
J = \min_{\mathbf{Z̃}} \frac{1}{2}\mathbf{Z̃' H̃ Z̃} + \mathbf{q̃' Z̃} + p
194+
```
195+
The Hessian ``\mathbf{H̃}`` matrix of the quadratic general form is not constant here because
196+
of the time-varying ``\mathbf{P̄}`` covariance . The matrices are computed with:
197+
```math
198+
\begin{aligned}
199+
\mathbf{F} &= \mathbf{G U} + \mathbf{J D} + \mathbf{Y^m} \\
200+
\mathbf{f_x̄} &= \mathbf{x̂}_{k-N_k}(k-N_k+1) \\
201+
\mathbf{F_Z̃} &= [\begin{smallmatrix}\mathbf{f_x̄} \\ \mathbf{F} \end{smallmatrix}] \\
202+
\mathbf{Ẽ_Z̃} &= [\begin{smallmatrix}\mathbf{ẽ_x̄} \\ \mathbf{Ẽ} \end{smallmatrix}] \\
203+
\mathbf{M}_{N_k} &= \mathrm{diag}(\mathbf{P̄}^{-1}, \mathbf{R̂}_{N_k}^{-1}) \\
204+
\mathbf{Ñ}_{N_k} &= \mathrm{diag}(C, \mathbf{0}, \mathbf{Q̂}_{N_k}^{-1}) \\
205+
\mathbf{H̃} &= 2(\mathbf{Ẽ_Z̃}' \mathbf{M}_{N_k} \mathbf{Ẽ_Z̃} + \mathbf{Ñ}_{N_k}) \\
206+
\mathbf{q̃} &= 2(\mathbf{M}_{N_k} \mathbf{Ẽ_Z̃})' \mathbf{F_Z̃} \\
207+
p &= \mathbf{F_Z̃}' \mathbf{M}_{N_k} \mathbf{F_Z̃}
208+
\end{aligned}
209+
```
194210
"""
195211
function initpred!(estim::MovingHorizonEstimator, model::LinModel)
196212
C, optim = estim.C, estim.optim
@@ -205,14 +221,14 @@ function initpred!(estim::MovingHorizonEstimator, model::LinModel)
205221
end
206222
estim.fx̄[:] = estim.x̂arr_old
207223
# --- update H̃, q̃ and p vectors for quadratic optimization ---
208-
= @views [estim.ẽx̄[:, 1:nZ̃]; estim.Ẽ[1:nYm, 1:nZ̃]]
209-
F = @views [estim.fx̄; estim.F[1:nYm]]
224+
ẼZ̃ = @views [estim.ẽx̄[:, 1:nZ̃]; estim.Ẽ[1:nYm, 1:nZ̃]]
225+
FZ̃ = @views [estim.fx̄; estim.F[1:nYm]]
210226
invQ̂_Nk, invR̂_Nk = @views estim.invQ̂_He[1:nŴ, 1:nŴ], estim.invR̂_He[1:nYm, 1:nYm]
211-
M = [estim.invP̄ zeros(nx̂, nYm); zeros(nYm, nx̂) invR̂_Nk]
212-
= [fill(C, nϵ, nϵ) zeros(nϵ, nx̂+nŴ); zeros(nx̂, nϵ+nx̂+nŴ); zeros(nŴ, nϵ+nx̂) invQ̂_Nk]
213-
estim.q̃[1:nZ̃] = 2(M*)'*F
214-
estim.p[] = dot(F, M, F)
215-
estim..data[1:nZ̃, 1:nZ̃] = 2*('*M* + )
227+
M_Nk = [estim.invP̄ zeros(nx̂, nYm); zeros(nYm, nx̂) invR̂_Nk]
228+
Ñ_Nk = [fill(C, nϵ, nϵ) zeros(nϵ, nx̂+nŴ); zeros(nx̂, nϵ+nx̂+nŴ); zeros(nŴ, nϵ+nx̂) invQ̂_Nk]
229+
estim.q̃[1:nZ̃] = 2(M_Nk*ẼZ̃)'*FZ̃
230+
estim.p[] = dot(FZ̃, M_Nk, FZ̃)
231+
estim..data[1:nZ̃, 1:nZ̃] = 2*(ẼZ̃'*M_Nk*ẼZ̃ + Ñ_Nk)
216232
Z̃var_Nk::Vector{VariableRef} = @views optim[:Z̃var][1:nZ̃]
217233
H̃_Nk = @views estim.H̃[1:nZ̃,1:nZ̃]
218234
q̃_Nk = @views estim.q̃[1:nZ̃]
@@ -227,7 +243,8 @@ initpred!(::MovingHorizonEstimator, ::SimModel) = nothing
227243
228244
Set `b` vector for the linear model inequality constraints (``\mathbf{A Z̃ ≤ b}``) of MHE.
229245
230-
Also init ``\mathbf{F_x̂}`` vector for the state constraints, see [`init_predmat_mhe`](@ref).
246+
Also init ``\mathbf{F_x̂ = G_x̂ U + J_x̂ D}`` vector for the state constraints, see
247+
[`init_predmat_mhe`](@ref).
231248
"""
232249
function linconstraint!(estim::MovingHorizonEstimator, model::LinModel)
233250
estim.con.Fx̂[:] = estim.con.Gx̂*estim.U

0 commit comments

Comments
 (0)