Skip to content

Commit 9194d4f

Browse files
committed
added: heuristic conversion factor of soft constraints
Since DAQP introduces implicitly a new variable for each softened constraints, it make sense to apply a conversion factor inversely proportional to the number of softened constraints. I tested on a simple SISO model and it works OK for various scenario of softened constraints. Note that the issue is less apparent when the only soft constraints is the output variable, which is the most common case in practice.
1 parent 92bb1b0 commit 9194d4f

1 file changed

Lines changed: 21 additions & 12 deletions

File tree

ext/LinearMPCext.jl

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import ModelPredictiveControl: isblockdiag
99

1010
function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
1111
model, estim, weights = mpc.estim.model, mpc.estim, mpc.weights
12-
nu, ny, nd, nx̂ = model.nu, model.ny, model.nd, estim.nx̂
12+
nu, ny, nx̂ = model.nu, model.ny, estim.nx̂
13+
Hp, Hc = mpc.Hp, mpc.Hc
14+
nΔU = Hc * nu
1315
validate_compatibility(mpc)
1416
# --- Model parameters ---
1517
F, G, Gd = estim.Â, estim.B̂u, estim.B̂d
1618
C, Dd = estim.Ĉ, estim.D̂d
17-
Np = Hp = mpc.Hp
18-
Nc = Hc = mpc.Hc
19+
Np = Hp
20+
Nc = Hc
1921
newmpc = LinearMPC.MPC(F, G; Gd, C, Dd, Np, Nc)
2022
# --- Operating points ---
2123
uoff = model.uop
@@ -33,19 +35,29 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
3335
Rr = weights.Ñ_Hc[1:nu, 1:nu]
3436
R = weights.L_Hp[1:nu, 1:nu]
3537
LinearMPC.set_objective!(newmpc; Q, Rr, R, Qf)
38+
# --- Custom move blocking ---
39+
LinearMPC.move_block!(newmpc, mpc.nb) # un-comment when debugged
40+
# ---- Constraint softening ---
3641
only_hard = weights.isinf_C
3742
if !only_hard
3843
# LinearMPC relies on a different softening mechanism, so we apply
39-
# an approximate conversion factor on the softening weight:
44+
# an approximate conversion factor on the softening weight Cwt:
45+
nsoft = sum((mpc.con.A[:,end] .< 0) .& (mpc.con.i_b)) - 1
46+
conversion_factor = 1/2/nsoft
4047
Cwt = weights.Ñ_Hc[end, end]
41-
conversion_factor = 0.1 #0.09066
4248
newmpc.settings.soft_weight = conversion_factor*Cwt
49+
C_u = -mpc.con.A_Umin[:, end]
50+
C_Δu = -mpc.con.A_ΔŨmin[1:nΔU, end]
51+
C_y = -mpc.con.A_Ymin[:, end]
52+
c_x̂ = -mpc.con.A_x̂min[:, end]
53+
else
54+
C_u = zeros(nu*Hp)
55+
C_Δu = zeros(nu*Hc)
56+
C_y = zeros(ny*Hp)
57+
c_x̂ = zeros(nx̂)
4358
end
44-
# --- Custom move blocking ---
45-
LinearMPC.move_block!(newmpc, mpc.nb) # un-comment when debugged
4659
# --- Manipulated inputs constraints ---
4760
Umin, Umax = mpc.con.U0min + mpc.Uop, mpc.con.U0max + mpc.Uop
48-
C_u = -mpc.con.A_Umin[:, end]
4961
I_u = Matrix{Float64}(I, nu, nu)
5062
# add_constraint! does not support u bounds pass the control horizon Hc
5163
# so we compute the extremum bounds from k=Hc-1 to Hp, and apply them at k=Hc-1
@@ -70,9 +82,7 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
7082
end
7183
end
7284
# --- Input increment constraints ---
73-
nΔU = Hc * nu
7485
ΔUmin, ΔUmax = mpc.con.ΔŨmin[1:nΔU], mpc.con.ΔŨmax[1:nΔU]
75-
C_Δu = -mpc.con.A_ΔŨmin[1:nΔU, end]
7686
I_Δu = Matrix{Float64}(I, nu, nu)
7787
for k in 0:Hc-1
7888
Δumin_k, Δumax_k = ΔUmin[k*nu+1:(k+1)*nu], ΔUmax[k*nu+1:(k+1)*nu]
@@ -88,7 +98,6 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
8898
end
8999
# --- Output constraints ---
90100
Y0min, Y0max = mpc.con.Y0min, mpc.con.Y0max
91-
C_y = -mpc.con.A_Ymin[:, end]
92101
for k in 1:Hp
93102
ymin_k, ymax_k = Y0min[(k-1)*ny+1:k*ny], Y0max[(k-1)*ny+1:k*ny]
94103
c_y_k = C_y[(k-1)*ny+1:k*ny]
@@ -103,7 +112,6 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
103112
end
104113
# --- Terminal constraints ---
105114
x̂0min, x̂0max = mpc.con.x̂0min, mpc.con.x̂0max
106-
c_x̂ = -mpc.con.A_x̂min[:, end]
107115
I_x̂ = Matrix{Float64}(I, nx̂, nx̂)
108116
ks = [Hp + 1] # a `1` in ks argument corresponds to the present time step k+0
109117
for i in 1:nx̂
@@ -165,6 +173,7 @@ end
165173

166174
function validate_constraints(mpc::ModelPredictiveControl.LinMPC)
167175
nΔU = mpc.Hc * mpc.estim.model.nu
176+
mpc.weights.isinf_C && return nothing # only hard constraints are entirely supported
168177
C_umin, C_umax = -mpc.con.A_Umin[:, end], -mpc.con.A_Umax[:, end]
169178
C_Δumin, C_Δumax = -mpc.con.A_ΔŨmin[1:nΔU, end], -mpc.con.A_ΔŨmax[1:nΔU, end]
170179
C_ymin, C_ymax = -mpc.con.A_Ymin[:, end], -mpc.con.A_Ymax[:, end]

0 commit comments

Comments
 (0)