Skip to content

Commit 9e41dfe

Browse files
committed
added: Transcription abstract type
1 parent de9d767 commit 9e41dfe

File tree

5 files changed

+331
-294
lines changed

5 files changed

+331
-294
lines changed

docs/src/public/predictive_control.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,23 @@ NonLinMPC
8888
```@docs
8989
moveinput!
9090
```
91+
92+
## Transcription Methods
93+
94+
### Transcription Method
95+
96+
```@docs
97+
ModelPredictiveControl.TranscriptionMethod
98+
```
99+
100+
### SingleShooting
101+
102+
```@docs
103+
SingleShooting
104+
```
105+
106+
### MultipleShooting
107+
108+
```@docs
109+
MultipleShooting
110+
```

src/ModelPredictiveControl.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export SteadyKalmanFilter, KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFi
3232
export MovingHorizonEstimator
3333
export default_nint, initstate!
3434
export PredictiveController, ExplicitMPC, LinMPC, NonLinMPC, setconstraint!, moveinput!
35+
export SingleShooting, MultipleShooting
3536
export SimResult, getinfo, sim!
3637

3738
include("general.jl")

src/controller/construct.jl

Lines changed: 0 additions & 294 deletions
Original file line numberDiff line numberDiff line change
@@ -445,300 +445,6 @@ function validate_args(mpc::PredictiveController, ry, d, D̂, R̂y, R̂u)
445445
size(R̂u) (nu*Hp,) && throw(DimensionMismatch("R̂u size $(size(R̂u)) ≠ manip. input size × Hp ($(nu*Hp),)"))
446446
end
447447

