Skip to content

Commit c7d7dc8

Browse files
committed
changed: support multiple shooting in the input conversion matrices
1 parent 97a3176 commit c7d7dc8

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

src/controller/construct.jl

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -447,20 +447,20 @@ end
447447

448448

449449
@doc raw"""
450-
init_ΔUtoU(model, Hp, Hc) -> S, T
450+
init_ZtoU(estim, Hp, Hc, transcription) -> S, T
451451
452-
Init manipulated input increments to inputs conversion matrices.
452+
Init decision variables to inputs over ``H_p`` conversion matrices.
453453
454454
The conversion from the input increments ``\mathbf{ΔU}`` to manipulated inputs over ``H_p``
455455
are calculated by:
456456
```math
457-
\mathbf{U} = \mathbf{S} \mathbf{ΔU} + \mathbf{T} \mathbf{u}(k-1)
457+
\mathbf{U} = \mathbf{S} \mathbf{Z} + \mathbf{T} \mathbf{u}(k-1)
458458
```
459459
The ``\mathbf{S}`` and ``\mathbf{T}`` matrices are defined in the Extended Help section.
460460
461461
# Extended Help
462462
!!! details "Extended Help"
463-
The ``\mathbf{U}`` vector and the two conversion matrices are defined as:
463+
The ``\mathbf{U}`` vector and the conversion matrices are defined as:
464464
```math
465465
\mathbf{U} = \begin{bmatrix}
466466
\mathbf{u}(k + 0) \\
@@ -469,7 +469,7 @@ The ``\mathbf{S}`` and ``\mathbf{T}`` matrices are defined in the Extended Help
469469
\mathbf{u}(k + H_c - 1) \\
470470
\vdots \\
471471
\mathbf{u}(k + H_p - 1) \end{bmatrix} , \quad
472-
\mathbf{S} = \begin{bmatrix}
472+
\mathbf{S^†} = \begin{bmatrix}
473473
\mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\
474474
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{0} \\
475475
\vdots & \vdots & \ddots & \vdots \\
@@ -484,12 +484,24 @@ The ``\mathbf{S}`` and ``\mathbf{T}`` matrices are defined in the Extended Help
484484
\vdots \\
485485
\mathbf{I} \end{bmatrix}
486486
```
487+
and, depending on the transcription method, we have:
488+
- ``\mathbf{S} = \mathbf{S^†}`` if `transcription == :singleshooting`
489+
- ``\mathbf{S} = [\begin{smallmatrix}\mathbf{S^†} \mathbf{0} \end{smallmatrix}]`` if
490+
`transcription == :multipleshooting`
487491
"""
488-
function init_ΔUtoU(model::SimModel{NT}, Hp, Hc) where {NT<:Real}
492+
function init_ZtoU(estim::StateEstimator{NT}, Hp, Hc, transcription) where {NT<:Real}
493+
model = estim.model
489494
# S and T are `Matrix{NT}` since conversion is faster than `Matrix{Bool}` or `BitMatrix`
490495
I_nu = Matrix{NT}(I, model.nu, model.nu)
491496
S_Hc = LowerTriangular(repeat(I_nu, Hc, Hc))
492-
S = [S_Hc; repeat(I_nu, Hp - Hc, Hc)]
497+
if transcription == :singleshooting
498+
O = zeros(NT, model.nu*Hp, 0)
499+
elseif transcription == :multipleshooting
500+
O = zeros(NT, model.nu*Hp, estim.nx̂*Hp)
501+
else
502+
throw(ArgumentError("transcription method not recognized"))
503+
end
504+
S = hcat([S_Hc; repeat(I_nu, Hp - Hc, Hc)], O)
493505
T = repeat(I_nu, Hp)
494506
return S, T
495507
end

