Skip to content

Commit a580956

Browse files
committed
has_values to check if solution available
1 parent a1bf7dd commit a580956

File tree

3 files changed

+21
-36
lines changed

3 files changed

+21
-36
lines changed

Project.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
99
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
1010
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1111
OSQP = "ab2f91bb-94b4-55e3-9ba0-7f65df51de79"
12-
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1312

1413
[compat]
1514
ControlSystemsBase = "1"
16-
JuMP = "1"
1715
Ipopt = "1"
16+
JuMP = "1"
1817
OSQP = "0.8"
1918
julia = "1.6"
2019

src/ModelPredictiveControl.jl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
module ModelPredictiveControl
22

3-
#using JuMP
43
using LinearAlgebra
54
using ControlSystemsBase
65
using JuMP, OSQP, Ipopt
7-
using SparseArrays
86

97
export SimModel, LinModel, NonLinModel, setop!, setstate!, updatestate!, evaloutput
108
export StateEstimator, InternalModel, SteadyKalmanFilter, KalmanFilter
@@ -13,9 +11,6 @@ export PredictiveController, LinMPC, setconstraint!, moveinput!
1311

1412
include("sim_model.jl")
1513
include("state_estim.jl")
16-
17-
export LinMPC
18-
1914
include("predictive_control.jl")
2015

2116
end

