Skip to content

Commit 708456b

Browse files
committed
Merge branch 'main' into diff_interface_final
2 parents 361da2b + b84d375 commit 708456b

File tree

9 files changed

+343
-223
lines changed

9 files changed

+343
-223
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 = "1.4.2"
4+
version = "1.4.3"
55

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

docs/src/internals/predictive_control.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ModelPredictiveControl.init_nonlincon!
3030

3131
```@docs
3232
ModelPredictiveControl.initpred!(::PredictiveController, ::LinModel, ::Any, ::Any, ::Any, ::Any)
33-
ModelPredictiveControl.linconstraint!(::PredictiveController, ::LinModel)
33+
ModelPredictiveControl.linconstraint!(::PredictiveController, ::LinModel, ::TranscriptionMethod)
3434
ModelPredictiveControl.linconstrainteq!
3535
```
3636

src/ModelPredictiveControl.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export SteadyKalmanFilter, KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFi
3939
export MovingHorizonEstimator
4040
export default_nint, initstate!
4141
export PredictiveController, ExplicitMPC, LinMPC, NonLinMPC, setconstraint!, moveinput!
42-
export SingleShooting, MultipleShooting
42+
export TranscriptionMethod, SingleShooting, MultipleShooting
4343
export SimResult, getinfo, sim!
4444

4545
include("general.jl")

