Skip to content

Commit ef4868f

Browse files
authored
Merge pull request #335 from JuliaControl/colloc_lin_defect
added: stochastic state defects as linear equality constraints for all `CollocationMethod`s
2 parents 4be6029 + c970f13 commit ef4868f

File tree

10 files changed

+256
-177
lines changed

10 files changed

+256
-177
lines changed

docs/src/internals/state_estim.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ ModelPredictiveControl.get_nonlincon_oracle(::MovingHorizonEstimator, ::ModelPre
2727
```@docs
2828
ModelPredictiveControl.f̂!
2929
ModelPredictiveControl.ĥ!
30-
ModelPredictiveControl.f̂_input!
3130
```
3231

3332
## Update Quadratic Optimization

src/controller/construct.jl

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ struct ControllerConstraint{NT<:Real, GCfunc<:Union{Nothing, Function}}
133133
vx̂ ::Matrix{NT}
134134
bx̂ ::Vector{NT}
135135
# matrices for the zero defect constraints (N/A for single shooting transcriptions):
136-
Ẽŝ ::Matrix{NT}
137-
Fŝ ::Vector{NT}
138-
Gŝ ::Matrix{NT}
139-
Jŝ ::Matrix{NT}
140-
Kŝ ::Matrix{NT}
141-
Vŝ ::Matrix{NT}
142-
Bŝ ::Vector{NT}
136+
ẼS ::Matrix{NT}
137+
FS ::Vector{NT}
138+
GS ::Matrix{NT}
139+
JS ::Matrix{NT}
140+
KS ::Matrix{NT}
141+
VS ::Matrix{NT}
142+
BS ::Vector{NT}
143143
# custom linear equality constraints:
144144
Ẽw ::Matrix{NT}
145145
Fw ::Vector{NT}
@@ -176,7 +176,6 @@ struct ControllerConstraint{NT<:Real, GCfunc<:Union{Nothing, Function}}
176176
# indices of finite numbers in the b vector (linear inequality constraints):
177177
i_b ::BitVector
178178
# A matrices for the linear equality constraints:
179-
A_ŝ ::Matrix{NT}
180179
Aeq ::Matrix{NT}
181180
# b vector for the linear equality constraints:
182181
beq ::Vector{NT}
@@ -518,7 +517,7 @@ function setconstraint!(
518517
con.A_Umin, con.A_Umax, con.A_ΔŨmin, con.A_ΔŨmax,
519518
con.A_Ymin, con.A_Ymax, con.A_Wmin, con.A_Wmax,
520519
con.A_x̂min, con.A_x̂max,
521-
con.A_ŝ
520+
con.Aeq
522521
)
523522
A = con.A[con.i_b, :]
524523
b = con.b[con.i_b]
@@ -858,7 +857,7 @@ verify_cond(::TranscriptionMethod,_,_) = nothing
858857
Hp, Hc,
859858
PΔu, Pu, E,
860859
ex̂, gx̂, jx̂, kx̂, vx̂, bx̂,
861-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ,
860+
ES, GS, JS, KS, VS, BS,
862861
Wy, Wu, Wd, Wr,
863862
gc!=nothing, nc=0
864863
) -> con, nϵ, P̃Δu, P̃u, Ẽ
@@ -874,14 +873,15 @@ function init_defaultcon_mpc(
874873
Hp, Hc,
875874
PΔu, Pu, E,
876875
ex̂, gx̂, jx̂, kx̂, vx̂, bx̂,
877-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ,
876+
ES, GS, JS, KS, VS, BS,
878877
Wy, Wu, Wd, Wr,
879878
gc!::GCfunc = nothing, nc = 0
880879
) where {NT<:Real, GCfunc<:Union{Nothing, Function}}
881880
model = estim.model
882881
nu, ny, nx̂ = model.nu, model.ny, estim.nx̂
883882
nw = size(Wy, 1)
884883
nW = nw*(Hp+1)
884+
nS = size(ES, 1)
885885
= weights.isinf_C ? 0 : 1
886886
u0min, u0max = fill(convert(NT,-Inf), nu), fill(convert(NT,+Inf), nu)
887887
Δumin, Δumax = fill(convert(NT,-Inf), nu), fill(convert(NT,+Inf), nu)
@@ -910,7 +910,7 @@ function init_defaultcon_mpc(
910910
A_Ymin, A_Ymax, Ẽ = relaxŶ(E, C_ymin, C_ymax, nϵ)
911911
A_Wmin, A_Wmax, Ẽw = relaxW(E, Pu, Hp, W̄y, W̄u, C_wmin, C_wmax, nϵ)
912912
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(ex̂, c_x̂min, c_x̂max, nϵ)
913-
A_ŝ, Ẽŝ = augmentdefect(Eŝ, nϵ)
913+
Aeq, ẼS = augmentdefect(ES, nϵ)
914914
i_Umin, i_Umax = .!isinf.(U0min), .!isinf.(U0max)
915915
i_ΔŨmin, i_ΔŨmax = .!isinf.(ΔŨmin), .!isinf.(ΔŨmax)
916916
i_Ymin, i_Ymax = .!isinf.(Y0min), .!isinf.(Y0max)
@@ -920,22 +920,21 @@ function init_defaultcon_mpc(
920920
model, transcription, nc,
921921
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_Wmin, i_Wmax, i_x̂min, i_x̂max,
922922
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_Wmin, A_Wmax, A_x̂max, A_x̂min,
923-
A_ŝ
923+
Aeq
924924
)
925-
# dummy fx̂, Fw and Fŝ vectors (updated just before optimization)
926-
fx̂, Fw, Fŝ = zeros(NT, nx̂), zeros(NT, nW), zeros(NT, nx̂*Hp)
925+
# dummy fx̂, Fw and FS vectors (updated just before optimization)
926+
fx̂, Fw, FS = zeros(NT, nx̂), zeros(NT, nW), zeros(NT, nS)
927927
# dummy b and beq vectors (updated just before optimization)
928928
b, beq = zeros(NT, size(A, 1)), zeros(NT, size(Aeq, 1))
929929
con = ControllerConstraint{NT, GCfunc}(
930930
ẽx̂ , fx̂ , gx̂ , jx̂ , kx̂ , vx̂ , bx̂ ,
931-
Ẽŝ , Fŝ , Gŝ , Jŝ , Kŝ , Vŝ , Bŝ ,
931+
ẼS , FS , GS , JS , KS , VS , BS ,
932932
Ẽw , Fw , W̄y , W̄u , W̄d , W̄r , nw ,
933933
U0min , U0max , ΔŨmin , ΔŨmax ,
934934
Y0min , Y0max , Wmin , Wmax , x̂0min , x̂0max ,
935935
A_Umin , A_Umax , A_ΔŨmin , A_ΔŨmax ,
936936
A_Ymin , A_Ymax , A_Wmin , A_Wmax , A_x̂min , A_x̂max ,
937937
A , b , i_b ,
938-
A_ŝ ,
939938
Aeq , beq ,
940939
neq ,
941940
C_ymin , C_ymax , C_wmin , C_wmax , c_x̂min , c_x̂max ,
@@ -1194,24 +1193,24 @@ function relaxterminal(ex̂::AbstractMatrix{NT}, c_x̂min, c_x̂max, nϵ) where
11941193
end
11951194

11961195
@doc raw"""
1197-
augmentdefect(Eŝ, nϵ) -> A_ŝ, Ẽŝ
1196+
augmentdefect(ES, nϵ) -> Aeq, ẼS
11981197
11991198
Augment defect equality constraints with slack variable ϵ if `nϵ == 1`.
12001199
1201-
It returns the ``\mathbf{Ẽ_ŝ}`` matrix that appears in the defect equation
1202-
``\mathbf{Ŝ = Ẽ_ŝ Z̃ + F_ŝ}`` and the ``\mathbf{A}`` matrix for the equality constraints:
1200+
It returns the ``\mathbf{Ẽ_S}`` matrix that appears in the linear defect equation
1201+
``\mathbf{Ẽ_S Z̃ + F_S}`` and the ``\mathbf{A}`` matrix for the equality constraints:
12031202
```math
1204-
\mathbf{A_ŝ Z̃} = - \mathbf{F_ŝ}
1203+
\mathbf{A_{eq} Z̃} = \mathbf{b_{eq}} = - \mathbf{F_S}
12051204
```
12061205
"""
1207-
function augmentdefect(Eŝ::AbstractMatrix{NT}, nϵ) where NT<:Real
1206+
function augmentdefect(ES::AbstractMatrix{NT}, nϵ) where NT<:Real
12081207
if== 1 # Z̃ = [Z; ϵ]
1209-
Ẽŝ = [Eŝ zeros(NT, size(Eŝ, 1), 1)]
1208+
ẼS = [ES zeros(NT, size(ES, 1), 1)]
12101209
else # Z̃ = Z (only hard constraints)
1211-
Ẽŝ = Eŝ
1210+
ẼS = ES
12121211
end
1213-
A_ŝ = Ẽŝ
1214-
return A_ŝ, Ẽŝ
1212+
Aeq = ẼS
1213+
return Aeq, ẼS
12151214
end
12161215

12171216
@doc raw"""

src/controller/execute.jl

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ function moveinput!(
7474
validate_args(mpc, ry, d, lastu, D̂, R̂y, R̂u)
7575
initpred!(mpc, mpc.estim.model, ry, d, lastu, D̂, R̂y, R̂u)
7676
linconstraint!(mpc, mpc.estim.model, mpc.transcription)
77-
linconstrainteq!(mpc, mpc.estim.model, mpc.transcription)
77+
linconstrainteq!(mpc, mpc.estim.model, mpc.estim, mpc.transcription)
7878
= optim_objective!(mpc)
7979
return getinput!(mpc, Z̃)
8080
end
@@ -312,7 +312,36 @@ function predictstoch!(Ŷs, mpc::PredictiveController, estim::InternalModel)
312312
return nothing
313313
end
314314
"Fill `Ŷs` vector with 0 values when `estim` is not an [`InternalModel`](@ref)."
315-
predictstoch!(Ŷs, mpc::PredictiveController, ::StateEstimator) = (Ŷs .= 0; nothing)
315+
predictstoch!(Ŷs, ::PredictiveController, ::StateEstimator) = (Ŷs .= 0; nothing)
316+
317+
"""
318+
disturbedinput!(Û0, mpc::PredictiveController, estim::StateEstimator, U0, X̂0) -> nothing
319+
320+
Fill disturbed inputs of the augmented model `Û0` in-place with stochastic states in `X̂0`
321+
322+
Both `Û0` and `U0` variables include deviation vectors from ``k+0`` to ``k+H_p-1``. The
323+
predicted states `X̂0` include deviation vectors from ``k+1`` to ``k+H_p-1`` (the current one
324+
is stored in `estim.x̂0`).
325+
326+
This function is used for the collocation methods that directly call the state derivative
327+
function `estim.model.f!` with the manipulated inputs augmented with the estimated
328+
disturbances at model input (see [`init_estimstoch`](@ref)). It's also necessary to prefill
329+
the `Û0` vector before anything since both `û0` and `û0next` are needed at each stage with
330+
hold order `h>0`, thus potential race conditions with multi-threading.
331+
"""
332+
function disturbedinput!(Û0, mpc::PredictiveController, estim::StateEstimator, U0, X̂0)
333+
nu, nx, nx̂ = estim.model.nu, estim.model.nx, estim.nx̂
334+
Cs_u = estim.Cs_u
335+
Û0 .= U0
336+
for j=0:mpc.Hp-1
337+
xs = @views j < 1 ? estim.x̂0[(nx+1):(nx̂)] : X̂0[(nx+1+nx̂*(j-1)):(nx̂*j)]
338+
û0 = @views Û0[(1+nu*j):(nu*(j+1))]
339+
mul!(û0, Cs_u, xs, 1, 1) # û0 = u0 + Cs_u*xs
340+
end
341+
return nothing
342+
end
343+
"No input disturbances for [`InternalModel`](@ref), hence do `Û0 .= U0`."
344+
disturbedinput!(Û0, ::PredictiveController, ::InternalModel, U0, _) = (Û0 .= U0; nothing)
316345

317346
@doc raw"""
318347
linconstraint_custom!(mpc::PredictiveController, model::SimModel)
@@ -690,14 +719,14 @@ function setmodel_controller!(mpc::PredictiveController, uop_old, x̂op_old)
690719
con.vx̂ .= vx̂
691720
con.bx̂ .= bx̂
692721
# --- defect matrices ---
693-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ = init_defectmat(model, estim, transcription, Hp, Hc, nb)
694-
A_ŝ, Ẽŝ = augmentdefect(Eŝ, mpc.nϵ)
695-
con.Ẽŝ .= Ẽŝ
696-
con.Gŝ .= Gŝ
697-
con.Jŝ .= Jŝ
698-
con.Kŝ .= Kŝ
699-
con.Vŝ .= Vŝ
700-
con.Bŝ .= Bŝ
722+
ES, GS, JS, KS, VS, BS = init_defectmat(model, estim, transcription, Hp, Hc, nb)
723+
Aeq, ẼS = augmentdefect(ES, mpc.nϵ)
724+
con.ẼS .= ẼS
725+
con.GS .= GS
726+
con.JS .= JS
727+
con.KS .= KS
728+
con.VS .= VS
729+
con.BS .= BS
701730
# --- custom linear constraints ---
702731
con.Ẽw .= Ẽw
703732
# --- linear inequality constraints ---
@@ -718,8 +747,7 @@ function setmodel_controller!(mpc::PredictiveController, uop_old, x̂op_old)
718747
con.A_x̂max
719748
]
720749
# --- linear equality constraints ---
721-
con.A_ŝ .= A_ŝ
722-
con.Aeq .= A_ŝ
750+
con.Aeq .= Aeq
723751
# --- operating points ---
724752
con.U0min .+= mpc.Uop # convert U0 to U with the old operating point
725753
con.U0max .+= mpc.Uop # convert U0 to U with the old operating point

src/controller/explicitmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ function Base.show(io::IO, mpc::ExplicitMPC)
191191
print_estim_dim(io, mpc.estim, n)
192192
end
193193

194-
linconstraint!(::ExplicitMPC, ::LinModel, ::TranscriptionMethod) = nothing
194+
linconstraint!(::ExplicitMPC, ::LinModel, ::SingleShooting) = nothing
195+
linconstrainteq!(::ExplicitMPC, ::LinModel, ::StateEstimator, ::SingleShooting) = nothing
196+
linconstrainteq!(::ExplicitMPC, ::LinModel, ::InternalModel, ::SingleShooting) = nothing
195197

196198
@doc raw"""
197199
optim_objective!(mpc::ExplicitMPC) -> Z̃

src/controller/linmpc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ struct LinMPC{
7373
model, estim, transcription, Hp, Hc, nb
7474
)
7575
F = zeros(NT, ny*Hp) # dummy value (updated just before optimization)
76-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ = init_defectmat(model, estim, transcription, Hp, Hc, nb)
76+
ES, GS, JS, KS, VS, BS = init_defectmat(model, estim, transcription, Hp, Hc, nb)
7777
con, nϵ, P̃Δu, P̃u, Ẽ = init_defaultcon_mpc(
7878
estim, weights, transcription,
7979
Hp, Hc,
8080
PΔu, Pu, E,
8181
ex̂, gx̂, jx̂, kx̂, vx̂, bx̂,
82-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ,
82+
ES, GS, JS, KS, VS, BS,
8383
Wy, Wu, Wd, Wr
8484
)
8585
= init_quadprog(model, transcription, weights, Ẽ, P̃Δu, P̃u)

src/controller/nonlinmpc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,13 @@ struct NonLinMPC{
103103
model, estim, transcription, Hp, Hc, nb
104104
)
105105
F = zeros(NT, ny*Hp) # dummy value (updated just before optimization)
106-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ = init_defectmat(model, estim, transcription, Hp, Hc, nb)
106+
ES, GS, JS, KS, VS, BS = init_defectmat(model, estim, transcription, Hp, Hc, nb)
107107
con, nϵ, P̃Δu, P̃u, Ẽ = init_defaultcon_mpc(
108108
estim, weights, transcription,
109109
Hp, Hc,
110110
PΔu, Pu, E,
111111
ex̂, gx̂, jx̂, kx̂, vx̂, bx̂,
112-
Eŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ,
112+
ES, GS, JS, KS, VS, BS,
113113
Wy, Wu, Wd, Wr,
114114
gc!, nc
115115
)

0 commit comments

Comments
 (0)