Skip to content

Commit 950bfce

Browse files
committed
added: allows any hermitian weight PredictiveController
1 parent 24598de commit 950bfce

File tree

5 files changed

+50
-47
lines changed

5 files changed

+50
-47
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelPredictiveControl"
22
uuid = "61f9bdb8-6ae4-484a-811f-bbf86720c31c"
33
authors = ["Francis Gagnon"]
4-
version = "0.16.1"
4+
version = "0.17.0"
55

66
[deps]
77
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"

src/controller/construct.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -672,18 +672,18 @@ returns the augmented constraints ``\mathbf{ΔŨ_{min}}`` and ``\mathbf{ΔŨ_{
672672
```
673673
"""
674674
function relaxΔU(::SimModel{NT}, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) where {NT<:Real}
675-
diag_N_Hc = diag(N_Hc)
675+
nΔU = size(N_Hc, 1)
676676
if !isinf(C) # ΔŨ = [ΔU; ϵ]
677677
# 0 ≤ ϵ ≤ ∞
678678
ΔŨmin, ΔŨmax = [ΔUmin; NT[0.0]], [ΔUmax; NT[Inf]]
679679
A_ϵ = [zeros(NT, 1, length(ΔUmin)) NT[1.0]]
680680
A_ΔŨmin, A_ΔŨmax = -[I C_Δumin; A_ϵ], [I -C_Δumax; A_ϵ]
681-
Ñ_Hc = Diagonal{NT}([diag_N_Hc; C])
681+
Ñ_Hc = Hermitian([N_Hc zeros(NT, nΔU, 1);zeros(NT, 1, nΔU) C])
682682
else # ΔŨ = ΔU (only hard constraints)
683683
ΔŨmin, ΔŨmax = ΔUmin, ΔUmax
684-
I_Hc = Matrix{NT}(I, size(N_Hc))
684+
I_Hc = Matrix{NT}(I, nΔU, nΔU)
685685
A_ΔŨmin, A_ΔŨmax = -I_Hc, I_Hc
686-
Ñ_Hc = Diagonal{NT}(diag_N_Hc)
686+
Ñ_Hc = N_Hc
687687
end
688688
return A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, Ñ_Hc
689689
end
@@ -817,9 +817,9 @@ function validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, C, E=nothing)
817817
size(M_Hp) (nM,nM) && throw(ArgumentError("M_Hp size $(size(M_Hp)) ≠ (ny*Hp, ny*Hp) ($nM,$nM)"))
818818
size(N_Hc) (nN,nN) && throw(ArgumentError("N_Hc size $(size(N_Hc)) ≠ (nu*Hc, nu*Hc) ($nN,$nN)"))
819819
size(L_Hp) (nL,nL) && throw(ArgumentError("L_Hp size $(size(L_Hp)) ≠ (nu*Hp, nu*Hp) ($nL,$nL)"))
820-
(!isdiag(M_Hp) || any(diag(M_Hp).<0)) && throw(ArgumentError("M_Hp should be a positive semidefinite diagonal matrix"))
821-
(!isdiag(N_Hc) || any(diag(N_Hc).<0)) && throw(ArgumentError("N_Hc should be a positive semidefinite diagonal matrix"))
822-
(!isdiag(L_Hp) || any(diag(L_Hp).<0)) && throw(ArgumentError("L_Hp should be a positive semidefinite diagonal matrix"))
820+
!ishermitian(M_Hp) && throw(ArgumentError("M_Hp should be a positive semidefinite hermitian"))
821+
!ishermitian(N_Hc) && throw(ArgumentError("N_Hc should be a positive semidefinite hermitian"))
822+
!ishermitian(L_Hp) && throw(ArgumentError("L_Hp should be a positive semidefinite hermitian"))
823823
size(C) () && throw(ArgumentError("Cwt should be a real scalar"))
824824
C < 0 && throw(ArgumentError("Cwt weight should be ≥ 0"))
825825
!isnothing(E) && size(E) () && throw(ArgumentError("Ewt should be a real scalar"))

src/controller/explicitmpc.jl

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
44
::Vector{NT}
55
Hp::Int
66
Hc::Int
7-
M_Hp::Diagonal{NT, Vector{NT}}
8-
Ñ_Hc::Diagonal{NT, Vector{NT}}
9-
L_Hp::Diagonal{NT, Vector{NT}}
7+
M_Hp::Hermitian{NT, Matrix{NT}}
8+
Ñ_Hc::Hermitian{NT, Matrix{NT}}
9+
L_Hp::Hermitian{NT, Matrix{NT}}
1010
C::NT
1111
E::NT
1212
R̂u::Vector{NT}
@@ -41,7 +41,8 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
4141
Cwt = Inf # no slack variable ϵ for ExplicitMPC
4242
Ewt = 0 # economic costs not supported for ExplicitMPC
4343
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
44-
M_Hp, N_Hc, L_Hp = Diagonal{NT}(M_Hp), Diagonal{NT}(N_Hc), Diagonal{NT}(L_Hp) # debug julia 1.6
44+
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
45+
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
4546
# dummy vals (updated just before optimization):
4647
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
4748
noR̂u = iszero(L_Hp)
@@ -118,9 +119,9 @@ function ExplicitMPC(
118119
Mwt = fill(DEFAULT_MWT, model.ny),
119120
Nwt = fill(DEFAULT_NWT, model.nu),
120121
Lwt = fill(DEFAULT_LWT, model.nu),
121-
M_Hp = Diagonal(repeat(Mwt, Hp)),
122-
N_Hc = Diagonal(repeat(Nwt, Hc)),
123-
L_Hp = Diagonal(repeat(Lwt, Hp)),
122+
M_Hp = diagm(repeat(Mwt, Hp)),
123+
N_Hc = diagm(repeat(Nwt, Hc)),
124+
L_Hp = diagm(repeat(Lwt, Hp)),
124125
kwargs...
125126
)
126127
estim = SteadyKalmanFilter(model; kwargs...)
@@ -156,9 +157,9 @@ function ExplicitMPC(
156157
Mwt = fill(DEFAULT_MWT, estim.model.ny),
157158
Nwt = fill(DEFAULT_NWT, estim.model.nu),
158159
Lwt = fill(DEFAULT_LWT, estim.model.nu),
159-
M_Hp = Diagonal(repeat(Mwt, Hp)),
160-
N_Hc = Diagonal(repeat(Nwt, Hc)),
161-
L_Hp = Diagonal(repeat(Lwt, Hp)),
160+
M_Hp = diagm(repeat(Mwt, Hp)),
161+
N_Hc = diagm(repeat(Nwt, Hc)),
162+
L_Hp = diagm(repeat(Lwt, Hp)),
162163
) where {NT<:Real, SE<:StateEstimator{NT}}
163164
isa(estim.model, LinModel) || error("estim.model type must be a LinModel")
164165
nk = estimate_delays(estim.model)

src/controller/linmpc.jl

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ struct LinMPC{
1414
::Vector{NT}
1515
Hp::Int
1616
Hc::Int
17-
M_Hp::Diagonal{NT, Vector{NT}}
18-
Ñ_Hc::Diagonal{NT, Vector{NT}}
19-
L_Hp::Diagonal{NT, Vector{NT}}
17+
M_Hp::Hermitian{NT, Matrix{NT}}
18+
Ñ_Hc::Hermitian{NT, Matrix{NT}}
19+
L_Hp::Hermitian{NT, Matrix{NT}}
2020
C::NT
2121
E::NT
2222
R̂u::Vector{NT}
@@ -49,7 +49,8 @@ struct LinMPC{
4949
= copy(model.yop) # dummy vals (updated just before optimization)
5050
Ewt = 0 # economic costs not supported for LinMPC
5151
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
52-
M_Hp, N_Hc, L_Hp = Diagonal{NT}(M_Hp), Diagonal{NT}(N_Hc), Diagonal{NT}(L_Hp) # debug julia 1.6
52+
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
53+
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
5354
# dummy vals (updated just before optimization):
5455
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5556
noR̂u = iszero(L_Hp)
@@ -119,9 +120,9 @@ arguments.
119120
- `Mwt=fill(1.0,model.ny)` : main diagonal of ``\mathbf{M}`` weight matrix (vector).
120121
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\mathbf{N}`` weight matrix (vector).
121122
- `Lwt=fill(0.0,model.nu)` : main diagonal of ``\mathbf{L}`` weight matrix (vector).
122-
- `M_Hp=Diagonal(repeat(Mwt),Hp)` : diagonal weight matrix ``\mathbf{M}_{H_p}``.
123-
- `N_Hc=Diagonal(repeat(Nwt),Hc)` : diagonal weight matrix ``\mathbf{N}_{H_c}``.
124-
- `L_Hp=Diagonal(repeat(Lwt),Hp)` : diagonal weight matrix ``\mathbf{L}_{H_p}``.
123+
- `M_Hp=diagm(repeat(Mwt,Hp))` : positive semidefinite symmetric weight ``\mathbf{M}_{H_p}``.
124+
- `N_Hc=diagm(repeat(Nwt,Hc))` : positive semidefinite symmetric weight ``\mathbf{N}_{H_c}``.
125+
- `L_Hp=diagm(repeat(Lwt,Hp))` : positive semidefinite symmetric weight ``\mathbf{L}_{H_p}``.
125126
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
126127
- `optim=JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer)` : quadratic optimizer used in
127128
the predictive controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.Model)
@@ -174,9 +175,9 @@ function LinMPC(
174175
Mwt = fill(DEFAULT_MWT, model.ny),
175176
Nwt = fill(DEFAULT_NWT, model.nu),
176177
Lwt = fill(DEFAULT_LWT, model.nu),
177-
M_Hp = Diagonal(repeat(Mwt, Hp)),
178-
N_Hc = Diagonal(repeat(Nwt, Hc)),
179-
L_Hp = Diagonal(repeat(Lwt, Hp)),
178+
M_Hp = diagm(repeat(Mwt, Hp)),
179+
N_Hc = diagm(repeat(Nwt, Hc)),
180+
L_Hp = diagm(repeat(Lwt, Hp)),
180181
Cwt = DEFAULT_CWT,
181182
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_LINMPC_OPTIMIZER, add_bridges=false),
182183
kwargs...
@@ -215,9 +216,9 @@ function LinMPC(
215216
Mwt = fill(DEFAULT_MWT, estim.model.ny),
216217
Nwt = fill(DEFAULT_NWT, estim.model.nu),
217218
Lwt = fill(DEFAULT_LWT, estim.model.nu),
218-
M_Hp = Diagonal(repeat(Mwt, Hp)),
219-
N_Hc = Diagonal(repeat(Nwt, Hc)),
220-
L_Hp = Diagonal(repeat(Lwt, Hp)),
219+
M_Hp = diagm(repeat(Mwt, Hp)),
220+
N_Hc = diagm(repeat(Nwt, Hc)),
221+
L_Hp = diagm(repeat(Lwt, Hp)),
221222
Cwt = DEFAULT_CWT,
222223
optim::JM = JuMP.Model(DEFAULT_LINMPC_OPTIMIZER, add_bridges=false),
223224
) where {NT<:Real, SE<:StateEstimator{NT}, JM<:JuMP.GenericModel}

src/controller/nonlinmpc.jl

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ struct NonLinMPC{
1515
::Vector{NT}
1616
Hp::Int
1717
Hc::Int
18-
M_Hp::Diagonal{NT, Vector{NT}}
19-
Ñ_Hc::Diagonal{NT, Vector{NT}}
20-
L_Hp::Diagonal{NT, Vector{NT}}
18+
M_Hp::Hermitian{NT, Matrix{NT}}
19+
Ñ_Hc::Hermitian{NT, Matrix{NT}}
20+
L_Hp::Hermitian{NT, Matrix{NT}}
2121
C::NT
2222
E::NT
2323
JE::JEfunc
@@ -50,7 +50,8 @@ struct NonLinMPC{
5050
nu, ny, nd = model.nu, model.ny, model.nd
5151
= copy(model.yop) # dummy vals (updated just before optimization)
5252
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
53-
M_Hp, N_Hc, L_Hp = Diagonal{NT}(M_Hp), Diagonal{NT}(N_Hc), Diagonal{NT}(L_Hp) # debug julia 1.6
53+
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
54+
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
5455
# dummy vals (updated just before optimization):
5556
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5657
noR̂u = iszero(L_Hp)
@@ -130,9 +131,9 @@ This method uses the default state estimator :
130131
- `Mwt=fill(1.0,model.ny)` : main diagonal of ``\mathbf{M}`` weight matrix (vector).
131132
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\mathbf{N}`` weight matrix (vector).
132133
- `Lwt=fill(0.0,model.nu)` : main diagonal of ``\mathbf{L}`` weight matrix (vector).
133-
- `M_Hp=Diagonal(repeat(Mwt),Hp)` : diagonal weight matrix ``\mathbf{M}_{H_p}``.
134-
- `N_Hc=Diagonal(repeat(Nwt),Hc)` : diagonal weight matrix ``\mathbf{N}_{H_c}``.
135-
- `L_Hp=Diagonal(repeat(Lwt),Hp)` : diagonal weight matrix ``\mathbf{L}_{H_p}``.
134+
- `M_Hp=diagm(repeat(Mwt,Hp))` : positive semidefinite symmetric weight ``\mathbf{M}_{H_p}``.
135+
- `N_Hc=diagm(repeat(Nwt,Hc))` : positive semidefinite symmetric weight ``\mathbf{N}_{H_c}``.
136+
- `L_Hp=diagm(repeat(Lwt,Hp))` : positive semidefinite symmetric weight ``\mathbf{L}_{H_p}``.
136137
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
137138
- `Ewt=0.0` : economic costs weight ``E`` (scalar).
138139
- `JE=(_,_,_)->0.0` : economic function ``J_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E)``.
@@ -179,9 +180,9 @@ function NonLinMPC(
179180
Mwt = fill(DEFAULT_MWT, model.ny),
180181
Nwt = fill(DEFAULT_NWT, model.nu),
181182
Lwt = fill(DEFAULT_LWT, model.nu),
182-
M_Hp = Diagonal(repeat(Mwt, Hp)),
183-
N_Hc = Diagonal(repeat(Nwt, Hc)),
184-
L_Hp = Diagonal(repeat(Lwt, Hp)),
183+
M_Hp = diagm(repeat(Mwt, Hp)),
184+
N_Hc = diagm(repeat(Nwt, Hc)),
185+
L_Hp = diagm(repeat(Lwt, Hp)),
185186
Cwt = DEFAULT_CWT,
186187
Ewt = DEFAULT_EWT,
187188
JE::Function = (_,_,_) -> 0.0,
@@ -199,9 +200,9 @@ function NonLinMPC(
199200
Mwt = fill(DEFAULT_MWT, model.ny),
200201
Nwt = fill(DEFAULT_NWT, model.nu),
201202
Lwt = fill(DEFAULT_LWT, model.nu),
202-
M_Hp = Diagonal(repeat(Mwt, Hp)),
203-
N_Hc = Diagonal(repeat(Nwt, Hc)),
204-
L_Hp = Diagonal(repeat(Lwt, Hp)),
203+
M_Hp = diagm(repeat(Mwt, Hp)),
204+
N_Hc = diagm(repeat(Nwt, Hc)),
205+
L_Hp = diagm(repeat(Lwt, Hp)),
205206
Cwt = DEFAULT_CWT,
206207
Ewt = DEFAULT_EWT,
207208
JE::Function = (_,_,_) -> 0.0,
@@ -242,9 +243,9 @@ function NonLinMPC(
242243
Mwt = fill(DEFAULT_MWT, estim.model.ny),
243244
Nwt = fill(DEFAULT_NWT, estim.model.nu),
244245
Lwt = fill(DEFAULT_LWT, estim.model.nu),
245-
M_Hp = Diagonal(repeat(Mwt, Hp)),
246-
N_Hc = Diagonal(repeat(Nwt, Hc)),
247-
L_Hp = Diagonal(repeat(Lwt, Hp)),
246+
M_Hp = diagm(repeat(Mwt, Hp)),
247+
N_Hc = diagm(repeat(Nwt, Hc)),
248+
L_Hp = diagm(repeat(Lwt, Hp)),
248249
Cwt = DEFAULT_CWT,
249250
Ewt = DEFAULT_EWT,
250251
JE::JEFunc = (_,_,_) -> 0.0,

0 commit comments

Comments
 (0)