Skip to content

Commit 9c22a35

Browse files
committed
Merge branch 'main' into debug_objfct_nlp
2 parents 8e52736 + 307a542 commit 9c22a35

26 files changed

Lines changed: 717 additions & 1142 deletions

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
name = "ModelPredictiveControl"
22
uuid = "61f9bdb8-6ae4-484a-811f-bbf86720c31c"
3-
version = "1.16.3"
3+
version = "2.0.0"
44
authors = ["Francis Gagnon"]
55

66
[deps]
77
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
88
DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63"
9+
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
910
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
1011
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
1112
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
@@ -33,6 +34,7 @@ ControlSystemsBase = "1.18.2"
3334
DAQP = "0.6, 0.7.1"
3435
DifferentiationInterface = "0.7.11"
3536
Documenter = "1"
37+
FastGaussQuadrature = "1.1.0"
3638
FiniteDiff = "2"
3739
ForwardDiff = "0.10, 1"
3840
Ipopt = "1"

benchmark/3_bench_predictive_control.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ nmpc_madnlp_ss = setconstraint!(nmpc_madnlp_ss; umin, umax)
345345
JuMP.unset_time_limit_sec(nmpc_madnlp_ss.optim)
346346

347347
optim = JuMP.Model(()->UnoSolver.Optimizer(preset="filtersqp"), add_bridges=false)
348-
transcription, hessian, oracle = MultipleShooting(), true, true
349-
nmpc_uno_ms_hess = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription, hessian, oracle)
348+
transcription, hessian = MultipleShooting(), true
349+
nmpc_uno_ms_hess = NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Cwt, optim, transcription, hessian)
350350
nmpc_uno_ms_hess = setconstraint!(nmpc_uno_ms_hess; umin, umax)
351351
JuMP.unset_time_limit_sec(nmpc_uno_ms_hess.optim)
352352

docs/src/internals/predictive_control.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ ModelPredictiveControl.relaxterminal
2525
ModelPredictiveControl.augmentdefect
2626
ModelPredictiveControl.init_quadprog
2727
ModelPredictiveControl.init_stochpred
28+
ModelPredictiveControl.init_orthocolloc
2829
ModelPredictiveControl.init_matconstraint_mpc
2930
ModelPredictiveControl.get_nonlinobj_op(::NonLinMPC, ::ModelPredictiveControl.GenericModel)
3031
ModelPredictiveControl.get_nonlincon_oracle(::NonLinMPC, ::ModelPredictiveControl.GenericModel)

docs/src/internals/state_estim.md

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

3233
## Update Quadratic Optimization

docs/src/public/predictive_control.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,10 @@ MultipleShooting
120120

