@@ -24,7 +24,13 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
24
24
G:: Matrix{Float64}
25
25
J:: Matrix{Float64}
26
26
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}
28
34
P̃:: Hermitian{Float64, Matrix{Float64}}
29
35
q̃:: Vector{Float64}
30
36
p:: Vector{Float64}
@@ -48,8 +54,8 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
48
54
R̂y, R̂u = zeros (ny* Hp), zeros (nu* Hp) # dummy vals (updated just before optimization)
49
55
noR̂u = iszero (L_Hp)
50
56
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̂ )
53
59
P̃, q̃, p = init_quadprog (model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
54
60
Ks, Ps = init_stochpred (estim, Hp)
55
61
d0, D̂0 = zeros (nd), zeros (nd* Hp)
@@ -62,7 +68,7 @@ struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
62
68
Hp, Hc,
63
69
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, JE, R̂u, R̂y, noR̂u,
64
70
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,
66
72
Ks, Ps,
67
73
d0, D̂0,
68
74
Ŷop, Dop,
@@ -113,7 +119,7 @@ This method uses the default state estimator :
113
119
114
120
# Arguments
115
121
- `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) .
117
123
- `Hc=2` : control horizon ``H_c``.
118
124
- `Mwt=fill(1.0,model.ny)` : main diagonal of ``\m athbf{M}`` weight matrix (vector).
119
125
- `Nwt=fill(0.1,model.nu)` : main diagonal of ``\m athbf{N}`` weight matrix (vector).
@@ -155,7 +161,7 @@ for common mistakes when writing these functions.
155
161
"""
156
162
function NonLinMPC (
157
163
model:: SimModel ;
158
- Hp:: Int = DEFAULT_HP ,
164
+ Hp:: Union{ Int, Nothing} = nothing ,
159
165
Hc:: Int = DEFAULT_HC,
160
166
Mwt = fill (DEFAULT_MWT, model. ny),
161
167
Nwt = fill (DEFAULT_NWT, model. nu),
@@ -169,9 +175,10 @@ function NonLinMPC(
169
175
estim = UnscentedKalmanFilter (model; kwargs... )
170
176
NonLinMPC (estim; Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
171
177
end
178
+
172
179
function NonLinMPC (
173
180
model:: LinModel ;
174
- Hp:: Int = DEFAULT_HP ,
181
+ Hp:: Union{ Int, Nothing} = nothing ,
175
182
Hc:: Int = DEFAULT_HC,
176
183
Mwt = fill (DEFAULT_MWT, model. ny),
177
184
Nwt = fill (DEFAULT_NWT, model. nu),
@@ -211,7 +218,7 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
211
218
"""
212
219
function NonLinMPC (
213
220
estim:: SE ;
214
- Hp:: Int = DEFAULT_HP ,
221
+ Hp:: Union{ Int, Nothing} = nothing ,
215
222
Hc:: Int = DEFAULT_HC,
216
223
Mwt = fill (DEFAULT_MWT, estim. model. ny),
217
224
Nwt = fill (DEFAULT_NWT, estim. model. nu),
@@ -221,6 +228,7 @@ function NonLinMPC(
221
228
JE:: JEFunc = (_,_,_) -> 0.0 ,
222
229
optim:: JuMP.Model = JuMP. Model (optimizer_with_attributes (Ipopt. Optimizer," sb" => " yes" ))
223
230
) where {SE<: StateEstimator , JEFunc<: Function }
231
+ Hp = default_Hp (estim. model, Hp)
224
232
return NonLinMPC {SE, JEFunc} (estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
225
233
end
226
234
@@ -256,20 +264,22 @@ function init_optimization!(mpc::NonLinMPC)
256
264
@constraint (optim, linconstraint, A* ΔŨvar .≤ b)
257
265
# --- nonlinear optimization init ---
258
266
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)
261
269
# 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̂
263
271
last_ΔŨtup_float, last_ΔŨtup_dual = nothing , nothing
264
272
Ŷ_cache:: DiffCacheType = DiffCache (zeros (nŶ), nvar + 3 )
265
273
C_cache:: DiffCacheType = DiffCache (zeros (nC), nvar + 3 )
274
+ x̂_cache:: DiffCacheType = DiffCache (zeros (nx̂), nvar + 3 )
266
275
function Jfunc (ΔŨtup:: Float64... )
267
276
Ŷ = get_tmp (Ŷ_cache, ΔŨtup[1 ])
268
277
ΔŨ = collect (ΔŨtup)
269
278
if ΔŨtup != last_ΔŨtup_float
279
+ x̂ = get_tmp (x̂_cache, ΔŨtup[1 ])
270
280
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, x̂ end , Ŷ, ΔŨ)
273
283
last_ΔŨtup_float = ΔŨtup
274
284
end
275
285
return obj_nonlinprog (mpc, model, Ŷ, ΔŨ)
@@ -278,31 +288,34 @@ function init_optimization!(mpc::NonLinMPC)
278
288
Ŷ = get_tmp (Ŷ_cache, ΔŨtup[1 ])
279
289
ΔŨ = collect (ΔŨtup)
280
290
if ΔŨtup != last_ΔŨtup_dual
291
+ x̂ = get_tmp (x̂_cache, ΔŨtup[1 ])
281
292
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, x̂ end , Ŷ, ΔŨ)
284
295
last_ΔŨtup_dual = ΔŨtup
285
296
end
286
297
return obj_nonlinprog (mpc, model, Ŷ, ΔŨ)
287
298
end
288
299
function con_nonlinprog_i (i, ΔŨtup:: NTuple{N, Float64} ) where {N}
289
300
C = get_tmp (C_cache, ΔŨtup[1 ])
290
301
if ΔŨtup != last_ΔŨtup_float
302
+ x̂ = get_tmp (x̂_cache, ΔŨtup[1 ])
291
303
Ŷ = get_tmp (Ŷ_cache, ΔŨtup[1 ])
292
304
ΔŨ = 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 , Ŷ, ΔŨ)
295
307
last_ΔŨtup_float = ΔŨtup
296
308
end
297
309
return C[i]
298
310
end
299
311
function con_nonlinprog_i (i, ΔŨtup:: NTuple{N, Real} ) where {N}
300
312
C = get_tmp (C_cache, ΔŨtup[1 ])
301
313
if ΔŨtup != last_ΔŨtup_dual
314
+ x̂ = get_tmp (x̂_cache, ΔŨtup[1 ])
302
315
Ŷ = get_tmp (Ŷ_cache, ΔŨtup[1 ])
303
316
ΔŨ = 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 , Ŷ, ΔŨ)
306
319
last_ΔŨtup_dual = ΔŨtup
307
320
end
308
321
return C[i]
@@ -313,15 +326,22 @@ function init_optimization!(mpc::NonLinMPC)
313
326
register (optim, :Jfunc , nvar, Jfunc, autodiff= true )
314
327
@NLobjective (optim, Min, Jfunc (ΔŨvar... ))
315
328
if nC ≠ 0
316
- n = 0
329
+ i_end_Ymin, i_end_Ymax, i_end_x̂min = 1 Hp * ny, 2 Hp * ny, 2 Hp * ny + nx̂
317
330
for i in eachindex (con. Ymin)
318
331
sym = Symbol (" C_Ymin_$i " )
319
- register (optim, sym, nvar, Cfunc[n + i], autodiff= true )
332
+ register (optim, sym, nvar, Cfunc[i], autodiff= true )
320
333
end
321
- n = lastindex (con. Ymin)
322
334
for i in eachindex (con. Ymax)
323
335
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 )
325
345
end
326
346
end
327
347
return nothing
@@ -345,27 +365,41 @@ function setnonlincon!(mpc::NonLinMPC, ::NonLinModel)
345
365
f_sym = Symbol (" C_Ymax_$(i) " )
346
366
add_nonlinear_constraint (optim, :($ (f_sym)($ (ΔŨvar... )) <= 0 ))
347
367
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
348
376
return nothing
349
377
end
350
378
351
379
"""
352
- con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, ΔŨ)
380
+ con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, x̂end, Ŷ, ΔŨ)
353
381
354
382
Nonlinear constrains for [`NonLinMPC`](@ref) when `model` is not a [`LinModel`](@ref).
355
383
"""
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 = 1 Hp* ny , 2 Hp* ny
387
+ i_end_x̂min, i_end_x̂max = 2 Hp* ny + 1 nx̂, 2 Hp* ny + 2 nx̂
358
388
if ! isinf (mpc. C) # constraint softening activated :
359
389
ϵ = ΔŨ[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 - x̂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
362
394
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 - x̂end
398
+ C[i_end_x̂min+ 1 : i_end_x̂max] = x̂end - mpc. con. x̂max
365
399
end
366
400
C[isinf .(C)] .= 0 # replace ±Inf with 0 to avoid INVALID_MODEL error
367
401
return C
368
402
end
369
403
370
404
" 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