Skip to content

Commit 9eabd05

Browse files
committed
added : non-constant manip. input setpoints
1 parent 0bc67b8 commit 9eabd05

File tree

6 files changed

+103
-119
lines changed

6 files changed

+103
-119
lines changed

docs/src/public/predictive_control.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ The vectors for the manipulated input ``\mathbf{u}`` are shifted by one time ste
3535

3636
```math
3737
\mathbf{U} = \begin{bmatrix}
38-
\mathbf{u}(k+0) \\ \mathbf{u}(k+1) \\ \vdots \\ \mathbf{u}(k+H_p-1)
38+
\mathbf{u}(k+0) \\ \mathbf{u}(k+1) \\ \vdots \\ \mathbf{u}(k+H_p-1)
3939
\end{bmatrix} \quad \text{and} \quad
4040
\mathbf{R̂_u} = \begin{bmatrix}
41-
\mathbf{r_u} \\ \mathbf{r_u} \\ \vdots \\ \mathbf{r_u}
41+
\mathbf{r̂_u}(k+0) \\ \mathbf{r̂_u}(k+1) \\ \vdots \\ \mathbf{r̂_u}(k+H_p-1)
4242
\end{bmatrix}
4343
```
4444

45-
assuming constant input setpoints at ``\mathbf{r_u}``. Defining the manipulated input
46-
increment as ``\mathbf{Δu}(k+j) = \mathbf{u}(k+j) - \mathbf{u}(k+j-1)``, the control horizon
47-
``H_c`` enforces that ``\mathbf{Δu}(k+j) = \mathbf{0}`` for ``j ≥ H_c``. For this reason,
48-
the vector that collects them is truncated up to ``k+H_c-1``:
45+
Defining the manipulated input increment as ``\mathbf{Δu}(k+j) =
46+
\mathbf{u}(k+j) - \mathbf{u}(k+j-1)``, the control horizon ``H_c`` enforces that
47+
``\mathbf{Δu}(k+j) = \mathbf{0}`` for ``j ≥ H_c``. For this reason, the vector that collects
48+
them is truncated up to ``k+H_c-1``:
4949