121121
```@docs
122122
TrapezoidalCollocation
123-
```
123+
```
124+
125+
### OrthogonalCollocation
126+
127+
```@docs
128+
OrthogonalCollocation
129+
```

src/ModelPredictiveControl.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import JuMP: @variable, @operator, @constraint, @objective
3737

3838
import OSQP, Ipopt
3939

40+
import FastGaussQuadrature
41+
4042
export SimModel, LinModel, NonLinModel
4143
export DiffSolver, RungeKutta, ForwardEuler
4244
export setop!, setname!
@@ -48,7 +50,8 @@ export MovingHorizonEstimator
4850
export ManualEstimator
4951
export default_nint, initstate!
5052
export PredictiveController, ExplicitMPC, LinMPC, NonLinMPC, setconstraint!, moveinput!
51-
export TranscriptionMethod, SingleShooting, MultipleShooting, TrapezoidalCollocation
53+
export TranscriptionMethod, SingleShooting, MultipleShooting
54+
export TrapezoidalCollocation, OrthogonalCollocation
5255
export SimResult, getinfo, sim!
5356

5457
include("general.jl")

src/controller/construct.jl

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,105 @@ function validate_args(mpc::PredictiveController, ry, d, lastu, D̂, R̂y, R̂u)
692692
size(R̂u) (nu*Hp,) && throw(DimensionMismatch("R̂u size $(size(R̂u)) ≠ manip. input size × Hp ($(nu*Hp),)"))
693693
end
694694

695+
@doc raw"""
696+
init_ZtoΔU(estim::StateEstimator, transcription::TranscriptionMethod, Hp, Hc) -> PΔu
697+
698+
Init decision variables to input increments over ``H_c`` conversion matrix `PΔu`.
699+
700+
The conversion from the decision variables ``\mathbf{Z}`` to ``\mathbf{ΔU}``, the input
701+
increments over ``H_c``, is computed by:
702+
```math
703+
\mathbf{ΔU} = \mathbf{P_{Δu}} \mathbf{Z}
704+
```
705+
706+
in which ``\mathbf{P_{Δu}}`` is defined in the Extended Help section.
707+
708+
# Extended Help
709+
!!! details "Extended Help"
710+
Following the decision variable definition of the [`TranscriptionMethod`](@ref), the
711+
conversion matrix ``\mathbf{P_{Δu}}``, we have:
712+
- ``\mathbf{P_{Δu}} = \mathbf{I}`` if `transcription` is a [`SingleShooting`](@ref)
713+
- ``\mathbf{P_{Δu}} = [\begin{smallmatrix}\mathbf{I} & \mathbf{0} \end{smallmatrix}]`` otherwise.
714+
The matrix is store as as `SparseMatrixCSC` to support both cases efficiently.
715+
"""
716+
function init_ZtoΔU(
717+
estim::StateEstimator{NT}, transcription::TranscriptionMethod, Hp, Hc
718+
) where {NT<:Real}
719+
I_nu_Hc = sparse(Matrix{NT}(I, estim.model.nu*Hc, estim.model.nu*Hc))
720+
nZ = get_nZ(estim, transcription, Hp, Hc)
721+
nΔU = estim.model.nu*Hc
722+
PΔu = [I_nu_Hc spzeros(NT, nΔU, nZ - nΔU)]
723+
return PΔu
724+
end
725+
726+
@doc raw"""
727+
init_ZtoU(estim, transcription, Hp, Hc, nb) -> Pu, Tu
728+
729+
Init decision variables to inputs over ``H_p`` conversion matrices.
730+
731+
The conversion from the decision variables ``\mathbf{Z}`` to ``\mathbf{U}``, the manipulated
732+
inputs over ``H_p``, is computed by:
733+
```math
734+
\mathbf{U} = \mathbf{P_u} \mathbf{Z} + \mathbf{T_u} \mathbf{u}(k-1)
735+
```
736+
The ``\mathbf{P_u}`` and ``\mathbf{T_u}`` matrices are defined in the Extended Help section.
737+
738+
# Extended Help
739+
!!! details "Extended Help"
740+
With ``n_i``, the ``i``th element of the ``\mathbf{n_b}`` vector defined in [`move_blocking`](@ref)
741+
documentation, we introduce the ``\mathbf{Q}(n_i)`` matrix of size `(nu*ni, nu)`:
742+
```math
743+
\mathbf{Q}(n_i) = \begin{bmatrix}
744+
\mathbf{I} \\
745+
\mathbf{I} \\
746+
\vdots \\
747+
\mathbf{I} \end{bmatrix}
748+
```
749+
The ``\mathbf{U}`` vector and the conversion matrices are defined as:
750+
```math
751+
\mathbf{U} = \begin{bmatrix}
752+
\mathbf{u}(k + 0) \\
753+
\mathbf{u}(k + 1) \\
754+
\vdots \\
755+
\mathbf{u}(k + H_p - 1) \end{bmatrix} , \quad
756+
\mathbf{P_u^†} = \begin{bmatrix}
757+
\mathbf{Q}(n_1) & \mathbf{0} & \cdots & \mathbf{0} \\
758+
\mathbf{Q}(n_2) & \mathbf{Q}(n_2) & \cdots & \mathbf{0} \\
759+
\vdots & \vdots & \ddots & \vdots \\
760+
\mathbf{Q}(n_{H_c}) & \mathbf{Q}(n_{H_c}) & \cdots & \mathbf{Q}(n_{H_c}) \end{bmatrix} , \quad
761+
\mathbf{T_u} = \begin{bmatrix}
762+
\mathbf{I} \\
763+
\mathbf{I} \\
764+
\vdots \\
765+
\mathbf{I} \end{bmatrix}
766+
```
767+
and, depending on the transcription method, we have:
768+
- ``\mathbf{P_u} = \mathbf{P_u^†}`` if `transcription` is a [`SingleShooting`](@ref)
769+
- ``\mathbf{P_u} = [\begin{smallmatrix}\mathbf{P_u^†} & \mathbf{0} \end{smallmatrix}]``
770+
if `transcription` is a [`MultipleShooting`](@ref)
771+
The conversion matrices are stored as `SparseMatrixCSC` since it was benchmarked that it
772+
is generally more performant than normal dense matrices, even for small `nu`, `Hp` and
773+
`Hc` values. Using `Bool` element type and `BitMatrix` is also slower.
774+
"""
775+
function init_ZtoU(
776+
estim::StateEstimator{NT}, transcription::TranscriptionMethod, Hp, Hc, nb
777+
) where {NT<:Real}
778+
nu = estim.model.nu
779+
I_nu = sparse(Matrix{NT}(I, nu, nu))
780+
PuDagger = Matrix{NT}(undef, nu*Hp, nu*Hc)
781+
for i=1:Hc
782+
ni = nb[i]
783+
Q_ni = repeat(I_nu, ni, 1)
784+
iRows = (1:nu*ni) .+ @views nu*sum(nb[1:i-1])
785+
PuDagger[iRows, :] = [repeat(Q_ni, 1, i) spzeros(nu*ni, nu*(Hc-i))]
786+
end
787+
PuDagger = sparse(PuDagger)
788+
nZ = get_nZ(estim, transcription, Hp, Hc)
789+
Pu = [PuDagger spzeros(NT, nu*Hp, nZ - nu*Hc)]
790+
Tu = repeat(I_nu, Hp)
791+
return Pu, Tu
792+
end
793+
695794
@doc raw"""
696795
init_quadprog(
697796
model::LinModel, transcriptions::TranscriptionMethod, weights::ControllerWeights,

src/controller/execute.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,15 @@ function getinfo(mpc::PredictiveController{NT}) where NT<:Real
142142
info = Dict{Symbol, Any}()
143143
ΔŨ = Vector{NT}(undef, nΔŨ)
144144
x̂0end = similar(mpc.estim.x̂0)
145-
K0 = Vector{NT}(undef, nK)
145+
K = Vector{NT}(undef, nK)
146146
Ue, Ŷe = Vector{NT}(undef, nUe), Vector{NT}(undef, nŶe)
147147
U0, Ŷ0 = similar(mpc.Uop), similar(mpc.Yop)
148148
Û0, X̂0 = Vector{NT}(undef, nÛ0), Vector{NT}(undef, nX̂0)
149149
U, Ŷ = buffer.U, buffer.
150150
= buffer.
151151
U0 = getU0!(U0, mpc, Z̃)
152152
ΔŨ = getΔŨ!(ΔŨ, mpc, transcription, Z̃)
153-
Ŷ0, x̂0end = predict!(Ŷ0, x̂0end, X̂0, Û0, K0, mpc, model, transcription, U0, Z̃)
153+
Ŷ0, x̂0end = predict!(Ŷ0, x̂0end, X̂0, Û0, K, mpc, model, transcription, U0, Z̃)
154154
Ue, Ŷe = extended_vectors!(Ue, Ŷe, mpc, U0, Ŷ0)
155155
U .= U0 .+ mpc.Uop
156156
Ŷ .= Ŷ0 .+ mpc.Yop

0 commit comments

Comments
 (0)