Skip to content

Commit 303c018

Browse files
committed
wip: multiple shooting transcription
1 parent 918dacd commit 303c018

File tree

6 files changed

+53
-27
lines changed

6 files changed

+53
-27
lines changed

src/controller/construct.jl

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ function validate_args(mpc::PredictiveController, ry, d, D̂, R̂y, R̂u)
472472
end
473473

474474
@doc raw"""
475-
init_quadprog(model::LinModel, weights::ControllerWeights, Ẽ, S) -> H̃
475+
init_quadprog(model::LinModel, weights::ControllerWeights, Ẽ, P̃, S̃) -> H̃
476476
477477
Init the quadratic programming Hessian `H̃` for MPC.
478478
@@ -489,9 +489,9 @@ The vector ``\mathbf{q̃}`` and scalar ``r`` need recalculation each control per
489489
[`initpred!`](@ref). ``r`` does not impact the minima position. It is thus useless at
490490
optimization but required to evaluate the minimal ``J`` value.
491491
"""
492-
function init_quadprog(::LinModel, weights::ControllerWeights, Ẽ, S̃)
492+
function init_quadprog(::LinModel, weights::ControllerWeights, Ẽ, P̃, S̃)
493493
M_Hp, Ñ_Hc, L_Hp = weights.M_Hp, weights.Ñ_Hc, weights.L_Hp
494-
= Hermitian(2*(Ẽ'*M_Hp*+ Ñ_Hc +'*L_Hp*S̃), :L)
494+
= Hermitian(2*(Ẽ'*M_Hp*+ '*Ñ_Hc* +'*L_Hp*S̃), :L)
495495
return
496496
end
497497
"Return empty matrix if `model` is not a [`LinModel`](@ref)."
@@ -502,7 +502,7 @@ end
502502

503503
"""
504504
init_defaultcon_mpc(
505-
estim::StateEstimator,
505+
estim::StateEstimator, transcription::TranscriptionMethod,
506506
Hp, Hc, C,
507507
P, S, E,
508508
ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂,
@@ -515,7 +515,7 @@ Init `ControllerConstraint` struct with default parameters based on estimator `e
515515
Also return `P̃`, `S̃`, `Ẽ` and `Ẽŝ` matrices for the the augmented decision vector `Z̃`.
516516
"""
517517
function init_defaultcon_mpc(
518-
estim::StateEstimator{NT},
518+
estim::StateEstimator{NT}, transcription::TranscriptionMethod,
519519
Hp, Hc, C,
520520
P, S, E,
521521
ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂,
@@ -538,7 +538,9 @@ function init_defaultcon_mpc(
538538
C_umin, C_umax, C_Δumin, C_Δumax, C_ymin, C_ymax =
539539
repeat_constraints(Hp, Hc, c_umin, c_umax, c_Δumin, c_Δumax, c_ymin, c_ymax)
540540
A_Umin, A_Umax, S̃ = relaxU(model, nϵ, C_umin, C_umax, S)
541-
A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, P̃ = relaxΔU(model, nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P)
541+
A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, P̃ = relaxΔU(
542+
model, transcription, nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P
543+
)
542544
A_Ymin, A_Ymax, Ẽ = relaxŶ(model, nϵ, C_ymin, C_ymax, E)
543545
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(model, nϵ, c_x̂min, c_x̂max, ex̂)
544546
A_ŝ, Ẽŝ = augmentdefect(model, nϵ, Eŝ)
@@ -619,15 +621,17 @@ end
619621

620622
@doc raw"""
621623
relaxΔU(
622-
model, nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P
624+
model, transcription, nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P
623625
) -> A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, P̃
624626
625627
Augment input increments constraints with slack variable ϵ for softening.
626628
627629
Denoting the decision variables augmented with the slack variable
628630
``\mathbf{Z̃} = [\begin{smallmatrix} \mathbf{Z} \\ ϵ \end{smallmatrix}]``, it returns the
629631
augmented conversion matrix ``\mathbf{P̃}``, similar to the one described at
630-
[`init_ZtoΔU`](@ref). Knowing that ``0 ≤ ϵ ≤ ∞``, it also returns the augmented bounds
632+
[`init_ZtoΔU`](@ref), but extracting the input increments augmented with the slack variable
633+
``\mathbf{ΔŨ} = [\begin{smallmatrix} \mathbf{ΔU} \\ ϵ \end{smallmatrix}] = \mathbf{P̃ Z̃}``.
634+
Also, knowing that ``0 ≤ ϵ ≤ ∞``, it also returns the augmented bounds
631635
``\mathbf{ΔŨ_{min}} = [\begin{smallmatrix} \mathbf{ΔU_{min}} \\ 0 \end{smallmatrix}]`` and
632636
``\mathbf{ΔŨ_{max}} = [\begin{smallmatrix} \mathbf{ΔU_{min}} \\\end{smallmatrix}]``,
633637
and the ``\mathbf{A}`` matrices for the inequality constraints:
@@ -646,13 +650,16 @@ bound, which is more specific than a linear inequality constraint. However, it i
646650
convenient to treat it as a linear inequality constraint since the optimizer `OSQP.jl` does
647651
not support pure bounds on the decision variables.
648652
"""
649-
function relaxΔU(::SimModel{NT}, nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P) where NT<:Real
653+
function relaxΔU(
654+
::SimModel{NT}, transcription::TranscriptionMethod,
655+
nϵ, C_Δumin, C_Δumax, ΔUmin, ΔUmax, P
656+
) where NT<:Real
650657
nZ = size(P, 2)
651658
if== 1 # Z̃ = [Z; ϵ]
652659
ΔŨmin, ΔŨmax = [ΔUmin; NT[0.0]], [ΔUmax; NT[Inf]] # 0 ≤ ϵ ≤ ∞
653660
A_ϵ = [zeros(NT, 1, nZ) NT[1.0]]
654661
A_ΔŨmin, A_ΔŨmax = -[P C_Δumin; A_ϵ], [P -C_Δumax; A_ϵ]
655-
= [P zeros(NT, size(P, 1), 1)]
662+
= [P zeros(NT, size(P, 1), 1); zeros(NT, 1, size(P, 2)) NT[1.0]]
656663
else # Z̃ = Z (only hard constraints)
657664
ΔŨmin, ΔŨmax = ΔUmin, ΔUmax
658665
A_ΔŨmin, A_ΔŨmax = -P, P

src/controller/execute.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ They are computed with these equations using in-place operations:
177177
+ \mathbf{V u_0}(k-1) + \mathbf{B} + \mathbf{Ŷ_s} \\
178178
\mathbf{C_y} &= \mathbf{F} + \mathbf{Y_{op}} - \mathbf{R̂_y} \\
179179
\mathbf{C_u} &= \mathbf{T}\mathbf{u}(k-1) - \mathbf{R̂_u} \\
180-
\mathbf{q̃} &= 2[(\mathbf{M}_{H_p} \mathbf{Ẽ})' \mathbf{C_y}
181-
+ (\mathbf{L}_{H_p} \mathbf{S̃})' \mathbf{C_u}] \\
182-
r &= \mathbf{C_y}' \mathbf{M}_{H_p} \mathbf{C_y}
183-
+ \mathbf{C_u}' \mathbf{L}_{H_p} \mathbf{C_u}
180+
\mathbf{q̃} &= 2[ (\mathbf{M}_{H_p} \mathbf{Ẽ})' \mathbf{C_y}
181+
+ (\mathbf{L}_{H_p} \mathbf{S̃})' \mathbf{C_u} ] \\
182+
r &= \mathbf{C_y}' \mathbf{M}_{H_p} \mathbf{C_y}
183+
+ \mathbf{C_u}' \mathbf{L}_{H_p} \mathbf{C_u}
184184
\end{aligned}
185185
```
186186
"""
@@ -765,7 +765,7 @@ function setmodel_controller!(mpc::PredictiveController, x̂op_old)
765765
JuMP.unregister(optim, :linconstraint)
766766
@constraint(optim, linconstraint, A*ΔŨvar .≤ b)
767767
# --- quadratic programming Hessian matrix ---
768-
= init_quadprog(model, mpc.weights, mpc.Ẽ, mpc.S̃)
768+
= init_quadprog(model, mpc.weights, mpc.. mpc., mpc.S̃)
769769
mpc.H̃ .=
770770
set_objective_hessian!(mpc, ΔŨvar)
771771
return nothing

src/controller/explicitmpc.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
5454
# dummy val (updated just before optimization):
5555
F, fx̂ = zeros(NT, ny*Hp), zeros(NT, nx̂)
5656
P̃, S̃, Ñ_Hc, Ẽ = P, S, N_Hc, E # no slack variable ϵ for ExplicitMPC
57-
= init_quadprog(model, weights ,Ẽ, S̃)
57+
= init_quadprog(model, weights, Ẽ, P̃, S̃)
5858
# dummy vals (updated just before optimization):
5959
q̃, r = zeros(NT, size(H̃, 1)), zeros(NT, 1)
6060
H̃_chol = cholesky(H̃)

src/controller/linmpc.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,12 @@ struct LinMPC{
6363
# dummy vals (updated just before optimization):
6464
F, fx̂, Fŝ = zeros(NT, ny*Hp), zeros(NT, nx̂), zeros(NT, nx̂*Hp)
6565
con, nϵ, P̃, S̃, Ẽ, Ẽŝ = init_defaultcon_mpc(
66-
estim, Hp, Hc, Cwt, P, S, E,
66+
estim, transcription,
67+
Hp, Hc, Cwt, P, S, E,
6768
ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂,
6869
Eŝ, Fŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ
6970
)
70-
= init_quadprog(model, weights, Ẽ, S̃)
71+
= init_quadprog(model, weights, Ẽ, P̃, S̃)
7172
# dummy vals (updated just before optimization):
7273
q̃, r = zeros(NT, size(H̃, 1)), zeros(NT, 1)
7374
Ks, Ps = init_stochpred(estim, Hp)

src/controller/nonlinmpc.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ struct NonLinMPC{
7777
# dummy vals (updated just before optimization):
7878
F, fx̂, Fŝ = zeros(NT, ny*Hp), zeros(NT, nx̂), zeros(NT, nx̂*Hp)
7979
con, nϵ, P̃, S̃, Ẽ, Ẽŝ = init_defaultcon_mpc(
80-
estim, Hp, Hc, Cwt, P, S, E,
80+
estim, transcription,
81+
Hp, Hc, Cwt, P, S, E,
8182
ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂,
8283
Eŝ, Fŝ, Gŝ, Jŝ, Kŝ, Vŝ, Bŝ,
8384
gc!, nc
8485
)
85-
= init_quadprog(model, weights, Ẽ, S̃)
86+
= init_quadprog(model, weights, Ẽ, P̃, S̃)
8687
# dummy vals (updated just before optimization):
8788
q̃, r = zeros(NT, size(H̃, 1)), zeros(NT, 1)
8889
Ks, Ps = init_stochpred(estim, Hp)

src/controller/transcription.jl

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,38 @@ in which ``\mathbf{P} is defined in the Extended Help section.
6767
- ``\mathbf{P} = [\begin{smallmatrix}\mathbf{I} \mathbf{0} \end{smallmatrix}]`` if
6868
`transcription isa MultipleShooting`
6969
"""
70-
function init_ZtoU end
70+
function init_ZtoΔU end
7171

7272
function init_ZtoΔU(
7373
estim::StateEstimator{NT}, transcription::SingleShooting, _ , Hc
7474
) where {NT<:Real}
75-
return Matrix{NT}(I, estim.model.nu*Hc, estim.model.nu*Hc)
75+
P = Matrix{NT}(I, estim.model.nu*Hc, estim.model.nu*Hc)
76+
return P
7677
end
7778

7879
function init_ZtoΔU(
7980
estim::StateEstimator{NT}, transcription::MultipleShooting, Hp, Hc
8081
) where {NT<:Real}
8182
I_nu_Hc = Matrix{NT}(I, estim.model.nu*Hc, estim.model.nu*Hc)
82-
return [I_nu_Hc zeros(NT, estim.model.nu*Hc, estim.nx̂*Hp)]
83+
P = [I_nu_Hc zeros(NT, estim.model.nu*Hc, estim.nx̂*Hp)]
84+
return P
8385
end
8486

87+
#=
88+
function init_Z̃toΔŨ(
89+
estim::StateEstimator{NT}, transcription::SingleShooting, Hp, Hc
90+
) where {NT<:Real}
91+
return Matrix{NT}(I, model.nu*Hc, model.nu*Hc)
92+
end
93+
94+
function init_Z̃toΔŨ(
95+
estim::StateEstimator{NT}, transcription::MultipleShooting, Hp, Hc
96+
) where {NT<:Real}
97+
I_nu_Hc = Matrix{NT}(I, model.nu*Hc, model.nu*Hc)
98+
return [I_nu_Hc zeros(NT, model.nu*Hc, model.nx̂*Hp)]
99+
end
100+
=#
101+
85102
@doc raw"""
86103
init_ZtoU(estim, transcription, Hp, Hc) -> S, T
87104
@@ -133,14 +150,14 @@ function init_ZtoU(
133150
I_nu = Matrix{NT}(I, model.nu, model.nu)
134151
S_Hc = LowerTriangular(repeat(I_nu, Hc, Hc))
135152
Sdagger = [S_Hc; repeat(I_nu, Hp - Hc, Hc)]
136-
S = init_ZtoU_Smat(estim, transcription, Hp, Hc, Sdagger)
153+
S = init_Smat(estim, transcription, Hp, Hc, Sdagger)
137154
T = repeat(I_nu, Hp)
138155
return S, T
139156
end
140157

141-
init_ZtoU_Smat( _ , transcription::SingleShooting, _ , _ , Sdagger) = Sdagger
158+
init_Smat( _ , transcription::SingleShooting, _ , _ , Sdagger) = Sdagger
142159

143-
function init_ZtoU_Smat(estim, transcription::MultipleShooting, Hp, _ , Sdagger)
160+
function init_Smat(estim, transcription::MultipleShooting, Hp, _ , Sdagger)
144161
return [Sdagger zeros(eltype(Sdagger), estim.model.nu*Hp, estim.nx̂*Hp)]
145162
end
146163

@@ -339,7 +356,7 @@ function init_predmat(
339356
J = repeatdiag(D̂d, Hp)
340357
jx̂ = zeros(NT, nx̂, Hp*nd)
341358
# --- state x̂op and state update f̂op operating points ---
342-
B = zeros(NT, Hp*ny, 1)
359+
B = zeros(NT, Hp*ny)
343360
bx̂ = zeros(NT, nx̂)
344361
return E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂
345362
end

0 commit comments

Comments
 (0)