@@ -9,7 +9,7 @@ import ModelPredictiveControl: isblockdiag
99
1010function Base. convert(:: Type{LinearMPC.MPC} , mpc:: ModelPredictiveControl.LinMPC )
1111 model, estim, weights = mpc. estim. model, mpc. estim, mpc. weights
12- nu, ny, nx̂ = model. nu, model. ny, estim. nx̂
12+ nu, ny, nd, nx̂, nw = model. nu, model. ny, model . nd, estim. nx̂, mpc . con . nw
1313 Hp, Hc = mpc. Hp, mpc. Hc
1414 nΔU = Hc * nu
1515 validate_compatibility(mpc)
@@ -36,17 +36,18 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
3636 R = weights. L_Hp[1 : nu, 1 : nu]
3737 LinearMPC. set_objective!(newmpc; Q, Rr, R, Qf)
3838 # --- Custom move blocking ---
39- LinearMPC. move_block!(newmpc, mpc. nb) # un-comment when debugged
39+ LinearMPC. move_block!(newmpc, mpc. nb)
4040 # ---- Constraint softening ---
4141 only_hard = weights. isinf_C
4242 if ! only_hard
4343 issoft(C) = any(x -> x > 0 , C)
4444 C_u = - mpc. con. A_Umin[:, end ]
4545 C_Δu = - mpc. con. A_ΔŨmin[1 : nΔU, end ]
4646 C_y = - mpc. con. A_Ymin[:, end ]
47+ C_w = - mpc. con. A_Wmin[:, end ]
4748 c_x̂ = - mpc. con. A_x̂min[:, end ]
4849 if sum(mpc. con. i_b) > 1 # ignore the slack variable ϵ bound
49- if issoft(C_u) || issoft(C_Δu) || issoft(C_y) || issoft(C_x̂)
50+ if issoft(C_u) || issoft(C_Δu) || issoft(C_y) || issoft(C_w) || issoft( C_x̂)
5051 @warn " The LinearMPC conversion is approximate for the soft constraints.\n " *
5152 " You may need to adjust the soft_weight field of the " *
5253 " LinearMPC.MPC object to replicate behaviors."
@@ -61,23 +62,14 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
6162 C_u = zeros(nu* Hp)
6263 C_Δu = zeros(nu* Hc)
6364 C_y = zeros(ny* Hp)
65+ C_w = zeros(nw* (Hp+ 1 ))
6466 c_x̂ = zeros(nx̂)
6567 end
6668 # --- Manipulated inputs constraints ---
6769 Umin, Umax = mpc. con. U0min + mpc. Uop, mpc. con. U0max + mpc. Uop
6870 I_u = Matrix{Float64}(I, nu, nu)
69- # add_constraint! does not support u bounds pass the control horizon Hc
70- # so we compute the extremum bounds from k=Hc-1 to Hp, and apply them at k=Hc-1
71- Umin_finals = reshape(Umin[nu* (Hc- 1 )+ 1 : end ], nu, :)
72- Umax_finals = reshape(Umax[nu* (Hc- 1 )+ 1 : end ], nu, :)
73- umin_end = mapslices(maximum, Umin_finals; dims= 2 )
74- umax_end = mapslices(minimum, Umax_finals; dims= 2 )
75- for k in 0 : Hc- 1
76- if k < Hc - 1
77- umin_k, umax_k = Umin[k* nu+ 1 : (k+ 1 )* nu], Umax[k* nu+ 1 : (k+ 1 )* nu]
78- else
79- umin_k, umax_k = umin_end, umax_end
80- end
71+ for k = 0 : Hp- 1
72+ umin_k, umax_k = Umin[k* nu+ 1 : (k+ 1 )* nu], Umax[k* nu+ 1 : (k+ 1 )* nu]
8173 c_u_k = C_u[k* nu+ 1 : (k+ 1 )* nu]
8274 ks = [k + 1 ] # a `1` in ks argument corresponds to the present time step k+0
8375 for i in 1 : nu
@@ -91,7 +83,7 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
9183 # --- Input increment constraints ---
9284 ΔUmin, ΔUmax = mpc. con. ΔŨmin[1 : nΔU], mpc. con. ΔŨmax[1 : nΔU]
9385 I_Δu = Matrix{Float64}(I, nu, nu)
94- for k in 0 : Hc- 1
86+ for k = 0 : Hc- 1
9587 Δumin_k, Δumax_k = ΔUmin[k* nu+ 1 : (k+ 1 )* nu], ΔUmax[k* nu+ 1 : (k+ 1 )* nu]
9688 c_Δu_k = C_Δu[k* nu+ 1 : (k+ 1 )* nu]
9789 ks = [k + 1 ] # a `1` in ks argument corresponds to the present time step k+0
@@ -105,7 +97,7 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
10597 end
10698 # --- Output constraints ---
10799 Y0min, Y0max = mpc. con. Y0min, mpc. con. Y0max
108- for k in 1 : Hp
100+ for k = 1 : Hp
109101 ymin_k, ymax_k = Y0min[(k- 1 )* ny+ 1 : k* ny], Y0max[(k- 1 )* ny+ 1 : k* ny]
110102 c_y_k = C_y[(k- 1 )* ny+ 1 : k* ny]
111103 ks = [k + 1 ] # a `1` in ks argument corresponds to the present time step k+0
@@ -117,6 +109,30 @@ function Base.convert(::Type{LinearMPC.MPC}, mpc::ModelPredictiveControl.LinMPC)
117109 LinearMPC. add_constraint!(newmpc; Ax, Ad, lb, ub, ks, soft)
118110 end
119111 end
112+ # --- Custom linear constraints ---
113+ Wmin, Wmax = mpc. con. Wmin, mpc. con. Wmax
114+ Wy = mpc. con. W̄y[1 : nw, 1 : ny]
115+ Wu = mpc. con. W̄u[1 : nw, 1 : nu]
116+ Wd = mpc. con. W̄d[1 : nw, 1 : nd]
117+ Wr = mpc. con. W̄r[1 : nw, 1 : ny]
118+ for k in 0 : Hp
119+ wmin_k, wmax_k = Wmin[k* nw+ 1 : (k+ 1 )* nw], Wmax[k* nw+ 1 : (k+ 1 )* nw]
120+ c_w_k = C_w[k* nw+ 1 : (k+ 1 )* nw]
121+ ks = [k + 1 ]
122+ for i in 1 : nw
123+ Wy_i, Wu_i, Wd_i, Wr_i = Wy[i: i, :], Wu[i: i, :], Wd[i: i, :], Wr[i: i, :]
124+ lb_k_i = wmin_k[i: i] - Wy_i* yoff
125+ ub_k_i = wmax_k[i: i] - Wy_i* yoff
126+ lb = isfinite(lb_k_i[]) ? lb_k_i : zeros(0 )
127+ ub = isfinite(ub_k_i[]) ? ub_k_i : zeros(0 )
128+ soft = ! only_hard && c_w_k[i] > 0
129+ Ax = Wy_i* C
130+ Au = Wu_i
131+ Ad = Wy_i* Dd + Wd_i
132+ Ar = Wr_i
133+ LinearMPC. add_constraint!(newmpc; Ax, Au, Ad, Ar, lb, ub, ks, soft)
134+ end
135+ end
120136 # --- Terminal constraints ---
121137 x̂0min, x̂0max = mpc. con. x̂0min, mpc. con. x̂0max
122138 I_x̂ = Matrix{Float64}(I, nx̂, nx̂)
@@ -180,29 +196,32 @@ end
180196
181197function validate_constraints(mpc:: ModelPredictiveControl.LinMPC )
182198 nΔU = mpc. Hc * mpc. estim. model. nu
183- mpc. con. nw > 0 && error(" Conversion of custom linear inequality constraints is not supported for now." )
184199 mpc. weights. isinf_C && return nothing # only hard constraints are entirely supported
185200 C_umin, C_umax = - mpc. con. A_Umin[:, end ], - mpc. con. A_Umax[:, end ]
186201 C_Δumin, C_Δumax = - mpc. con. A_ΔŨmin[1 : nΔU, end ], - mpc. con. A_ΔŨmax[1 : nΔU, end ]
187202 C_ymin, C_ymax = - mpc. con. A_Ymin[:, end ], - mpc. con. A_Ymax[:, end ]
203+ C_wmin, C_wmax = - mpc. con. A_Wmin[:, end ], - mpc. con. A_Wmax[:, end ]
188204 C_x̂min, C_x̂max = - mpc. con. A_x̂min[:, end ], - mpc. con. A_x̂max[:, end ]
205+ if (
206+ ! isapprox(C_umin, C_umax) ||
207+ ! isapprox(C_Δumin, C_Δumax) ||
208+ ! isapprox(C_ymin, C_ymax) ||
209+ ! isapprox(C_wmin, C_wmax) ||
210+ ! isapprox(C_x̂min, C_x̂max)
211+ )
212+ error(" LinearMPC only supports identical softness parameters for lower and upper bounds." )
213+ end
189214 is0or1(C) = all(x -> x ≈ 0 || x ≈ 1 , C)
190215 if (
191216 ! is0or1(C_umin) || ! is0or1(C_umax) ||
192217 ! is0or1(C_Δumin) || ! is0or1(C_Δumax) ||
193- ! is0or1(C_ymin) || ! is0or1(C_ymax) ||
218+ ! is0or1(C_ymin) || ! is0or1(C_ymax) ||
219+ ! is0or1(C_wmin) || ! is0or1(C_wmax) ||
194220 ! is0or1(C_x̂min) || ! is0or1(C_x̂max)
195221
196222 )
197- error(" LinearMPC only supports softness parameters c = 0 or 1." )
198- end
199- if (
200- ! isapprox(C_umin, C_umax) ||
201- ! isapprox(C_Δumin, C_Δumax) ||
202- ! isapprox(C_ymin, C_ymax) ||
203- ! isapprox(C_x̂min, C_x̂max)
204- )
205- error(" LinearMPC only supports identical softness parameters for lower and upper bounds." )
223+ @warn " LinearMPC only supports softness parameters c = 0 or 1.\n " *
224+ " All constraints with c > 0 will be considered soft."
206225 end
207226 return nothing
208227end
0 commit comments