5050
```math
5151
\mathbf{ΔU} =

src/controller/explicitmpc.jl

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
1111
E::Float64
1212
R̂u::Vector{Float64}
1313
R̂y::Vector{Float64}
14+
noR̂u::Bool
1415
S̃_Hp::Matrix{Bool}
1516
T_Hp::Matrix{Bool}
1617
T_Hc::Matrix{Bool}
@@ -30,20 +31,19 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
3031
::Vector{Float64}
3132
Ŷop::Vector{Float64}
3233
Dop::Vector{Float64}
33-
function ExplicitMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt, ru) where {S<:StateEstimator}
34+
function ExplicitMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt) where {S<:StateEstimator}
3435
model = estim.model
3536
nu, ny, nd = model.nu, model.ny, model.nd
3637
= zeros(ny)
3738
Cwt = Inf # no slack variable ϵ for ExplicitMPC
3839
Ewt = 0 # economic costs not supported for ExplicitMPC
39-
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru)
40+
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt)
4041
M_Hp = Diagonal{Float64}(repeat(Mwt, Hp))
4142
N_Hc = Diagonal{Float64}(repeat(Nwt, Hc))
4243
L_Hp = Diagonal{Float64}(repeat(Lwt, Hp))
4344
C = Cwt
44-
# manipulated input setpoint predictions are constant over Hp :
45-
R̂u = ~iszero(Lwt) ? repeat(ru, Hp) : R̂u = empty(estim.x̂)
46-
R̂y = zeros(ny* Hp) # dummy R̂y (updated just before optimization)
45+
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
46+
noR̂u = iszero(L_Hp)
4747
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
4848
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
4949
_ , S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
@@ -58,7 +58,7 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
5858
estim,
5959
ΔŨ, ŷ,
6060
Hp, Hc,
61-
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y,
61+
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
6262
S̃_Hp, T_Hp, T_Hc,
6363
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6464
P̃_chol,
@@ -94,7 +94,6 @@ state estimator, a [`SteadyKalmanFilter`](@ref) with default arguments.
9494
- `Mwt=fill(1.0,model.ny)` : main diagonal of ``\mathbf{M}`` weight matrix (vector).
9595
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\mathbf{N}`` weight matrix (vector).
9696
- `Lwt=fill(0.0,model.nu)` : main diagonal of ``\mathbf{L}`` weight matrix (vector).
97-
- `ru=model.uop` : manipulated input setpoints ``\mathbf{r_u}`` (vector).
9897
- additionnal keyword arguments are passed to [`SteadyKalmanFilter`](@ref) constructor.
9998
10099
# Examples
@@ -120,11 +119,10 @@ function ExplicitMPC(
120119
Mwt = fill(DEFAULT_MWT, model.ny),
121120
Nwt = fill(DEFAULT_NWT, model.nu),
122121
Lwt = fill(DEFAULT_LWT, model.nu),
123-
ru = model.uop,
124122
kwargs...
125123
)
126124
estim = SteadyKalmanFilter(model; kwargs...)
127-
return ExplicitMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, ru)
125+
return ExplicitMPC(estim; Hp, Hc, Mwt, Nwt, Lwt)
128126
end
129127

130128
"""
@@ -155,8 +153,7 @@ function ExplicitMPC(
155153
Hc::Int = DEFAULT_HC,
156154
Mwt = fill(DEFAULT_MWT, estim.model.ny),
157155
Nwt = fill(DEFAULT_NWT, estim.model.nu),
158-
Lwt = fill(DEFAULT_LWT, estim.model.nu),
159-
ru = estim.model.uop,
156+
Lwt = fill(DEFAULT_LWT, estim.model.nu)
160157
) where {S<:StateEstimator}
161158
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
162159
poles = eigvals(estim.model.A)
@@ -168,7 +165,7 @@ function ExplicitMPC(
168165
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
169166
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
170167
end
171-
return ExplicitMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt, ru)
168+
return ExplicitMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt)
172169
end
173170

174171
setconstraint!(::ExplicitMPC,kwargs...) = error("ExplicitMPC does not support constraints.")

src/controller/linmpc.jl

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
1313
E::Float64
1414
R̂u::Vector{Float64}
1515
R̂y::Vector{Float64}
16+
noR̂u::Bool
1617
S̃_Hp::Matrix{Bool}
1718
T_Hp::Matrix{Bool}
1819
T_Hc::Matrix{Bool}
@@ -31,19 +32,18 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
3132
::Vector{Float64}
3233
Ŷop::Vector{Float64}
3334
Dop::Vector{Float64}
34-
function LinMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru, optim) where {S<:StateEstimator}
35+
function LinMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim) where {S<:StateEstimator}
3536
model = estim.model
3637
nu, ny, nd = model.nu, model.ny, model.nd
3738
= zeros(ny)
3839
Ewt = 0 # economic costs not supported for LinMPC
39-
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru)
40+
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt)
4041
M_Hp = Diagonal{Float64}(repeat(Mwt, Hp))
4142
N_Hc = Diagonal{Float64}(repeat(Nwt, Hc))
4243
L_Hp = Diagonal{Float64}(repeat(Lwt, Hp))
4344
C = Cwt
44-
# manipulated input setpoint predictions are constant over Hp :
45-
R̂u = ~iszero(Lwt) ? repeat(ru, Hp) : R̂u = empty(estim.x̂)
46-
R̂y = zeros(ny* Hp) # dummy R̂y (updated just before optimization)
45+
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
46+
noR̂u = iszero(L_Hp)
4747
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
4848
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
4949
con, S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
@@ -57,7 +57,7 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
5757
estim, optim, con,
5858
ΔŨ, ŷ,
5959
Hp, Hc,
60-
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y,
60+
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
6161
S̃_Hp, T_Hp, T_Hc,
6262
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6363
Ks, Ps,
@@ -89,12 +89,11 @@ in which the weight matrices are repeated ``H_p`` or ``H_c`` times:
8989
\mathbf{L}_{H_p} &= \text{diag}\mathbf{(L,L,...,L)}
9090
\end{aligned}
9191
```
92-
The ``\mathbf{ΔU}`` vector includes the manipulated input increments ``\mathbf{Δu}(k+j) =
93-
\mathbf{u}(k+j) - \mathbf{u}(k+j-1)`` from ``j=0`` to ``H_c-1``, the ``\mathbf{Ŷ}`` vector,
94-
the output predictions ``\mathbf{ŷ}(k+j)`` from ``j=1`` to ``H_p``, and the ``\mathbf{U}``
95-
vector, the manipulated inputs ``\mathbf{u}(k+j)`` from ``j=0`` to ``H_p-1``. The
96-
manipulated input setpoint predictions ``\mathbf{R̂_u}`` are constant at ``\mathbf{r_u}``.
97-
See Extended Help for a detailed nomenclature.
92+
The ``\mathbf{ΔU}`` vector includes the manipulated input increments ``\mathbf{Δu}(k+j) =
93+
\mathbf{u}(k+j) - \mathbf{u}(k+j-1)`` from ``j=0`` to ``H_c-1``, the ``\mathbf{Ŷ}`` vector,
94+
the output predictions ``\mathbf{ŷ}(k+j)`` from ``j=1`` to ``H_p``, and the ``\mathbf{U}``
95+
vector, the manipulated inputs ``\mathbf{u}(k+j)`` from ``j=0`` to ``H_p-1``. See Extended
96+
Help for a detailed nomenclature.
9897
9998
This method uses the default state estimator, a [`SteadyKalmanFilter`](@ref) with default
10099
arguments.
@@ -107,7 +106,6 @@ arguments.
107106
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\mathbf{N}`` weight matrix (vector).
108107
- `Lwt=fill(0.0,model.nu)` : main diagonal of ``\mathbf{L}`` weight matrix (vector).
109108
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
110-
- `ru=model.uop` : manipulated input setpoints ``\mathbf{r_u}`` (vector).
111109
- `optim=JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer)` : quadratic optimizer used in
112110
the predictive controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/reference/models/#JuMP.Model)
113111
(default to [`OSQP.jl`](https://osqp.org/docs/parsers/jump.html) optimizer).
@@ -158,12 +156,11 @@ function LinMPC(
158156
Nwt = fill(DEFAULT_NWT, model.nu),
159157
Lwt = fill(DEFAULT_LWT, model.nu),
160158
Cwt = DEFAULT_CWT,
161-
ru = model.uop,
162159
optim::JuMP.Model = JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer),
163160
kwargs...
164161
)
165162
estim = SteadyKalmanFilter(model; kwargs...)
166-
return LinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru, optim)
163+
return LinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim)
167164
end
168165

