Skip to content

Commit 780cdbf

Browse files
authored
Merge pull request #16 from franckgaga/terminal
Added : terminal constraints
2 parents b7929f1 + 4b435d0 commit 780cdbf

File tree

10 files changed

+488
-253
lines changed

10 files changed

+488
-253
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.9.1"
4+
version = "0.10.0"
55

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

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ for more detailed examples.
8383
- [x] move suppression
8484
- [x] input setpoint tracking
8585
- [x] economic costs (economic model predictive control)
86-
- [ ] terminal cost to ensure nominal stability
8786
- [x] explicit predictive controller for problems without constraint
8887
- [x] soft and hard constraints on:
8988
- [x] output predictions
9089
- [x] manipulated inputs
9190
- [x] manipulated inputs increments
91+
- [x] terminal states to ensure nominal stability
9292
- [ ] custom manipulated input constraints that are a function of the predictions
9393
- [x] supported feedback strategy:
9494
- [x] state estimator (see State Estimation features)

docs/src/manual/linmpc.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ These are the integrating states for the unmeasured plant disturbances, and they
8484
automatically added to the model outputs by default if feasible (see [`SteadyKalmanFilter`](@ref)
8585
for details).
8686

87-
[^1]: To avoid observer design, we could have use an [`InternalModel`](@ref) structure with
88-
`mpc = LinMPC(InternalModel(model), Hp=15, Hc=2, Mwt=[1, 1], Nwt=[0.1, 0.1])` . It was
87+
[^1]: As an alternative to state observer, we could have use an [`InternalModel`](@ref)
88+
structure with `mpc = LinMPC(InternalModel(model), Hp=15, Hc=2, Mwt=[1, 1], Nwt=[0.1, 0.1])` . It was
8989
tested on the example of this page and it gives similar results.
9090

9191
Before closing the loop, we call [`initstate!`](@ref) with the actual plant inputs and

