@@ -4,7 +4,8 @@ struct NonLinMPC{
44 NT<: Real ,
55 SE<: StateEstimator ,
66 JM<: JuMP.GenericModel ,
7- JEfunc<: Function
7+ JEfunc<: Function ,
8+ P<: Any
89} <: PredictiveController{NT}
910 estim:: SE
1011 # note: `NT` and the number type `JNT` in `JuMP.GenericModel{JNT}` can be
@@ -21,6 +22,7 @@ struct NonLinMPC{
2122 L_Hp:: Hermitian{NT, Matrix{NT}}
2223 E:: NT
2324 JE:: JEfunc
25+ p:: P
2426 R̂u0:: Vector{NT}
2527 R̂y0:: Vector{NT}
2628 noR̂u:: Bool
@@ -46,9 +48,9 @@ struct NonLinMPC{
4648 Yop:: Vector{NT}
4749 Dop:: Vector{NT}
4850 buffer:: PredictiveControllerBuffer{NT}
49- function NonLinMPC {NT, SE, JM, JEFunc} (
50- estim:: SE , Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE:: JEFunc , optim:: JM
51- ) where {NT<: Real , SE<: StateEstimator , JM<: JuMP.GenericModel , JEFunc<: Function }
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 }
5254 model = estim. model
5355 nu, ny, nd, nx̂ = model. nu, model. ny, model. nd, estim. nx̂
5456 ŷ = copy (model. yop) # dummy vals (updated just before optimization)
@@ -77,11 +79,11 @@ struct NonLinMPC{
7779 nΔŨ = size (Ẽ, 2 )
7880 ΔŨ = zeros (NT, nΔŨ)
7981 buffer = PredictiveControllerBuffer {NT} (nu, ny, nd, Hp)
80- mpc = new {NT, SE, JM, JEFunc} (
82+ mpc = new {NT, SE, JM, JEFunc, P } (
8183 estim, optim, con,
8284 ΔŨ, ŷ,
8385 Hp, Hc, nϵ,
84- M_Hp, Ñ_Hc, L_Hp, Ewt, JE,
86+ M_Hp, Ñ_Hc, L_Hp, Ewt, JE, p,
8587 R̂u0, R̂y0, noR̂u,
8688 S̃, T, T_lastu0,
8789 Ẽ, F, G, J, K, V, B,
@@ -109,12 +111,12 @@ controller minimizes the following objective function at each discrete time ``k`
109111 + \m athbf{(ΔU)}' \m athbf{N}_{H_c} \m athbf{(ΔU)} \\ &
110112 + \m athbf{(R̂_u - U)}' \m athbf{L}_{H_p} \m athbf{(R̂_u - U)}
111113 + C ϵ^2
112- + E J_E(\m athbf{U}_E, \m athbf{Ŷ}_E, \m athbf{D̂}_E)
114+ + E J_E(\m athbf{U}_E, \m athbf{Ŷ}_E, \m athbf{D̂}_E, \m athbf{p} )
113115\e nd{aligned}
114116```
115117See [`LinMPC`](@ref) for the variable definitions. The custom economic function ``J_E`` can
116118penalizes solutions with high economic costs. Setting all the weights to 0 except ``E``
117- creates a pure economic model predictive controller (EMPC). The arguments of ``J_E`` are
119+ creates a pure economic model predictive controller (EMPC). The arguments of ``J_E`` include
118120the manipulated inputs, the predicted outputs and measured disturbances from ``k`` to
119121``k+H_p`` inclusively:
120122```math
@@ -124,10 +126,10 @@ the manipulated inputs, the predicted outputs and measured disturbances from ``k
124126```
125127since ``H_c ≤ H_p`` implies that ``\m athbf{Δu}(k+H_p) = \m athbf{0}`` or ``\m athbf{u}(k+H_p)=
126128\m athbf{u}(k+H_p-1)``. The vector ``\m athbf{D̂}`` includes the predicted measured disturbance
127- over ``H_p``.
129+ over ``H_p``. The argument `` \m athbf{p}`` is a custom parameter object of any type.
128130
129131!!! tip
130- Replace any of the 3 arguments with `_` if not needed (see `JE` default value below).
132+ Replace any of the 4 arguments with `_` if not needed (see `JE` default value below).
131133
132134This method uses the default state estimator :
133135
@@ -150,7 +152,8 @@ This method uses the default state estimator :
150152- `L_Hp=diagm(repeat(Lwt,Hp))` : positive semidefinite symmetric matrix ``\m athbf{L}_{H_p}``.
151153- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
152154- `Ewt=0.0` : economic costs weight ``E`` (scalar).
153- - `JE=(_,_,_)->0.0` : economic function ``J_E(\m athbf{U}_E, \m athbf{Ŷ}_E, \m athbf{D̂}_E)``.
155+ - `JE=(_,_,_,_)->0.0` : economic function ``J_E(\m athbf{U}_E, \m athbf{Ŷ}_E, \m athbf{D̂}_E, \m athbf{p})``.
156+ - `p=model.p` : ``J_E`` function parameter ``\m athbf{p}`` (any type).
154157- `optim=JuMP.Model(Ipopt.Optimizer)` : nonlinear optimizer used in the predictive
155158 controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.Model)
156159 (default to [`Ipopt`](https://github.com/jump-dev/Ipopt.jl) optimizer).
@@ -201,11 +204,12 @@ function NonLinMPC(
201204 Cwt = DEFAULT_CWT,
202205 Ewt = DEFAULT_EWT,
203206 JE:: Function = (_,_,_) -> 0.0 ,
207+ p = model. p,
204208 optim:: JuMP.GenericModel = JuMP. Model (DEFAULT_NONLINMPC_OPTIMIZER, add_bridges= false ),
205209 kwargs...
206210)
207211 estim = UnscentedKalmanFilter (model; kwargs... )
208- NonLinMPC (estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, M_Hp, N_Hc, L_Hp, optim)
212+ NonLinMPC (estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, p, M_Hp, N_Hc, L_Hp, optim)
209213end
210214
211215function NonLinMPC (
@@ -220,12 +224,13 @@ function NonLinMPC(
220224 L_Hp = diagm (repeat (Lwt, Hp)),
221225 Cwt = DEFAULT_CWT,
222226 Ewt = DEFAULT_EWT,
223- JE:: Function = (_,_,_) -> 0.0 ,
227+ JE:: Function = (_,_,_,_) -> 0.0 ,
228+ p = model. p,
224229 optim:: JuMP.GenericModel = JuMP. Model (DEFAULT_NONLINMPC_OPTIMIZER, add_bridges= false ),
225230 kwargs...
226231)
227232 estim = SteadyKalmanFilter (model; kwargs... )
228- NonLinMPC (estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, M_Hp, N_Hc, L_Hp, optim)
233+ NonLinMPC (estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, p, M_Hp, N_Hc, L_Hp, optim)
229234end
230235
231236
@@ -265,14 +270,17 @@ function NonLinMPC(
265270 Cwt = DEFAULT_CWT,
266271 Ewt = DEFAULT_EWT,
267272 JE:: JEFunc = (_,_,_) -> 0.0 ,
273+ p:: P = estim. model. p,
268274 optim:: JM = JuMP. Model (DEFAULT_NONLINMPC_OPTIMIZER, add_bridges= false ),
269- ) where {NT<: Real , SE<: StateEstimator{NT} , JM<: JuMP.GenericModel , JEFunc<: Function }
275+ ) where {NT<: Real , SE<: StateEstimator{NT} , JM<: JuMP.GenericModel , JEFunc<: Function , P <: Any }
270276 nk = estimate_delays (estim. model)
271277 if Hp ≤ nk
272278 @warn (" prediction horizon Hp ($Hp ) ≤ estimated number of delays in model " *
273279 " ($nk ), the closed-loop system may be unstable or zero-gain (unresponsive)" )
274280 end
275- return NonLinMPC {NT, SE, JM, JEFunc} (estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, optim)
281+ return NonLinMPC {NT, SE, JM, JEFunc, P} (
282+ estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, p, optim
283+ )
276284end
277285
278286"""
@@ -285,7 +293,7 @@ function addinfo!(info, mpc::NonLinMPC)
285293 UE = [U; U[(end - mpc. estim. model. nu + 1 ): end ]]
286294 ŶE = [ŷ; Ŷ]
287295 D̂E = [d; D̂]
288- info[:JE ] = mpc. JE (UE, ŶE, D̂E)
296+ info[:JE ] = mpc. JE (UE, ŶE, D̂E, mpc . p )
289297 info[:sol ] = JuMP. solution_summary (mpc. optim, verbose= true )
290298 return info
291299end
@@ -457,4 +465,22 @@ function con_nonlinprog!(g, mpc::NonLinMPC, ::SimModel, x̂0end, Ŷ0, ΔŨ)
457465end
458466
459467" No nonlinear constraints if `model` is a [`LinModel`](@ref), return `g` unchanged."
460- con_nonlinprog! (g, :: NonLinMPC , :: LinModel , _ , _ , _ ) = g
468+ con_nonlinprog! (g, :: NonLinMPC , :: LinModel , _ , _ , _ ) = g
469+
470+ " Evaluate the economic term of the objective function for [`NonLinMPC`](@ref)."
471+ function obj_econ! (U0, Ȳ, mpc:: NonLinMPC , model:: SimModel , Ŷ0, ΔŨ)
472+ if ! iszero (mpc. E)
473+ ny, Hp, ŷ, D̂E = model. ny, mpc. Hp, mpc. ŷ, mpc. D̂E
474+ U = U0
475+ U .+ = mpc. Uop
476+ uend = @views U[(end - model. nu+ 1 ): end ]
477+ Ŷ = Ȳ
478+ Ŷ .= Ŷ0 .+ mpc. Yop
479+ UE = [U; uend]
480+ ŶE = [ŷ; Ŷ]
481+ E_JE = mpc. E* mpc. JE (UE, ŶE, D̂E, mpc. p)
482+ else
483+ E_JE = 0.0
484+ end
485+ return E_JE
486+ end
0 commit comments