src/controller/construct.jl

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ function setconstraint!(
386386
JuMP.delete(optim, optim[:linconstraint])
387387
JuMP.unregister(optim, :linconstraint)
388388
@constraint(optim, linconstraint, A*Z̃var .≤ b)
389-
set_nonlincon!(mpc, model, optim)
389+
set_nonlincon!(mpc, model, transcription, optim)
390390
else
391391
i_b, i_g = init_matconstraint_mpc(
392392
model, transcription, nc,
@@ -400,94 +400,6 @@ function setconstraint!(
400400
return mpc
401401
end
402402

403-
404-
@doc raw"""
405-
init_matconstraint_mpc(
406-
model::LinModel, transcription::TranscriptionMethod, nc::Int,
407-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
408-
args...
409-
) -> i_b, i_g, A, Aeq, neq
410-
411-
Init `i_b`, `i_g`, `neq`, and `A` and `Aeq` matrices for the all the MPC constraints.
412-
413-
The linear and nonlinear constraints are respectively defined as:
414-
```math
415-
\begin{aligned}
416-
\mathbf{A Z̃ } &≤ \mathbf{b} \\
417-
\mathbf{A_{eq} Z̃} &= \mathbf{b_{eq}} \\
418-
\mathbf{g(Z̃)} &≤ \mathbf{0} \\
419-
\mathbf{g_{eq}(Z̃)} &= \mathbf{0} \\
420-
\end{aligned}
421-
```
422-
The argument `nc` is the number of custom nonlinear inequality constraints in
423-
``\mathbf{g_c}``. `i_b` is a `BitVector` including the indices of ``\mathbf{b}`` that are
424-
finite numbers. `i_g` is a similar vector but for the indices of ``\mathbf{g}``. The method
425-
also returns the ``\mathbf{A, A_{eq}}`` matrices and `neq` if `args` is provided. In such a
426-
case, `args` needs to contain all the inequality and equality constraint matrices:
427-
`A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂min, A_x̂max, A_ŝ`. The integer `neq`
428-
is the number of nonlinear equality constraints in ``\mathbf{g_{eq}}``.
429-
"""
430-
function init_matconstraint_mpc(
431-
::LinModel{NT}, ::TranscriptionMethod, nc::Int,
432-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
433-
args...
434-
) where {NT<:Real}
435-
if isempty(args)
436-
A, Aeq, neq = nothing, nothing, nothing
437-
else
438-
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂min, A_x̂max, A_ŝ = args
439-
A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax; A_Ymin; A_Ymax; A_x̂min; A_x̂max]
440-
Aeq = A_ŝ
441-
neq = 0
442-
end
443-
i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax; i_Ymin; i_Ymax; i_x̂min; i_x̂max]
444-
i_g = trues(nc)
445-
return i_b, i_g, A, Aeq, neq
446-
end
447-
448-
"Init `i_b` without output constraints if [`NonLinModel`](@ref) & [`MultipleShooting`](@ref)."
449-
function init_matconstraint_mpc(
450-
::NonLinModel{NT}, ::MultipleShooting, nc::Int,
451-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
452-
args...
453-
) where {NT<:Real}
454-
if isempty(args)
455-
A, Aeq, neq = nothing, nothing, nothing
456-
else
457-
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂min, A_x̂max, A_ŝ = args
458-
A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax; A_Ymin; A_Ymax; A_x̂min; A_x̂max]
459-
Aeq = A_ŝ
460-
nΔŨ, nZ̃ = size(A_ΔŨmin)
461-
neq = nZ̃ - nΔŨ
462-
end
463-
i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax; i_x̂min; i_x̂max]
464-
i_g = [i_Ymin; i_Ymax; trues(nc)]
465-
return i_b, i_g, A, Aeq, neq
466-
end
467-
468-
"Init `i_b` without output & terminal constraints if [`NonLinModel`](@ref) & [`SingleShooting`](@ref)."
469-
function init_matconstraint_mpc(
470-
::NonLinModel{NT}, ::SingleShooting, nc::Int,
471-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
472-
args...
473-
) where {NT<:Real}
474-
if isempty(args)
475-
A, Aeq, neq = nothing, nothing, nothing
476-
else
477-
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂min, A_x̂max, A_ŝ = args
478-
A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax; A_Ymin; A_Ymax; A_x̂min; A_x̂max]
479-
Aeq = A_ŝ
480-
neq = 0
481-
end
482-
i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax]
483-
i_g = [i_Ymin; i_Ymax; i_x̂min; i_x̂max; trues(nc)]
484-
return i_b, i_g, A, Aeq, neq
485-
end
486-
487-
488-
"By default, there is no nonlinear constraint, thus do nothing."
489-
set_nonlincon!(::PredictiveController, ::SimModel, ::JuMP.GenericModel) = nothing
490-
491403
"""
492404
default_Hp(model::LinModel)
493405

src/controller/execute.jl

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function moveinput!(
6666
end
6767
validate_args(mpc, ry, d, D̂, R̂y, R̂u)
6868
initpred!(mpc, mpc.estim.model, d, D̂, R̂y, R̂u)
69-
linconstraint!(mpc, mpc.estim.model)
69+
linconstraint!(mpc, mpc.estim.model, mpc.transcription)
7070
linconstrainteq!(mpc, mpc.estim.model, mpc.transcription)
7171
= optim_objective!(mpc)
7272
return getinput(mpc, Z̃)
@@ -278,66 +278,6 @@ end
278278
"Fill `Ŷs` vector with 0 values when `estim` is not an [`InternalModel`](@ref)."
279279
predictstoch!(Ŷs, mpc::PredictiveController, ::StateEstimator) = (Ŷs .= 0; nothing)
280280

281-
@doc raw"""
282-
linconstraint!(mpc::PredictiveController, model::LinModel)
283-
284-
Set `b` vector for the linear model inequality constraints (``\mathbf{A Z̃ ≤ b}``).
285-
286-
Also init ``\mathbf{f_x̂} = \mathbf{g_x̂ d_0}(k) + \mathbf{j_x̂ D̂_0} + \mathbf{k_x̂ x̂_0}(k) +
287-
\mathbf{v_x̂ u_0}(k-1) + \mathbf{b_x̂}`` vector for the terminal constraints, see
288-
[`init_predmat`](@ref).
289-
"""
290-
function linconstraint!(mpc::PredictiveController, model::LinModel)
291-
nU, nΔŨ, nY = length(mpc.con.U0min), length(mpc.con.ΔŨmin), length(mpc.con.Y0min)
292-
nx̂, fx̂ = mpc.estim.nx̂, mpc.con.fx̂
293-
fx̂ .= mpc.con.bx̂
294-
mul!(fx̂, mpc.con.kx̂, mpc.estim.x̂0, 1, 1)
295-
mul!(fx̂, mpc.con.vx̂, mpc.estim.lastu0, 1, 1)
296-
if model.nd 0
297-
mul!(fx̂, mpc.con.gx̂, mpc.d0, 1, 1)
298-
mul!(fx̂, mpc.con.jx̂, mpc.D̂0, 1, 1)
299-
end
300-
n = 0
301-
mpc.con.b[(n+1):(n+nU)] .= @. -mpc.con.U0min + mpc.Tu_lastu0
302-
n += nU
303-
mpc.con.b[(n+1):(n+nU)] .= @. +mpc.con.U0max - mpc.Tu_lastu0
304-
n += nU
305-
mpc.con.b[(n+1):(n+nΔŨ)] .= @. -mpc.con.ΔŨmin
306-
n += nΔŨ
307-
mpc.con.b[(n+1):(n+nΔŨ)] .= @. +mpc.con.ΔŨmax
308-
n += nΔŨ
309-
mpc.con.b[(n+1):(n+nY)] .= @. -mpc.con.Y0min + mpc.F
310-
n += nY
311-
mpc.con.b[(n+1):(n+nY)] .= @. +mpc.con.Y0max - mpc.F
312-
n += nY
313-
mpc.con.b[(n+1):(n+nx̂)] .= @. -mpc.con.x̂0min + fx̂
314-
n += nx̂
315-
mpc.con.b[(n+1):(n+nx̂)] .= @. +mpc.con.x̂0max - fx̂
316-
if any(mpc.con.i_b)
317-
lincon = mpc.optim[:linconstraint]
318-
JuMP.set_normalized_rhs(lincon, mpc.con.b[mpc.con.i_b])
319-
end
320-
return nothing
321-
end
322-
323-
"Set `b` excluding predicted output constraints when `model` is not a [`LinModel`](@ref)."
324-
function linconstraint!(mpc::PredictiveController, ::SimModel)
325-
nU, nΔŨ = length(mpc.con.U0min), length(mpc.con.ΔŨmin)
326-
n = 0
327-
mpc.con.b[(n+1):(n+nU)] .= @. -mpc.con.U0min + mpc.Tu_lastu0
328-
n += nU
329-
mpc.con.b[(n+1):(n+nU)] .= @. +mpc.con.U0max - mpc.Tu_lastu0
330-
n += nU
331-
mpc.con.b[(n+1):(n+nΔŨ)] .= @. -mpc.con.ΔŨmin
332-
n += nΔŨ
333-
mpc.con.b[(n+1):(n+nΔŨ)] .= @. +mpc.con.ΔŨmax
334-
if any(mpc.con.i_b)
335-
lincon = mpc.optim[:linconstraint]
336-
@views JuMP.set_normalized_rhs(lincon, mpc.con.b[mpc.con.i_b])
337-
end
338-
return nothing
339-
end
340-
341281
"""
342282
extended_vectors!(Ue, Ŷe, mpc::PredictiveController, U0, Ŷ0) -> Ue, Ŷe
343283