448-
449-
@doc raw"""
450-
init_ZtoU(estim, Hp, Hc, transcription) -> S, T
451-
452-
Init decision variables to inputs over ``H_p`` conversion matrices.
453-
454-
The conversion from the input increments ``\mathbf{ΔU}`` to manipulated inputs over ``H_p``
455-
are calculated by:
456-
```math
457-
\mathbf{U} = \mathbf{S} \mathbf{Z} + \mathbf{T} \mathbf{u}(k-1)
458-
```
459-
The ``\mathbf{S}`` and ``\mathbf{T}`` matrices are defined in the Extended Help section.
460-
461-
# Extended Help
462-
!!! details "Extended Help"
463-
The ``\mathbf{U}`` vector and the conversion matrices are defined as:
464-
```math
465-
\mathbf{U} = \begin{bmatrix}
466-
\mathbf{u}(k + 0) \\
467-
\mathbf{u}(k + 1) \\
468-
\vdots \\
469-
\mathbf{u}(k + H_c - 1) \\
470-
\vdots \\
471-
\mathbf{u}(k + H_p - 1) \end{bmatrix} , \quad
472-
\mathbf{S^†} = \begin{bmatrix}
473-
\mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\
474-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{0} \\
475-
\vdots & \vdots & \ddots & \vdots \\
476-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \\
477-
\vdots & \vdots & \ddots & \vdots \\
478-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \end{bmatrix} , \quad
479-
\mathbf{T} = \begin{bmatrix}
480-
\mathbf{I} \\
481-
\mathbf{I} \\
482-
\vdots \\
483-
\mathbf{I} \\
484-
\vdots \\
485-
\mathbf{I} \end{bmatrix}
486-
```
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`
491-
"""
492-
function init_ZtoU(estim::StateEstimator{NT}, Hp, Hc, transcription) where {NT<:Real}
493-
model = estim.model
494-
# S and T are `Matrix{NT}` since conversion is faster than `Matrix{Bool}` or `BitMatrix`
495-
I_nu = Matrix{NT}(I, model.nu, model.nu)
496-
S_Hc = LowerTriangular(repeat(I_nu, 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)
505-
T = repeat(I_nu, Hp)
506-
return S, T
507-
end
508-
509-
510-
@doc raw"""
511-
init_predmat(
512-
estim, model::LinModel, Hp, Hc, transcription
513-
) -> E, G, J, K, V, ex̂, gx̂, jx̂, kx̂, vx̂
514-
515-
Construct the prediction matrices for [`LinModel`](@ref) `model`.
516-
517-
The model predictions are evaluated from the deviation vectors (see [`setop!`](@ref)) and:
518-
```math
519-
\begin{aligned}
520-
\mathbf{Ŷ_0} &= \mathbf{E Z} + \mathbf{G d_0}(k) + \mathbf{J D̂_0}
521-
+ \mathbf{K x̂_0}(k) + \mathbf{V u_0}(k-1)
522-
+ \mathbf{B} + \mathbf{Ŷ_s} \\
523-
&= \mathbf{E Z} + \mathbf{F}
524-
\end{aligned}
525-
```
526-
in which ``\mathbf{x̂_0}(k) = \mathbf{x̂}_i(k) - \mathbf{x̂_{op}}``, with ``i = k`` if
527-
`estim.direct==true`, otherwise ``i = k - 1``. The predicted outputs ``\mathbf{Ŷ_0}`` and
528-
measured disturbances ``\mathbf{D̂_0}`` respectively include ``\mathbf{ŷ_0}(k+j)`` and
529-
``\mathbf{d̂_0}(k+j)`` values with ``j=1`` to ``H_p``, and input increments ``\mathbf{ΔU}``,
530-
``\mathbf{Δu}(k+j)`` from ``j=0`` to ``H_c-1``. The vector ``\mathbf{B}`` contains the
531-
contribution for non-zero state ``\mathbf{x̂_{op}}`` and state update ``\mathbf{f̂_{op}}``
532-
operating points (for linearization at non-equilibrium point, see [`linearize`](@ref)). The
533-
stochastic predictions ``\mathbf{Ŷ_s=0}`` if `estim` is not a [`InternalModel`](@ref), see
534-
[`init_stochpred`](@ref). The method also computes similar matrices for the predicted
535-
terminal states at ``k+H_p``:
536-
```math
537-
\begin{aligned}
538-
\mathbf{x̂_0}(k+H_p) &= \mathbf{e_x̂ Z} + \mathbf{g_x̂ d_0}(k) + \mathbf{j_x̂ D̂_0}
539-
+ \mathbf{k_x̂ x̂_0}(k) + \mathbf{v_x̂ u_0}(k-1)
540-
+ \mathbf{b_x̂} \\
541-
&= \mathbf{e_x̂ Z} + \mathbf{f_x̂}
542-
\end{aligned}
543-
```
544-
The matrices ``\mathbf{E, G, J, K, V, B, e_x̂, g_x̂, j_x̂, k_x̂, v_x̂, b_x̂}`` are defined in the
545-
Extended Help section. The ``\mathbf{F}`` and ``\mathbf{f_x̂}`` vectors are recalculated at
546-
each control period ``k``, see [`initpred!`](@ref) and [`linconstraint!`](@ref).
547-
548-
# Extended Help
549-
!!! details "Extended Help"
550-
Using the augmented matrices ``\mathbf{Â, B̂_u, Ĉ, B̂_d, D̂_d}`` in `estim` (see
551-
[`augment_model`](@ref)), and the function ``\mathbf{W}(j) = ∑_{i=0}^j \mathbf{Â}^i``,
552-
the prediction matrices are computed by :
553-
```math
554-
\begin{aligned}
555-
\mathbf{E} &= \begin{bmatrix}
556-
\mathbf{Ĉ W}(0)\mathbf{B̂_u} & \mathbf{0} & \cdots & \mathbf{0} \\
557-
\mathbf{Ĉ W}(1)\mathbf{B̂_u} & \mathbf{Ĉ W}(0)\mathbf{B̂_u} & \cdots & \mathbf{0} \\
558-
\vdots & \vdots & \ddots & \vdots \\
559-
\mathbf{Ĉ W}(H_p-1)\mathbf{B̂_u} & \mathbf{Ĉ W}(H_p-2)\mathbf{B̂_u} & \cdots & \mathbf{Ĉ W}(H_p-H_c+1)\mathbf{B̂_u} \end{bmatrix} \\
560-
\mathbf{G} &= \begin{bmatrix}
561-
\mathbf{Ĉ}\mathbf{Â}^{0} \mathbf{B̂_d} \\
562-
\mathbf{Ĉ}\mathbf{Â}^{1} \mathbf{B̂_d} \\
563-
\vdots \\
564-
\mathbf{Ĉ}\mathbf{Â}^{H_p-1} \mathbf{B̂_d} \end{bmatrix} \\
565-
\mathbf{J} &= \begin{bmatrix}
566-
\mathbf{D̂_d} & \mathbf{0} & \cdots & \mathbf{0} \\
567-
\mathbf{Ĉ}\mathbf{Â}^{0} \mathbf{B̂_d} & \mathbf{D̂_d} & \cdots & \mathbf{0} \\
568-
\vdots & \vdots & \ddots & \vdots \\
569-
\mathbf{Ĉ}\mathbf{Â}^{H_p-2} \mathbf{B̂_d} & \mathbf{Ĉ}\mathbf{Â}^{H_p-3} \mathbf{B̂_d} & \cdots & \mathbf{D̂_d} \end{bmatrix} \\
570-
\mathbf{K} &= \begin{bmatrix}
571-
\mathbf{Ĉ}\mathbf{Â}^{1} \\
572-
\mathbf{Ĉ}\mathbf{Â}^{2} \\
573-
\vdots \\
574-
\mathbf{Ĉ}\mathbf{Â}^{H_p} \end{bmatrix} \\
575-
\mathbf{V} &= \begin{bmatrix}
576-
\mathbf{Ĉ W}(0)\mathbf{B̂_u} \\
577-
\mathbf{Ĉ W}(1)\mathbf{B̂_u} \\
578-
\vdots \\
579-
\mathbf{Ĉ W}(H_p-1)\mathbf{B̂_u} \end{bmatrix} \\
580-
\mathbf{B} &= \begin{bmatrix}
581-
\mathbf{Ĉ W}(0) \\
582-
\mathbf{Ĉ W}(1) \\
583-
\vdots \\
584-
\mathbf{Ĉ W}(H_p-1) \end{bmatrix} \mathbf{\big(f̂_{op} - x̂_{op}\big)}
585-
\end{aligned}
586-
```
587-
For the terminal constraints, the matrices are computed with:
588-
```math
589-
\begin{aligned}
590-
\mathbf{e_x̂} &= \begin{bmatrix}
591-
\mathbf{W}(H_p-1)\mathbf{B̂_u} &
592-
\mathbf{W}(H_p-2)\mathbf{B̂_u} &
593-
\cdots &
594-
\mathbf{W}(H_p-H_c+1)\mathbf{B̂_u} \end{bmatrix} \\
595-
\mathbf{g_x̂} &= \mathbf{Â}^{H_p-1} \mathbf{B̂_d} \\
596-
\mathbf{j_x̂} &= \begin{bmatrix}
597-
\mathbf{Â}^{H_p-2} \mathbf{B̂_d} &
598-
\mathbf{Â}^{H_p-3} \mathbf{B̂_d} &
599-
\cdots &
600-
\mathbf{0}
601-
\end{bmatrix} \\
602-
\mathbf{k_x̂} &= \mathbf{Â}^{H_p} \\
603-
\mathbf{v_x̂} &= \mathbf{W}(H_p-1)\mathbf{B̂_u} \\
604-
\mathbf{b_x̂} &= \mathbf{W}(H_p-1) \mathbf{\big(f̂_{op} - x̂_{op}\big)}
605-
\end{aligned}
606-
```
607-
"""
608-
function init_predmat(
609-
estim::StateEstimator{NT}, model::LinModel, Hp, Hc, transcription
610-
) where {NT<:Real}
611-
Â, B̂u, Ĉ, B̂d, D̂d = estim.Â, estim.B̂u, estim.Ĉ, estim.B̂d, estim.D̂d
612-
nu, nx̂, ny, nd = model.nu, estim.nx̂, model.ny, model.nd
613-
# --- pre-compute matrix powers ---
614-
# Apow 3D array : Apow[:,:,1] = A^0, Apow[:,:,2] = A^1, ... , Apow[:,:,Hp+1] = A^Hp
615-
Âpow = Array{NT}(undef, nx̂, nx̂, Hp+1)
616-
Âpow[:,:,1] = I(nx̂)
617-
for j=2:Hp+1
618-
Âpow[:,:,j] = @views Âpow[:,:,j-1]*
619-
end
620-
# Apow_csum 3D array : Apow_csum[:,:,1] = A^0, Apow_csum[:,:,2] = A^1 + A^0, ...
621-
Âpow_csum = cumsum(Âpow, dims=3)
622-
# helper function to improve code clarity and be similar to eqs. in docstring:
623-
getpower(array3D, power) = @views array3D[:,:, power+1]
624-
# --- state estimates x̂ ---
625-
kx̂ = getpower(Âpow, Hp)
626-
K = Matrix{NT}(undef, Hp*ny, nx̂)
627-
for j=1:Hp
628-
iRow = (1:ny) .+ ny*(j-1)
629-
K[iRow,:] =*getpower(Âpow, j)
630-
end
631-
# --- manipulated inputs u ---
632-
vx̂ = getpower(Âpow_csum, Hp-1)*B̂u
633-
V = Matrix{NT}(undef, Hp*ny, nu)
634-
for j=1:Hp
635-
iRow = (1:ny) .+ ny*(j-1)
636-
V[iRow,:] =*getpower(Âpow_csum, j-1)*B̂u
637-
end
638-
ex̂ = Matrix{NT}(undef, nx̂, Hc*nu)
639-
E = zeros(NT, Hp*ny, Hc*nu)
640-
for j=1:Hc # truncated with control horizon
641-
iRow = (ny*(j-1)+1):(ny*Hp)
642-
iCol = (1:nu) .+ nu*(j-1)
643-
E[iRow, iCol] = V[iRow .- ny*(j-1),:]
644-
ex̂[: , iCol] = getpower(Âpow_csum, Hp-j)*B̂u
645-
end
646-
# --- measured disturbances d ---
647-
gx̂ = getpower(Âpow, Hp-1)*B̂d
648-
G = Matrix{NT}(undef, Hp*ny, nd)
649-
jx̂ = Matrix{NT}(undef, nx̂, Hp*nd)
650-
J = repeatdiag(D̂d, Hp)
651-
if nd 0
652-
for j=1:Hp
653-
iRow = (1:ny) .+ ny*(j-1)
654-
G[iRow,:] =*getpower(Âpow, j-1)*B̂d
655-
end
656-
for j=1:Hp
657-
iRow = (ny*j+1):(ny*Hp)
658-
iCol = (1:nd) .+ nd*(j-1)
659-
J[iRow, iCol] = G[iRow .- ny*j,:]
660-
jx̂[: , iCol] = j < Hp ? getpower(Âpow, Hp-j-1)*B̂d : zeros(NT, nx̂, nd)
661-
end
662-
end
663-
# --- state x̂op and state update f̂op operating points ---
664-
coef_bx̂ = getpower(Âpow_csum, Hp-1)
665-
coef_B = Matrix{NT}(undef, ny*Hp, nx̂)
666-
for j=1:Hp
667-
iRow = (1:ny) .+ ny*(j-1)
668-
coef_B[iRow,:] =*getpower(Âpow_csum, j-1)
669-
end
670-
f̂op_n_x̂op = estim.f̂op - estim.x̂op
671-
bx̂ = coef_bx̂ * f̂op_n_x̂op
672-
B = coef_B * f̂op_n_x̂op
673-
return E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂
674-
end
675-
676-
"Return empty matrices if `model` is not a [`LinModel`](@ref)"
677-
function init_predmat(
678-
estim::StateEstimator{NT}, model::SimModel, Hp, Hc, transcription
679-
) where {NT<:Real}
680-
nu, nx̂, nd = model.nu, estim.nx̂, model.nd
681-
E = zeros(NT, 0, nu*Hc)
682-
G = zeros(NT, 0, nd)
683-
J = zeros(NT, 0, nd*Hp)
684-
K = zeros(NT, 0, nx̂)
685-
V = zeros(NT, 0, nu)
686-
B = zeros(NT, 0)
687-
ex̂, gx̂, jx̂, kx̂, vx̂, bx̂ = E, G, J, K, V, B
688-
return E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂
689-
end
690-
691-
692-
@doc raw"""
693-
init_defectmat(estim::StateEstimator, model::LinModel, Hp, Hc, transcription)
694-
695-
Init the matrices for computing the defects over the predicted states.
696-
697-
An equation similar to the prediction matrices (see
698-
[`init_predmat`](@ref)) computes the defects over the predicted states:
699-
```math
700-
\begin{aligned}
701-
\mathbf{Ŝ} &= \mathbf{E_ŝ Z} + \mathbf{G_ŝ d_0}(k) + \mathbf{J_ŝ D̂_0}
702-
+ \mathbf{K_ŝ x̂_0}(k) + \mathbf{V_ŝ u_0}(k-1)
703-
+ \mathbf{B_ŝ} \\
704-
&= \mathbf{E_ŝ Z} + \mathbf{F_ŝ}
705-
\end{aligned}
706-
```
707-
They are forced to be ``\mathbf{Ŝ = 0}`` using the optimization equality constraints. The
708-
matrices ``\mathbf{E_ŝ, G_ŝ, J_ŝ, K_ŝ, V_ŝ, B_ŝ}`` are defined in the Extended Help section.
709-
710-
# Extended Help
711-
!!! details "Extended Help"
712-
The matrices are computed by:
713-
```math
714-
\begin{aligned}
715-
\mathbf{E_ŝ} &= \begin{bmatrix}
716-
\mathbf{B̂_u} & \mathbf{0} & \cdots & \mathbf{0} & -\mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\
717-
\mathbf{0} & \mathbf{B̂_u} & \cdots & \mathbf{0} & \mathbf{Â} & -\mathbf{I} & \cdots & \mathbf{0} \\
718-
\vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \ddots & \vdots \\
719-
\mathbf{0} & \mathbf{0} & \cdots & \mathbf{B̂_u} & \mathbf{0} & \mathbf{0} & \cdots & -\mathbf{I} \end{bmatrix} \\
720-
\mathbf{G_ŝ} &= \begin{bmatrix}
721-
\mathbf{B̂_d} \\ \mathbf{0} \\ \vdots \\ \mathbf{0} \end{bmatrix} \\
722-
\mathbf{J_ŝ} &= \begin{bmatrix}
723-
\mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} & \mathbf{0} \\
724-
\mathbf{B̂_d} & \mathbf{0} & \cdots & \mathbf{0} & \mathbf{0} \\
725-
\vdots & \vdots & \ddots & \vdots & \vdots \\
726-
\mathbf{0} & \mathbf{0} & \cdots & \mathbf{B̂_d} & \mathbf{0} \end{bmatrix} \\
727-
\mathbf{K_ŝ} &= \begin{bmatrix}
728-
\mathbf{Â} \\ \mathbf{0} \\ \vdots \\ \mathbf{0} \end{bmatrix} \\
729-
\mathbf{V_ŝ} &= \begin{bmatrix}
730-
\mathbf{B̂_u} \\ \mathbf{B̂_u} \\ \vdots \\ \mathbf{B̂_u} \end{bmatrix} \\
731-
\mathbf{B_ŝ} &= \begin{bmatrix}
732-
\mathbf{f̂_{op} - x̂_{op}} \\ \mathbf{f̂_{op} - x̂_{op}} \\ \vdots \\ \mathbf{f̂_{op} - x̂_{op}} \end{bmatrix}
733-
\end{aligned}
734-
```
735-
"""
736-
function init_defectmat(
737-
estim::StateEstimator{NT}, model::LinModel, Hp, Hc, transcription
738-
) where {NT<:Real}
739-
740-
end
741-
742448
@doc raw"""
743449
init_quadprog(model::LinModel, weights::ControllerWeights, Ẽ, S) -> H̃
744450

0 commit comments

Comments
 (0)