src/predictive_control.jl

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,10 @@ end
399399
Compute the optimal manipulated input value `u` for the current control period.
400400
401401
Solve the optimization problem of `mpc` [`PredictiveController`](@ref) and return the
402-
results ``\mathbf{u}(k)``. Following the receding horizon principle, the algorithm dicards
402+
results ``\mathbf{u}(k)``. Following the receding horizon principle, the algorithm discards
403403
the optimal future manipulated inputs ``\mathbf{u}(k+1), \mathbf{u}(k+2), ``... The
404404
arguments `ry` and `d` are current output setpoints ``\mathbf{r_y}(k)`` and measured
405-
disturbances ``\mathbf{d}(k)``. The predicted output setpoint `R̂y` and mesured disturbances
405+
disturbances ``\mathbf{d}(k)``. The predicted output setpoint `R̂y` and measured disturbances
406406
`D̂` are defined as:
407407
```math
408408
\mathbf{R̂_y} = \begin{bmatrix}
@@ -447,8 +447,8 @@ function moveinput!(
447447
ŷs, Ŷs = predict_stoch(mpc, mpc.estim, x̂s, d, ym)
448448
F, q̃, p = init_prediction(mpc, mpc.model, d, D̂, Ŷs, R̂y, x̂d, lastu)
449449
b = init_constraint(mpc, mpc.model, F, lastu)
450-
ΔŨ, ϵ, J = optim_objective!(mpc, b, q̃, p)
451-
write_optimdata!(mpc, ΔŨ, ϵ, J, ŷs, Ŷs, lastu, F, ym, d)
450+
ΔŨ, J = optim_objective!(mpc, b, q̃, p)
451+
write_optimdata!(mpc, ΔŨ, J, ŷs, Ŷs, lastu, F, ym, d)
452452
Δu = ΔŨ[1:mpc.model.nu] # receding horizon principle: only Δu(k) is used (first one)
453453
u = lastu + Δu
454454
return u
@@ -501,7 +501,7 @@ predict_stoch(mpc, estim::StateEstimator, x̂s, d, _ ) = (estim.Cs*x̂s, mpc.Ks*
501501
"""
502502
predict_stoch(mpc, estim::InternalModel, x̂s, d, ym )
503503
504-
Use current measured ouputs `ym` for prediction when `estim` is a [`InternalModel`](@ref).
504+
Use current measured outputs `ym` for prediction when `estim` is a [`InternalModel`](@ref).
505505
"""
506506
function predict_stoch(mpc, estim::InternalModel, x̂s, d, ym )
507507
isnothing(ym) && error("Predictive controllers with InternalModel need the measured "*
@@ -563,38 +563,39 @@ end
563563
Optimize the `mpc` quadratic objective function for [`LinMPC`](@ref) type.
564564
"""
565565
function optim_objective!(mpc::LinMPC, b, q̃, p)
566-
# initial ΔŨ (warm start): [Δu_{k-1}(k); Δu_{k-1}(k+1); ... ; 0_{nu × 1}]
566+
optmodel = mpc.optim.model
567+
ΔŨ = optmodel[:ΔŨ]
567568
lastΔŨ = mpc.optim.ΔŨ
569+
set_objective_function(optmodel, obj_quadprog(ΔŨ, mpc.P̃, q̃))
570+
set_normalized_rhs.(optmodel[:constraint_lin], b)
571+
# initial ΔŨ (warm start): [Δu_{k-1}(k); Δu_{k-1}(k+1); ... ; 0_{nu × 1}]
568572
ΔŨ0 = [lastΔŨ[(mpc.model.nu+1):(mpc.Hc*mpc.model.nu)]; zeros(mpc.model.nu)]
569573
# if soft constraints, append the last slack value ϵ_{k-1}:
570574
!isinf(mpc.C) && (ΔŨ0 = [ΔŨ0; lastΔŨ[end]])
571-
ΔŨ = mpc.optim.model[:ΔŨ]
572575
set_start_value.(ΔŨ, ΔŨ0)
573-
set_objective_function(mpc.optim.model, obj_quadprog(ΔŨ, mpc.P̃, q̃))
574-
set_normalized_rhs.(mpc.optim.model[:constraint_lin], b)
575-
optimize!(mpc.optim.model)
576-
ΔŨ = value.(ΔŨ)
577-
ϵ = isinf(mpc.C) ? nothing : ΔŨ[end]
578-
J = objective_value(mpc.optim.model) + p # optimal objective value by adding constant p
579-
status = termination_status(mpc.optim.model)
576+
optimize!(optmodel)
577+
status = termination_status(optmodel)
580578
if !(status == OPTIMAL || status == LOCALLY_SOLVED)
581579
@warn "MPC termination status not OPTIMAL or LOCALLY_SOLVER ($status)"
580+
@debug solution_summary(optmodel)
582581
end
583-
if isfatal(status)
584-
# if error, we take last value :
582+
if has_values(optmodel)
583+
ΔŨ = value.(ΔŨ)
584+
else # if error, we take last value :
585585
ΔŨ = ΔŨ0
586586
end
587-
return ΔŨ, ϵ, J
587+
J = objective_value(optmodel) + p # optimal objective value by adding constant p
588+
return ΔŨ, J
588589
end
589590

590591
"""
591592
write_optimdata!(mpc::LinMPC, ΔŨ, ϵ, J, info, ŷs, Ŷs, lastu, F, ym, d)
592593
593594
Write `mpc.optim` with the [`LinMPC`](@ref) optimization results.
594595
"""
595-
function write_optimdata!(mpc::LinMPC, ΔŨ, ϵ, J, ŷs, Ŷs, lastu, F, ym, d)
596+
function write_optimdata!(mpc::LinMPC, ΔŨ, J, ŷs, Ŷs, lastu, F, ym, d)
596597
mpc.optim.ΔŨ = ΔŨ
597-
mpc.optim.ϵ = ϵ
598+
mpc.optim.ϵ = isinf(mpc.C) ? nothing : ΔŨ[end]
598599
mpc.optim.J = J
599600
mpc.optim.U = mpc.S̃_Hp*ΔŨ + mpc.T_Hp*lastu
600601
mpc.optim.u = mpc.optim.U[1:mpc.model.nu]
@@ -958,16 +959,6 @@ function validate_weights(model, Hp, Hc, Mwt, Nwt, Lwt, Cwt, ru)
958959
Cwt < 0 && error("Cwt weight should be ≥ 0")
959960
end
960961

961-
"Verify that the solver termination status means 'no solution available'."
962-
function isfatal(status::MOI.TerminationStatusCode)
963-
fatalstatuses = [
964-
INFEASIBLE, DUAL_INFEASIBLE, LOCALLY_INFEASIBLE, INFEASIBLE_OR_UNBOUNDED,
965-
SLOW_PROGRESS, NUMERICAL_ERROR, INVALID_MODEL, INVALID_OPTION, INTERRUPTED,
966-
OTHER_ERROR
967-
]
968-
return any(status .== fatalstatuses)
969-
end
970-
971962
"Generate a block diagonal matrix repeating `n` times the matrix `A`."
972963
repeatdiag(A, n::Int) = kron(I(n), A)
973964

0 commit comments

Comments
 (0)