src/controller/explicitmpc.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ function Base.show(io::IO, mpc::ExplicitMPC)
182182
print_estim_dim(io, mpc.estim, n)
183183
end
184184

185-
linconstraint!(::ExplicitMPC, ::LinModel) = nothing
185+
linconstraint!(::ExplicitMPC, ::LinModel, ::TranscriptionMethod) = nothing
186186

187187
@doc raw"""
188188
optim_objective!(mpc::ExplicitMPC) -> Z̃

src/controller/nonlinmpc.jl

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ function init_optimization!(
543543
@operator(optim, J, nZ̃, Jfunc, ∇Jfunc!)
544544
@objective(optim, Min, J(Z̃var...))
545545
init_nonlincon!(mpc, model, transcription, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!)
546-
set_nonlincon!(mpc, model, optim)
546+
set_nonlincon!(mpc, model, transcription, optim)
547547
return nothing
548548
end
549549

@@ -739,60 +739,6 @@ function get_optim_functions(
739739
return Jfunc, ∇Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!
740740
end
741741

742-
"""
743-
set_nonlincon!(mpc::NonLinMPC, ::LinModel, optim)
744-
745-
Set the custom nonlinear inequality constraints for `LinModel`.
746-
"""
747-
function set_nonlincon!(
748-
mpc::NonLinMPC, ::LinModel, optim::JuMP.GenericModel{JNT}
749-
) where JNT<:Real
750-
Z̃var = optim[:Z̃var]
751-
con = mpc.con
752-
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
753-
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
754-
for i in 1:con.nc
755-
gfunc_i = optim[Symbol("g_c_$i")]
756-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
757-
end
758-
return nothing
759-
end
760-
761-
"""
762-
set_nonlincon!(mpc::NonLinMPC, ::NonLinModel, optim)
763-
764-
Also set output prediction `Ŷ` and terminal state `x̂end` constraints when not a `LinModel`.
765-
"""
766-
function set_nonlincon!(
767-
mpc::NonLinMPC, ::SimModel, optim::JuMP.GenericModel{JNT}
768-
) where JNT<:Real
769-
Z̃var = optim[:Z̃var]
770-
con = mpc.con
771-
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
772-
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
773-
for i in findall(.!isinf.(con.Y0min))
774-
gfunc_i = optim[Symbol("g_Y0min_$(i)")]
775-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
776-
end
777-
for i in findall(.!isinf.(con.Y0max))
778-
gfunc_i = optim[Symbol("g_Y0max_$(i)")]
779-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
780-
end
781-
for i in findall(.!isinf.(con.x̂0min))
782-
gfunc_i = optim[Symbol("g_x̂0min_$(i)")]
783-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
784-
end
785-
for i in findall(.!isinf.(con.x̂0max))
786-
gfunc_i = optim[Symbol("g_x̂0max_$(i)")]
787-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
788-
end
789-
for i in 1:con.nc
790-
gfunc_i = optim[Symbol("g_c_$i")]
791-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
792-
end
793-
return nothing
794-
end
795-
796742
"""
797743
con_nonlinprog!(g, mpc::NonLinMPC, model::LinModel, _ , _ , gc, ϵ) -> g
798744

0 commit comments

Comments
 (0)