169166

@@ -197,7 +194,6 @@ function LinMPC(
197194
Nwt = fill(DEFAULT_NWT, estim.model.nu),
198195
Lwt = fill(DEFAULT_LWT, estim.model.nu),
199196
Cwt = DEFAULT_CWT,
200-
ru = estim.model.uop,
201197
optim::JuMP.Model = JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer)
202198
) where {S<:StateEstimator}
203199
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
@@ -210,7 +206,7 @@ function LinMPC(
210206
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
211207
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
212208
end
213-
return LinMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru, optim)
209+
return LinMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim)
214210
end
215211

216212
"""

src/controller/nonlinmpc.jl

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
1616
JE::JEfunc
1717
R̂u::Vector{Float64}
1818
R̂y::Vector{Float64}
19+
noR̂u::Bool
1920
S̃_Hp::Matrix{Bool}
2021
T_Hp::Matrix{Bool}
2122
T_Hc::Matrix{Bool}
@@ -35,19 +36,18 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
3536
Ŷop::Vector{Float64}
3637
Dop::Vector{Float64}
3738
function NonLinMPC{S, JEFunc}(
38-
estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE::JEFunc, ru, optim
39+
estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE::JEFunc, optim
3940
) where {S<:StateEstimator, JEFunc<:Function}
4041
model = estim.model
4142
nu, ny, nd = model.nu, model.ny, model.nd
4243
= zeros(ny)
43-
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru, Ewt)
44+
validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt)
4445
M_Hp = Diagonal(convert(Vector{Float64}, repeat(Mwt, Hp)))
4546
N_Hc = Diagonal(convert(Vector{Float64}, repeat(Nwt, Hc)))
4647
L_Hp = Diagonal(convert(Vector{Float64}, repeat(Lwt, Hp)))
4748
C = Cwt
48-
# manipulated input setpoint predictions are constant over Hp :
49-
R̂u = ~iszero(Lwt) ? repeat(ru, Hp) : R̂u = empty(estim.x̂)
50-
R̂y = zeros(ny* Hp) # dummy R̂y (updated just before optimization)
49+
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
50+
noR̂u = iszero(L_Hp)
5151
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
5252
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
5353
con, S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
@@ -61,7 +61,7 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
6161
estim, optim, con,
6262
ΔŨ, ŷ,
6363
Hp, Hc,
64-
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, JE, R̂u, R̂y,
64+
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, JE, R̂u, R̂y, noR̂u,
6565
S̃_Hp, T_Hp, T_Hc,
6666
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6767
Ks, Ps,
@@ -121,7 +121,6 @@ This method uses the default state estimator :
121121
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
122122
- `Ewt=0.0` : economic costs weight ``E`` (scalar).
123123
- `JE=(_,_,_)->0.0` : economic function ``J_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E)``.
124-
- `ru=model.uop` : manipulated input setpoints ``\mathbf{r_u}`` (vector).
125124
- `optim=JuMP.Model(Ipopt.Optimizer)` : nonlinear optimizer used in the predictive
126125
controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/reference/models/#JuMP.Model)
127126
(default to [`Ipopt.jl`](https://github.com/jump-dev/Ipopt.jl) optimizer).
@@ -164,12 +163,11 @@ function NonLinMPC(
164163
Cwt = DEFAULT_CWT,
165164
Ewt = DEFAULT_EWT,
166165
JE::Function = (_,_,_) -> 0.0,
167-
ru = model.uop,
168166
optim::JuMP.Model = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes")),
169167
kwargs...
170168
)
171169
estim = UnscentedKalmanFilter(model; kwargs...)
172-
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, ru, optim)
170+
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
173171
end
174172
function NonLinMPC(
175173
model::LinModel;
@@ -181,12 +179,11 @@ function NonLinMPC(
181179
Cwt = DEFAULT_CWT,
182180
Ewt = DEFAULT_EWT,
183181
JE::Function = (_,_,_) -> 0.0,
184-
ru = model.uop,
185182
optim::JuMP.Model = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes")),
186183
kwargs...
187184
)
188185
estim = SteadyKalmanFilter(model; kwargs...)
189-
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, ru, optim)
186+
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
190187
end
191188

192189

@@ -222,10 +219,9 @@ function NonLinMPC(
222219
Cwt = DEFAULT_CWT,
223220
Ewt = DEFAULT_EWT,
224221
JE::JEFunc = (_,_,_) -> 0.0,
225-
ru = estim.model.uop,
226222
optim::JuMP.Model = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"))
227223
) where {S<:StateEstimator, JEFunc<:Function}
228-
return NonLinMPC{S, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, ru, optim)
224+
return NonLinMPC{S, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
229225
end
230226

231227
"""

0 commit comments

Comments
 (0)