@@ -80,10 +80,13 @@ struct NonLinMPC{S<:StateEstimator, JEFunc<:Function} <: PredictiveController
80
80
nonlinconstraint = let mpc= mpc, model= model # capture mpc and model variables
81
81
(ΔŨ... ) -> con_nonlinprog (mpc, model, ΔŨ)
82
82
end
83
- register (mpc. optim, :nonlinconstraint , nvar, nonlinconstraint, autodiff= true )
84
- ncon = sum (con. i_Ŷmin) + sum (con. i_Ŷmax)
85
- @NLconstraint (mpc. optim, [i= 1 : ncon], nonlinconstraint (ΔŨ... ) ≤ zeros (ncon))
86
-
83
+ nonlincon_memoized = memoize (nonlinconstraint, 2 * ny* Hp)
84
+ for i= 1 : ny* Hp
85
+ register (mpc. optim, Symbol (" C_Ŷmin_$(i) " ), nvar, nonlincon_memoized[i], autodiff= true )
86
+ end
87
+ for i= 1 : ny* Hp
88
+ register (mpc. optim, Symbol (" C_Ŷmax_$(i) " ), nvar, nonlincon_memoized[ny* Hp+ i], autodiff= true )
89
+ end
87
90
set_silent (optim)
88
91
return mpc
89
92
end
@@ -193,6 +196,23 @@ function NonLinMPC(
193
196
return NonLinMPC {S, JEFunc} (estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, ru, optim)
194
197
end
195
198
199
+ setnontlincon! (mpc:: NonLinMPC , model:: LinModel ) = nothing
200
+
201
+ function setnonlincon! (mpc:: NonLinMPC , model:: NonLinModel )
202
+ optim = mpc. optim
203
+ ΔŨ = mpc. optim[:ΔŨ ]
204
+ con = mpc. con
205
+ map (con -> delete (optim, con), all_nonlinear_constraints (optim))
206
+ for i in findall (con. i_Ŷmin)
207
+ f_sym = Symbol (" C_Ŷmin_$(i) " )
208
+ add_nonlinear_constraint (optim, :($ (f_sym)($ (ΔŨ... )) <= 0 ))
209
+ end
210
+ for i in findall (con. i_Ŷmax)
211
+ f_sym = Symbol (" C_Ŷmax_$(i) " )
212
+ add_nonlinear_constraint (optim, :($ (f_sym)($ (ΔŨ... )) <= 0 ))
213
+ end
214
+ return nothing
215
+ end
196
216
197
217
init_objective! (mpc:: NonLinMPC , _ ) = nothing
198
218
@@ -236,11 +256,12 @@ function con_nonlinprog(mpc::NonLinMPC, model::SimModel, ΔŨ::NTuple{N, T}) wh
236
256
ΔŨ = collect (ΔŨ) # convert NTuple to Vector
237
257
U0 = mpc. S̃_Hp* ΔŨ + mpc. T_Hp* (mpc. estim. lastu0)
238
258
Ŷ = evalŶ (mpc, model, mpc. x̂d, mpc. d0, mpc. D̂0, U0)
239
- C_Ŷmin = (mpc. con. Ŷmin - Ŷ)[mpc . con . i_Ŷmin]
240
- C_Ŷmax = (Ŷ - mpc. con. Ŷmax)[mpc . con . i_Ŷmin]
259
+ C_Ŷmin = (mpc. con. Ŷmin - Ŷ)
260
+ C_Ŷmax = (Ŷ - mpc. con. Ŷmax)
241
261
if ! isinf (mpc. C) # constraint softening activated :
242
- C_Ŷmin = C_Ŷmin - ΔŨ[end ]* mpc. con. c_Ŷmin[mpc. con. i_Ŷmin]
243
- C_Ŷmax = C_Ŷmax - ΔŨ[end ]* mpc. con. c_Ŷmin[mpc. con. i_Ŷmin]
262
+ ϵ = ΔŨ[end ]
263
+ C_Ŷmin = C_Ŷmin - ϵ* mpc. con. c_Ŷmin
264
+ C_Ŷmax = C_Ŷmax - ϵ* mpc. con. c_Ŷmin
244
265
end
245
266
C = [C_Ŷmin; C_Ŷmax]
246
267
return C
@@ -258,3 +279,32 @@ function evalŶ(mpc, model, x̂d, d0, D̂0, U0::Vector{T}) where {T}
258
279
return Ŷd0 + mpc. F
259
280
end
260
281
282
+ """
283
+ memoize(myfunc::Function, n_outputs::Int)
284
+
285
+ Take a function `myfunc` and return a vector of length `n_outputs`, where element
286
+ `i` is a function that returns the equivalent of `myfunc(x...)[i]`.
287
+
288
+ To avoid duplication of work, cache the most-recent evaluations of `myfunc`.
289
+ Because `myfunc_i` is auto-differentiated with ForwardDiff, our cache needs to
290
+ work when `x` is a `Float64` and a `ForwardDiff.Dual`.
291
+ """
292
+ function memoize (f:: Function , n_outputs:: Int )
293
+ last_ΔŨ , last_f = nothing , nothing
294
+ function f_i (i, ΔŨ:: Float64... )
295
+ if ΔŨ != = last_ΔŨ
296
+ last_f = f (ΔŨ... )
297
+ last_ΔŨ = ΔŨ
298
+ end
299
+ return last_f[i]
300
+ end
301
+ last_dΔŨ, last_dfdΔŨ = nothing , nothing
302
+ function f_i (i, dΔŨ:: T... ) where {T<: Real }
303
+ if dΔŨ != = last_dΔŨ
304
+ last_dfdΔŨ = f (dΔŨ... )
305
+ last_dΔŨ = dΔŨ
306
+ end
307
+ return last_dfdΔŨ[i]
308
+ end
309
+ return [(x... ) -> f_i (i, x... ) for i in 1 : n_outputs]
310
+ end
0 commit comments