Skip to content

Commit 05739eb

Browse files
committed
added: gE and nE field in ControllerConstraint
1 parent 36350da commit 05739eb

File tree

2 files changed

+65
-30
lines changed

2 files changed

+65
-30
lines changed

src/controller/construct.jl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"Include all the data for the constraints of [`PredictiveController`](@ref)"
2-
struct ControllerConstraint{NT<:Real}
2+
struct ControllerConstraint{NT<:Real, GEfunc<:Function}
33
ẽx̂ ::Matrix{NT}
44
fx̂ ::Vector{NT}
55
gx̂ ::Matrix{NT}
@@ -31,6 +31,8 @@ struct ControllerConstraint{NT<:Real}
3131
c_x̂min ::Vector{NT}
3232
c_x̂max ::Vector{NT}
3333
i_g ::BitVector
34+
gE ::GEfunc
35+
nE ::Int
3436
end
3537

3638
@doc raw"""
@@ -625,16 +627,18 @@ function init_quadprog(::SimModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:
625627
end
626628

627629
"""
628-
init_defaultcon_mpc(estim, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂) -> con, S̃, Ñ_Hc, Ẽ
630+
init_defaultcon_mpc(
631+
estim, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, gE=()->nothing, nE=0
632+
) -> con, S̃, Ñ_Hc, Ẽ
629633
630634
Init `ControllerConstraint` struct with default parameters based on estimator `estim`.
631635
632636
Also return `S̃`, `Ñ_Hc` and `Ẽ` matrices for the the augmented decision vector `ΔŨ`.
633637
"""
634638
function init_defaultcon_mpc(
635639
estim::StateEstimator{NT},
636-
Hp, Hc, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂
637-
) where {NT<:Real}
640+
Hp, Hc, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂, gE::GEfunc=()->nothing, nE=0
641+
) where {NT<:Real, GEfunc<:Function}
638642
model = estim.model
639643
nu, ny, nx̂ = model.nu, model.ny, estim.nx̂
640644
= isinf(C) ? 0 : 1
@@ -666,11 +670,12 @@ function init_defaultcon_mpc(
666670
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂max, A_x̂min
667671
)
668672
b = zeros(NT, size(A, 1)) # dummy b vector (updated just before optimization)
669-
con = ControllerConstraint{NT}(
673+
con = ControllerConstraint{NT, GEfunc}(
670674
ẽx̂ , fx̂ , gx̂ , jx̂ , kx̂ , vx̂ , bx̂ ,
671675
U0min , U0max , ΔŨmin , ΔŨmax , Y0min , Y0max , x̂0min , x̂0max,
672676
A_Umin , A_Umax, A_ΔŨmin, A_ΔŨmax , A_Ymin , A_Ymax , A_x̂min , A_x̂max,
673-
A , b , i_b , C_ymin , C_ymax , c_x̂min , c_x̂max , i_g
677+
A , b , i_b , C_ymin , C_ymax , c_x̂min , c_x̂max , i_g,
678+
gE , nE
674679
)
675680
return con, nϵ, S̃, Ñ_Hc, Ẽ
676681
end

src/controller/nonlinmpc.jl

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ struct NonLinMPC{
4848
Yop::Vector{NT}
4949
Dop::Vector{NT}
5050
buffer::PredictiveControllerBuffer{NT}
51-
function NonLinMPC{NT, SE, JM, JEFunc, P}(
52-
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEFunc, p::P, optim::JM
53-
) where {NT<:Real, SE<:StateEstimator, JM<:JuMP.GenericModel, JEFunc<:Function, P<:Any}
51+
function NonLinMPC{NT, SE, JM, JEfunc, P}(
52+
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gE, nE, p::P, optim::JM
53+
) where {NT<:Real, SE<:StateEstimator, JM<:JuMP.GenericModel, JEfunc<:Function, P<:Any}
5454
model = estim.model
5555
nu, ny, nd, nx̂ = model.nu, model.ny, model.nd, estim.nx̂
5656
= copy(model.yop) # dummy vals (updated just before optimization)
@@ -68,7 +68,7 @@ struct NonLinMPC{
6868
# dummy vals (updated just before optimization):
6969
F, fx̂ = zeros(NT, ny*Hp), zeros(NT, nx̂)
7070
con, nϵ, S̃, Ñ_Hc, Ẽ = init_defaultcon_mpc(
71-
estim, Hp, Hc, Cwt, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂
71+
estim, Hp, Hc, Cwt, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂, gE, nE
7272
)
7373
= init_quadprog(model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
7474
# dummy vals (updated just before optimization):
@@ -80,7 +80,7 @@ struct NonLinMPC{
8080
nΔŨ = size(Ẽ, 2)
8181
ΔŨ = zeros(NT, nΔŨ)
8282
buffer = PredictiveControllerBuffer{NT}(nu, ny, nd, Hp)
83-
mpc = new{NT, SE, JM, JEFunc, P}(
83+
mpc = new{NT, SE, JM, JEfunc, P}(
8484
estim, optim, con,
8585
ΔŨ, ŷ,
8686
Hp, Hc, nϵ,
@@ -115,14 +115,14 @@ controller minimizes the following objective function at each discrete time ``k`
115115
+ E J_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, \mathbf{p})
116116
\end{aligned}
117117
```
118-
subject to [`setconstraint!`](@ref) bounds, and the custom economic inequality constraints:
118+
subject to [`setconstraint!`](@ref) bounds, and the economic inequality constraints:
119119
```math
120-
\mathbf{g}_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, \mathbf{p}, ε) ≤ \mathbf{0}
121-
````
120+
\mathbf{g}_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, ϵ, \mathbf{p}) ≤ \mathbf{0}
121+
```
122122
The economic function ``J_E`` can penalizes solutions with high economic costs. Setting all
123123
the weights to 0 except ``E`` creates a pure economic model predictive controller (EMPC).
124-
The arguments of ``J_E`` include the manipulated inputs, the predicted outputs and measured
125-
disturbances from ``k`` to ``k+H_p`` inclusively:
124+
The arguments of ``J_E`` and ``\mathbf{g}_E`` include the manipulated inputs, the predicted
125+
outputs and measured disturbances from ``k`` to ``k+H_p`` inclusively:
126126
```math
127127
\mathbf{U}_E = \begin{bmatrix} \mathbf{U} \\ \mathbf{u}(k+H_p-1) \end{bmatrix} , \quad
128128
\mathbf{Ŷ}_E = \begin{bmatrix} \mathbf{ŷ}(k) \\ \mathbf{Ŷ} \end{bmatrix} , \quad
@@ -134,7 +134,8 @@ over ``H_p``. The argument ``\mathbf{p}`` is a custom parameter object of any ty
134134
mutable one if you want to modify it later e.g.: a vector.
135135
136136
!!! tip
137-
Replace any of the 4 arguments with `_` if not needed (see `JE` default value below).
137+
Replace any of the arguments of ``J_E`` and ``\mathbf{g}_E`` functions with `_` if not
138+
needed (details in Extended Help).
138139
139140
See [`LinMPC`](@ref) for the definition of the other variables. This method uses the default
140141
state estimator :
@@ -158,11 +159,12 @@ state estimator :
158159
- `L_Hp=diagm(repeat(Lwt,Hp))` : positive semidefinite symmetric matrix ``\mathbf{L}_{H_p}``.
159160
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
160161
- `Ewt=0.0` : economic costs weight ``E`` (scalar).
161-
- `JE=(_,_,_,_)->0.0` : economic (or custom) cost function
162-
``J_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, \mathbf{p})``.
163-
- `gE=(_,_,_,_,_)->[]` : economic (or custom) constraint function
164-
``\mathbf{g}_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, \mathbf{p}, ε)``.
165-
- `p=model.p` : ``J_E`` function parameter ``\mathbf{p}`` (any type).
162+
- `JE=(_,_,_,_)->0.0` : economic (or custom) cost function ``J_E(\mathbf{U}_E, \mathbf{Ŷ}_E,
163+
\mathbf{D̂}_E, \mathbf{p})`` (details in Extended Help).
164+
- `gE=(_,_,_,_,_,_)->nothing` : economic (or custom) constraint function ``\mathbf{g}_E(
165+
\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, ϵ, \mathbf{p})`` (details in Extended Help).
166+
- `nE=0` : number of economic constraints.
167+
- `p=model.p` : ``J_E`` and ``\mathbf{g}_E`` functions parameter ``\mathbf{p}`` (any type).
166168
- `optim=JuMP.Model(Ipopt.Optimizer)` : nonlinear optimizer used in the predictive
167169
controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.Model)
168170
(default to [`Ipopt`](https://github.com/jump-dev/Ipopt.jl) optimizer).
@@ -191,6 +193,15 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
191193
algebra instead of a `for` loop. This feature can accelerate the optimization, especially
192194
for the constraint handling, and is not available in any other package, to my knowledge.
193195
196+
The J
197+
198+
1. **Non-mutating functions** (out-of-place): define them as `f(x, u, d, p) -> ẋ` and
199+
`h(x, d, p) -> y`. This syntax is simple and intuitive but it allocates more memory.
200+
2. **Mutating functions** (in-place): define them as `f!(ẋ, x, u, d, p) -> nothing` and
201+
`h!(y, x, d, p) -> nothing`. This syntax reduces the allocations and potentially the
202+
computational burden as well.
203+
204+
194205
The optimization relies on [`JuMP`](https://github.com/jump-dev/JuMP.jl) automatic
195206
differentiation (AD) to compute the objective and constraint derivatives. Optimizers
196207
generally benefit from exact derivatives like AD. However, the [`NonLinModel`](@ref)
@@ -212,13 +223,18 @@ function NonLinMPC(
212223
L_Hp = diagm(repeat(Lwt, Hp)),
213224
Cwt = DEFAULT_CWT,
214225
Ewt = DEFAULT_EWT,
215-
JE::Function = (args...) -> 0.0,
226+
JE::Function = (_,_,_,_) -> 0.0,
227+
gE::Function = (_,_,_,_,_,_) -> nothing,
228+
nE = 0,
216229
p = model.p,
217230
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
218231
kwargs...
219232
)
220233
estim = UnscentedKalmanFilter(model; kwargs...)
221-
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, p, M_Hp, N_Hc, L_Hp, optim)
234+
return NonLinMPC(
235+
estim;
236+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gE, nE, p, M_Hp, N_Hc, L_Hp, optim
237+
)
222238
end
223239

224240
function NonLinMPC(
@@ -233,13 +249,18 @@ function NonLinMPC(
233249
L_Hp = diagm(repeat(Lwt, Hp)),
234250
Cwt = DEFAULT_CWT,
235251
Ewt = DEFAULT_EWT,
236-
JE::Function = (args...) -> 0.0,
252+
JE::Function = (_,_,_,_) -> 0.0,
253+
gE::Function = (_,_,_,_,_,_) -> nothing,
254+
nE = 0,
237255
p = model.p,
238256
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
239257
kwargs...
240258
)
241259
estim = SteadyKalmanFilter(model; kwargs...)
242-
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, p, M_Hp, N_Hc, L_Hp, optim)
260+
return NonLinMPC(
261+
estim;
262+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gE, nE, p, M_Hp, N_Hc, L_Hp, optim
263+
)
243264
end
244265

245266

@@ -278,17 +299,26 @@ function NonLinMPC(
278299
L_Hp = diagm(repeat(Lwt, Hp)),
279300
Cwt = DEFAULT_CWT,
280301
Ewt = DEFAULT_EWT,
281-
JE::JEFunc = (args...) -> 0.0,
302+
JE::JEfunc = (_,_,_,_) -> 0.0,
303+
gE::GEfunc = (_,_,_,_,_,_) -> nothing,
304+
nE = 0,
282305
p::P = estim.model.p,
283306
optim::JM = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
284-
) where {NT<:Real, SE<:StateEstimator{NT}, JM<:JuMP.GenericModel, JEFunc<:Function, P<:Any}
307+
) where {
308+
NT<:Real,
309+
SE<:StateEstimator{NT},
310+
JM<:JuMP.GenericModel,
311+
JEfunc<:Function,
312+
GEfunc<:Function,
313+
P<:Any
314+
}
285315
nk = estimate_delays(estim.model)
286316
if Hp nk
287317
@warn("prediction horizon Hp ($Hp) ≤ estimated number of delays in model "*
288318
"($nk), the closed-loop system may be unstable or zero-gain (unresponsive)")
289319
end
290-
return NonLinMPC{NT, SE, JM, JEFunc, P}(
291-
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, p, optim
320+
return NonLinMPC{NT, SE, JM, JEfunc, P}(
321+
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gE, nE, p, optim
292322
)
293323
end
294324

0 commit comments

Comments
 (0)