src/controller/nonlinmpc.jl

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct NonLinMPC{
99
GCfunc<:Function
1010
} <: PredictiveController{NT}
1111
estim::SE
12+
transcription::Symbol
1213
# note: `NT` and the number type `JNT` in `JuMP.GenericModel{JNT}` can be
1314
# different since solvers that support non-Float64 are scarce.
1415
optim::JM
@@ -47,7 +48,8 @@ struct NonLinMPC{
4748
buffer::PredictiveControllerBuffer{NT}
4849
function NonLinMPC{NT}(
4950
estim::SE,
50-
Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gc!::GCfunc, nc, p::P, optim::JM
51+
Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gc!::GCfunc, nc, p::P,
52+
transcription, optim::JM
5153
) where {
5254
NT<:Real,
5355
SE<:StateEstimator,
@@ -62,7 +64,7 @@ struct NonLinMPC{
6264
weights = ControllerWeights{NT}(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
6365
# dummy vals (updated just before optimization):
6466
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
65-
S, T = init_ΔUtoU(model, Hp, Hc)
67+
S, T = init_ZtoU(estim, Hp, Hc, transcription)
6668
E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂ = init_predmat(estim, model, Hp, Hc)
6769
# dummy vals (updated just before optimization):
6870
F, fx̂ = zeros(NT, ny*Hp), zeros(NT, nx̂)
@@ -81,7 +83,7 @@ struct NonLinMPC{
8183
ΔŨ = zeros(NT, nΔŨ)
8284
buffer = PredictiveControllerBuffer{NT}(nu, ny, nd, Hp, Hc, nϵ)
8385
mpc = new{NT, SE, JM, P, JEfunc, GCfunc}(
84-
estim, optim, con,
86+
estim, transcription, optim, con,
8587
ΔŨ, ŷ,
8688
Hp, Hc, nϵ,
8789
weights,
@@ -122,9 +124,8 @@ subject to [`setconstraint!`](@ref) bounds, and the custom inequality constraint
122124
```
123125
and the slack ``ϵ`` and the ``\mathbf{Z}`` vector as the decision variables:
124126
125-
- ``\mathbf{Z} = \mathbf{ΔŨ}`` if the transcription method is `:singleshooting`
126-
- ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{ΔŨ}' & \mathbf{X̂}' \end{smallmatrix}]'`` if the transcription method is `:multipleshoting`
127-
- ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{ΔŨ}' & \mathbf{X̂}' & \mathbf{Ĉ}' \end{smallmatrix}]'`` if the transcription method is `:directcollocation`
127+
- ``\mathbf{Z} = \mathbf{ΔU}`` if the transcription method is `:singleshooting`
128+
- ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{ΔU}' & \mathbf{X̂}' \end{smallmatrix}]'`` if the transcription method is `:multipleshoting`
128129
129130
The economic function ``J_E`` can penalizes solutions with high economic costs. Setting all
130131
the weights to 0 except ``E`` creates a pure economic model predictive controller (EMPC).
@@ -176,7 +177,7 @@ This controller allocates memory at each time step for the optimization.
176177
- `nc=0` : number of custom inequality constraints.
177178
- `p=model.p` : ``J_E`` and ``\mathbf{g_c}`` functions parameter ``\mathbf{p}`` (any type).
178179
- `transcription=:singleshooting` : transcription method for the nonlinear optimization
179-
problem, can be `:singleshooting`, `:multipleshoting` or `:directcollocation`.
180+
problem, can be `:singleshooting` or `:multipleshoting`.
180181
- `optim=JuMP.Model(Ipopt.Optimizer)` : nonlinear optimizer used in the predictive
181182
controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.Model)
182183
(default to [`Ipopt`](https://github.com/jump-dev/Ipopt.jl) optimizer).
@@ -254,13 +255,15 @@ function NonLinMPC(
254255
gc ::Function = gc!,
255256
nc::Int = 0,
256257
p = model.p,
258+
transcription = :singleshooting,
257259
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
258260
kwargs...
259261
)
260262
estim = UnscentedKalmanFilter(model; kwargs...)
261263
return NonLinMPC(
262264
estim;
263-
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp, optim
265+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp,
266+
transcription, optim
264267
)
265268
end
266269

@@ -281,13 +284,15 @@ function NonLinMPC(
281284
gc ::Function = gc!,
282285
nc::Int = 0,
283286
p = model.p,
287+
transcription = :singleshooting,
284288
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
285289
kwargs...
286290
)
287291
estim = SteadyKalmanFilter(model; kwargs...)
288292
return NonLinMPC(
289293
estim;
290-
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp, optim
294+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp,
295+
transcription, optim
291296
)
292297
end
293298

@@ -332,6 +337,7 @@ function NonLinMPC(
332337
gc ::Function = gc!,
333338
nc = 0,
334339
p::P = estim.model.p,
340+
transcription = :singleshooting,
335341
optim::JM = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
336342
) where {
337343
NT<:Real,
@@ -347,7 +353,8 @@ function NonLinMPC(
347353
validate_JE(NT, JE)
348354
gc! = get_mutating_gc(NT, gc)
349355
return NonLinMPC{NT}(
350-
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gc!, nc, p, optim
356+
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gc!, nc, p,
357+
transcription, optim
351358
)
352359
end
353360

0 commit comments

Comments
 (0)