src/controller/explicitmpc.jl

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ struct ExplicitMPC{SE<:StateEstimator} <: PredictiveController
1919
G::Matrix{Float64}
2020
J::Matrix{Float64}
2121
K::Matrix{Float64}
22-
Q::Matrix{Float64}
22+
V::Matrix{Float64}
23+
ẽx̂::Matrix{Float64}
24+
fx̂::Vector{Float64}
25+
gx̂::Matrix{Float64}
26+
jx̂::Matrix{Float64}
27+
kx̂::Matrix{Float64}
28+
vx̂::Matrix{Float64}
2329
::Hermitian{Float64, Matrix{Float64}}
2430
::Vector{Float64}
2531
p::Vector{Float64}
@@ -44,8 +50,8 @@ struct ExplicitMPC{SE<:StateEstimator} <: PredictiveController
4450
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
4551
noR̂u = iszero(L_Hp)
4652
S, T = init_ΔUtoU(nu, Hp, Hc)
47-
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
48-
_ , S̃, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
53+
E, F, G, J, K, V, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂ = init_predmat(estim, model, Hp, Hc)
54+
S̃, Ñ_Hc, Ẽ, ẽx̂ = S, N_Hc, E, ex̂ # no slack variable ϵ for ExplicitMPC
4955
P̃, q̃, p = init_quadprog(model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
5056
P̃_chol = cholesky(P̃)
5157
Ks, Ps = init_stochpred(estim, Hp)
@@ -59,7 +65,7 @@ struct ExplicitMPC{SE<:StateEstimator} <: PredictiveController
5965
Hp, Hc,
6066
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
6167
S̃, T,
62-
Ẽ, F, G, J, K, Q, P̃, q̃, p,
68+
Ẽ, F, G, J, K, V, ẽx̂, fx̂, gx̂, jx̂, kx̂, vx̂, P̃, q̃, p,
6369
P̃_chol,
6470
Ks, Ps,
6571
d0, D̂0,
@@ -155,15 +161,7 @@ function ExplicitMPC(
155161
Lwt = fill(DEFAULT_LWT, estim.model.nu)
156162
) where {SE<:StateEstimator}
157163
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
158-
poles = eigvals(estim.model.A)
159-
nk = sum(poles .≈ 0)
160-
if isnothing(Hp)
161-
Hp = DEFAULT_HP + nk
162-
end
163-
if Hp nk
164-
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
165-
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
166-
end
164+
Hp = default_Hp(estim.model, Hp)
167165
return ExplicitMPC{SE}(estim, Hp, Hc, Mwt, Nwt, Lwt)
168166
end
169167

src/controller/linmpc.jl

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ struct LinMPC{SE<:StateEstimator} <: PredictiveController
2121
G::Matrix{Float64}
2222
J::Matrix{Float64}
2323
K::Matrix{Float64}
24-
Q::Matrix{Float64}
24+
V::Matrix{Float64}
25+
ẽx̂::Matrix{Float64}
26+
fx̂::Vector{Float64}
27+
gx̂::Matrix{Float64}
28+
jx̂::Matrix{Float64}
29+
kx̂::Matrix{Float64}
30+
vx̂::Matrix{Float64}
2531
::Hermitian{Float64, Matrix{Float64}}
2632
::Vector{Float64}
2733
p::Vector{Float64}
@@ -44,8 +50,8 @@ struct LinMPC{SE<:StateEstimator} <: PredictiveController
4450
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
4551
noR̂u = iszero(L_Hp)
4652
S, T = init_ΔUtoU(nu, Hp, Hc)
47-
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
48-
con, S̃, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
53+
E, F, G, J, K, V, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂ = init_predmat(estim, model, Hp, Hc)
54+
con, S̃, Ñ_Hc, Ẽ, ẽx̂ = init_defaultcon(estim, Hp, Hc, C, S, N_Hc, E, ex̂)
4955
P̃, q̃, p = init_quadprog(model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
5056
Ks, Ps = init_stochpred(estim, Hp)
5157
d0, D̂0 = zeros(nd), zeros(nd*Hp)
@@ -58,7 +64,7 @@ struct LinMPC{SE<:StateEstimator} <: PredictiveController
5864
Hp, Hc,
5965
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
6066
S̃, T,
61-
Ẽ, F, G, J, K, Q, P̃, q̃, p,
67+
Ẽ, F, G, J, K, V, ẽx̂, fx̂, gx̂, jx̂, kx̂, vx̂, P̃, q̃, p,
6268
Ks, Ps,
6369
d0, D̂0,
6470
Ŷop, Dop,
@@ -187,7 +193,7 @@ LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, KalmanFilter es
187193
"""
188194
function LinMPC(
189195
estim::SE;
190-
Hp::Union{Int, Nothing} = DEFAULT_HP,
196+
Hp::Union{Int, Nothing} = nothing,
191197
Hc::Int = DEFAULT_HC,
192198
Mwt = fill(DEFAULT_MWT, estim.model.ny),
193199
Nwt = fill(DEFAULT_NWT, estim.model.nu),
@@ -196,15 +202,7 @@ function LinMPC(
196202
optim::JuMP.Model = JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer)
197203
) where {SE<:StateEstimator}
198204
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
199-
poles = eigvals(estim.model.A)
200-
nk = sum(poles .≈ 0)
201-
if isnothing(Hp)
202-
Hp = DEFAULT_HP + nk
203-
end
204-
if Hp nk
205-
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
206-
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
207-
end
205+
Hp = default_Hp(estim.model, Hp)
208206
return LinMPC{SE}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim)
209207
end
210208

src/controller/nonlinmpc.jl

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
2424
G::Matrix{Float64}
2525
J::Matrix{Float64}
2626
K::Matrix{Float64}
27-
Q::Matrix{Float64}
27+
V::Matrix{Float64}
28+
ẽx̂::Matrix{Float64}
29+
fx̂::Vector{Float64}
30+
gx̂::Matrix{Float64}
31+
jx̂::Matrix{Float64}
32+
kx̂::Matrix{Float64}
33+
vx̂::Matrix{Float64}
2834
::Hermitian{Float64, Matrix{Float64}}
2935
::Vector{Float64}
3036
p::Vector{Float64}
@@ -48,8 +54,8 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
4854
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
4955
noR̂u = iszero(L_Hp)
5056
S, T = init_ΔUtoU(nu, Hp, Hc)
51-
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
52-
con, S̃, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
57+
E, F, G, J, K, V, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂ = init_predmat(estim, model, Hp, Hc)
58+
con, S̃, Ñ_Hc, Ẽ, ẽx̂ = init_defaultcon(estim, Hp, Hc, C, S, N_Hc, E, ex̂)
5359
P̃, q̃, p = init_quadprog(model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
5460
Ks, Ps = init_stochpred(estim, Hp)
5561
d0, D̂0 = zeros(nd), zeros(nd*Hp)
@@ -62,7 +68,7 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
6268
Hp, Hc,
6369
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, JE, R̂u, R̂y, noR̂u,
6470
S̃, T,
65-
Ẽ, F, G, J, K, Q, P̃, q̃, p,
71+
Ẽ, F, G, J, K, V, ẽx̂, fx̂, gx̂, jx̂, kx̂, vx̂, P̃, q̃, p,
6672
Ks, Ps,
6773
d0, D̂0,
6874
Ŷop, Dop,
@@ -113,7 +119,7 @@ This method uses the default state estimator :
113119
114120
# Arguments
115121
- `model::SimModel` : model used for controller predictions and state estimations.
116-
- `Hp=10`: prediction horizon ``H_p``.
122+
- `Hp=nothing`: prediction horizon ``H_p``, must be specified for [`NonLinModel`](@ref).
117123
- `Hc=2` : control horizon ``H_c``.
118124
- `Mwt=fill(1.0,model.ny)` : main diagonal of ``\mathbf{M}`` weight matrix (vector).
119125
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\mathbf{N}`` weight matrix (vector).
@@ -155,7 +161,7 @@ for common mistakes when writing these functions.
155161
"""
156162
function NonLinMPC(
157163
model::SimModel;
158-
Hp::Int = DEFAULT_HP,
164+
Hp::Union{Int, Nothing} = nothing,
159165
Hc::Int = DEFAULT_HC,
160166
Mwt = fill(DEFAULT_MWT, model.ny),
161167
Nwt = fill(DEFAULT_NWT, model.nu),
@@ -169,9 +175,10 @@ function NonLinMPC(
169175
estim = UnscentedKalmanFilter(model; kwargs...)
170176
NonLinMPC(estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
171177
end
178+
172179
function NonLinMPC(
173180
model::LinModel;
174-
Hp::Int = DEFAULT_HP,
181+
Hp::Union{Int, Nothing} = nothing,
175182
Hc::Int = DEFAULT_HC,
176183
Mwt = fill(DEFAULT_MWT, model.ny),
177184
Nwt = fill(DEFAULT_NWT, model.nu),
@@ -211,7 +218,7 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
211218
"""
212219
function NonLinMPC(
213220
estim::SE;
214-
Hp::Int = DEFAULT_HP,
221+
Hp::Union{Int, Nothing} = nothing,
215222
Hc::Int = DEFAULT_HC,
216223
Mwt = fill(DEFAULT_MWT, estim.model.ny),
217224
Nwt = fill(DEFAULT_NWT, estim.model.nu),
@@ -221,6 +228,7 @@ function NonLinMPC(
221228
JE::JEFunc = (_,_,_) -> 0.0,
222229
optim::JuMP.Model = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"))
223230
) where {SE<:StateEstimator, JEFunc<:Function}
231+
Hp = default_Hp(estim.model, Hp)
224232
return NonLinMPC{SE, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
225233
end
226234

@@ -256,20 +264,22 @@ function init_optimization!(mpc::NonLinMPC)
256264
@constraint(optim, linconstraint, A*ΔŨvar .≤ b)
257265
# --- nonlinear optimization init ---
258266
model = mpc.estim.model
259-
ny, nu, Hp, Hc = model.ny, model.nu, mpc.Hp, mpc.Hc
260-
nC = (2*Hp*nu + 2*nvar + 2*Hp*ny) - length(mpc.con.b)
267+
ny, nu, nx̂, Hp = model.ny, model.nu, mpc.estim.nx̂, mpc.Hp
268+
nC = (2*Hp*nu + 2*nvar + 2*Hp*ny + 2*nx̂) - length(mpc.con.b)
261269
# inspired from https://jump.dev/JuMP.jl/stable/tutorials/nonlinear/tips_and_tricks/#User-defined-operators-with-vector-outputs
262-
Jfunc, Cfunc = let mpc=mpc, model=model, nC=nC, nvar=nvar , nŶ=Hp*ny
270+
Jfunc, Cfunc = let mpc=mpc, model=model, nC=nC, nvar=nvar , nŶ=Hp*ny, nx̂=nx̂
263271
last_ΔŨtup_float, last_ΔŨtup_dual = nothing, nothing
264272
Ŷ_cache::DiffCacheType = DiffCache(zeros(nŶ), nvar + 3)
265273
C_cache::DiffCacheType = DiffCache(zeros(nC), nvar + 3)
274+
x̂_cache::DiffCacheType = DiffCache(zeros(nx̂), nvar + 3)
266275
function Jfunc(ΔŨtup::Float64...)
267276
= get_tmp(Ŷ_cache, ΔŨtup[1])
268277
ΔŨ = collect(ΔŨtup)
269278
if ΔŨtup != last_ΔŨtup_float
279+
= get_tmp(x̂_cache, ΔŨtup[1])
270280
C = get_tmp(C_cache, ΔŨtup[1])
271-
predict!(Ŷ, mpc, model, ΔŨ)
272-
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
281+
Ŷ, x̂end = predict!(Ŷ, x̂, mpc, model, ΔŨ)
282+
con_nonlinprog!(C, mpc, model, end, Ŷ, ΔŨ)
273283
last_ΔŨtup_float = ΔŨtup
274284
end
275285
return obj_nonlinprog(mpc, model, Ŷ, ΔŨ)
@@ -278,31 +288,34 @@ function init_optimization!(mpc::NonLinMPC)
278288
= get_tmp(Ŷ_cache, ΔŨtup[1])
279289
ΔŨ = collect(ΔŨtup)
280290
if ΔŨtup != last_ΔŨtup_dual
291+
= get_tmp(x̂_cache, ΔŨtup[1])
281292
C = get_tmp(C_cache, ΔŨtup[1])
282-
predict!(Ŷ, mpc, model, ΔŨ)
283-
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
293+
Ŷ, x̂end = predict!(Ŷ, x̂, mpc, model, ΔŨ)
294+
con_nonlinprog!(C, mpc, model, end, Ŷ, ΔŨ)
284295
last_ΔŨtup_dual = ΔŨtup
285296
end
286297
return obj_nonlinprog(mpc, model, Ŷ, ΔŨ)
287298
end
288299
function con_nonlinprog_i(i, ΔŨtup::NTuple{N, Float64}) where {N}
289300
C = get_tmp(C_cache, ΔŨtup[1])
290301
if ΔŨtup != last_ΔŨtup_float
302+
= get_tmp(x̂_cache, ΔŨtup[1])
291303
= get_tmp(Ŷ_cache, ΔŨtup[1])
292304
ΔŨ = collect(ΔŨtup)
293-
predict!(Ŷ, mpc, model, ΔŨ)
294-
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
305+
Ŷ, x̂end = predict!(Ŷ, x̂, mpc, model, ΔŨ)
306+
C = con_nonlinprog!(C, mpc, model, x̂end, Ŷ, ΔŨ)
295307
last_ΔŨtup_float = ΔŨtup
296308
end
297309
return C[i]
298310
end
299311
function con_nonlinprog_i(i, ΔŨtup::NTuple{N, Real}) where {N}
300312
C = get_tmp(C_cache, ΔŨtup[1])
301313
if ΔŨtup != last_ΔŨtup_dual
314+
= get_tmp(x̂_cache, ΔŨtup[1])
302315
= get_tmp(Ŷ_cache, ΔŨtup[1])
303316
ΔŨ = collect(ΔŨtup)
304-
predict!(Ŷ, mpc, model, ΔŨ)
305-
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
317+
Ŷ, x̂end = predict!(Ŷ, x̂, mpc, model, ΔŨ)
318+
C = con_nonlinprog!(C, mpc, model, x̂end, Ŷ, ΔŨ)
306319
last_ΔŨtup_dual = ΔŨtup
307320
end
308321
return C[i]
@@ -313,15 +326,22 @@ function init_optimization!(mpc::NonLinMPC)
313326
register(optim, :Jfunc, nvar, Jfunc, autodiff=true)
314327
@NLobjective(optim, Min, Jfunc(ΔŨvar...))
315328
if nC 0
316-
n = 0
329+
i_end_Ymin, i_end_Ymax, i_end_x̂min = 1Hp*ny, 2Hp*ny, 2Hp*ny + nx̂
317330
for i in eachindex(con.Ymin)
318331
sym = Symbol("C_Ymin_$i")
319-
register(optim, sym, nvar, Cfunc[n + i], autodiff=true)
332+
register(optim, sym, nvar, Cfunc[i], autodiff=true)
320333
end
321-
n = lastindex(con.Ymin)
322334
for i in eachindex(con.Ymax)
323335
sym = Symbol("C_Ymax_$i")
324-
register(optim, sym, nvar, Cfunc[n + i], autodiff=true)
336+
register(optim, sym, nvar, Cfunc[i_end_Ymin+i], autodiff=true)
337+
end
338+
for i in eachindex(con.x̂min)
339+
sym = Symbol("C_x̂min_$i")
340+
register(optim, sym, nvar, Cfunc[i_end_Ymax+i], autodiff=true)
341+
end
342+
for i in eachindex(con.x̂max)
343+
sym = Symbol("C_x̂max_$i")
344+
register(optim, sym, nvar, Cfunc[i_end_x̂min+i], autodiff=true)
325345
end
326346
end
327347
return nothing
@@ -345,27 +365,41 @@ function setnonlincon!(mpc::NonLinMPC, ::NonLinModel)
345365
f_sym = Symbol("C_Ymax_$(i)")
346366
add_nonlinear_constraint(optim, :($(f_sym)($(ΔŨvar...)) <= 0))
347367
end
368+
for i in findall(.!isinf.(con.x̂min))
369+
f_sym = Symbol("C_x̂min_$(i)")
370+
add_nonlinear_constraint(optim, :($(f_sym)($(ΔŨvar...)) <= 0))
371+
end
372+
for i in findall(.!isinf.(con.x̂max))
373+
f_sym = Symbol("C_x̂max_$(i)")
374+
add_nonlinear_constraint(optim, :($(f_sym)($(ΔŨvar...)) <= 0))
375+
end
348376
return nothing
349377
end
350378

351379
"""
352-
con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, ΔŨ)
380+
con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, x̂end, Ŷ, ΔŨ)
353381
354382
Nonlinear constrains for [`NonLinMPC`](@ref) when `model` is not a [`LinModel`](@ref).
355383
"""
356-
function con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, Ŷ, ΔŨ)
357-
ny, Hp = model.ny, mpc.Hp
384+
function con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, x̂end, Ŷ, ΔŨ)
385+
ny, nx̂, Hp = model.ny, mpc.estim.nx̂, mpc.Hp
386+
i_end_Ymin, i_end_Ymax = 1Hp*ny , 2Hp*ny
387+
i_end_x̂min, i_end_x̂max = 2Hp*ny + 1nx̂, 2Hp*ny + 2nx̂
358388
if !isinf(mpc.C) # constraint softening activated :
359389
ϵ = ΔŨ[end]
360-
C[begin:(Hp*ny)] = (mpc.con.Ymin - Ŷ) - ϵ*mpc.con.c_Ymin
361-
C[(Hp*ny+1):end] = (Ŷ - mpc.con.Ymax) - ϵ*mpc.con.c_Ymax
390+
C[ 1:i_end_Ymin] = (mpc.con.Ymin - Ŷ) - ϵ*mpc.con.c_Ymin
391+
C[i_end_Ymin+1:i_end_Ymax] = (Ŷ - mpc.con.Ymax) - ϵ*mpc.con.c_Ymax
392+
C[i_end_Ymax+1:i_end_x̂min] = (mpc.con.x̂min -end) - ϵ*mpc.con.c_x̂min
393+
C[i_end_x̂min+1:i_end_x̂max] = (x̂end - mpc.con.x̂max) - ϵ*mpc.con.c_x̂max
362394
else # no constraint softening :
363-
C[begin:(Hp*ny)] = (mpc.con.Ymin - Ŷ)
364-
C[(Hp*ny+1):end] = (Ŷ - mpc.con.Ymax)
395+
C[ 1:i_end_Ymin] = mpc.con.Ymin -
396+
C[i_end_Ymin+1:i_end_Ymax] =- mpc.con.Ymax
397+
C[i_end_Ymax+1:i_end_x̂min] = mpc.con.x̂min -end
398+
C[i_end_x̂min+1:i_end_x̂max] =end - mpc.con.x̂max
365399
end
366400
C[isinf.(C)] .= 0 # replace ±Inf with 0 to avoid INVALID_MODEL error
367401
return C
368402
end
369403

370404
"No nonlinear constraints if `model` is a [`LinModel`](@ref), return `C` unchanged."
371-
con_nonlinprog!(C, ::NonLinMPC, ::LinModel, _ , _ ) = C
405+
con_nonlinprog!(C, ::NonLinMPC, ::LinModel, _ , _ , _ ) = C

0 commit comments

Comments
 (0)