@@ -70,12 +70,24 @@ The predictive controllers support both soft and hard constraints, defined by:
7070 \m athbf{y_{min} - c_{y_{min}}} ϵ &≤ \m athbf{ŷ}(k+j) &&≤ \m athbf{y_{max} + c_{y_{max}}} ϵ &&\q quad j = 1, 2 ,..., H_p \\
7171\e nd{alignat*}
7272```
73- and also ``ϵ ≥ 0``. All the constraint parameters are vector. Use `±Inf` values when there
74- is no bound. The constraint softness parameters ``\m athbf{c}``, also called equal concern
75- for relaxation, are non-negative values that specify the softness of the associated bound.
76- Use `0.0` values for hard constraints. The output constraints ``\m athbf{y_{min}}`` and
73+ and also ``ϵ ≥ 0``. All the constraint parameters are vector. Use `±Inf` values when there
74+ is no bound. The constraint softness parameters ``\m athbf{c}``, also called equal concern
75+ for relaxation, are non-negative values that specify the softness of the associated bound.
76+ Use `0.0` values for hard constraints. The output constraints ``\m athbf{y_{min}}`` and
7777``\m athbf{y_{max}}`` are soft by default.
7878
79+ The bounds can be modified after calling [`moveinput!`](@ref), that is, at runtime, but not
80+ the softness parameters ``\m athbf{c}``. It is not possible to modify `±Inf` constraints
81+ at runtime.
82+
83+ !!! tip
84+ To keep a variable unconstrained while maintaining the ability to add a constraint later
85+ at runtime, set the bound to an absolute value sufficiently large when you create the
86+ controller.
87+
88+ Varying the constraints over the prediction/control horizon is not supported yet but it will
89+ be implemented soon.
90+
7991# Arguments
8092!!! info
8193 The default constraints are mentioned here for clarity but omitting a keyword argument
@@ -123,13 +135,16 @@ function setconstraint!(
123135 ŷmin = nothing , ŷmax = nothing ,
124136 c_ŷmin = nothing , c_ŷmax = nothing ,
125137)
126- model = mpc. estim. model
127- con = mpc. con
128- nu, ny = model. nu, model. ny
129- Hp, Hc = mpc. Hp, mpc. Hc
138+ model, con, optim = mpc. estim. model, mpc. con, mpc. optim
139+ nu, ny, Hp, Hc = model. nu, model. ny, mpc. Hp, mpc. Hc
140+ notSolvedYet = (termination_status (optim) == OPTIMIZE_NOT_CALLED)
130141 C, E = mpc. C, mpc. Ẽ[:, 1 : nu* Hc]
142+ if ! all (isnothing .([c_umin, c_umax, c_Δumin, c_Δumax, c_ymin, c_ymax]))
143+ ! isinf (C) || throw (ArgumentError (" Slack variable Cwt must be finite to set softness parameters" ))
144+ notSolvedYet || error (" Cannot set softness parameters after calling moveinput!" )
145+ end
131146
132- # these 4 if will be deleted in the future:
147+ # these 4 `if`s will be deleted in the future:
133148 if ! isnothing (ŷmin)
134149 Base. depwarn (" keyword arg ŷmin is deprecated, use ymin instead" , :setconstraint! )
135150 ymin = ŷmin
@@ -148,75 +163,69 @@ function setconstraint!(
148163 end
149164
150165 if ! isnothing (umin)
151- size (umin) == (nu,) || error ( " umin size must be $((nu,)) " )
166+ size (umin) == (nu,) || throw ( ArgumentError ( " umin size must be $((nu,)) " ) )
152167 Umin = repeat (umin, Hc)
153168 con. Umin[:] = Umin
154169 end
155170 if ! isnothing (umax)
156- size (umax) == (nu,) || error ( " umax size must be $((nu,)) " )
157- Umax = repeat (umax, Hc)
171+ size (umax) == (nu,) || throw ( ArgumentError ( " umax size must be $((nu,)) " ) )
172+ Umax = repeat (umax, Hc)
158173 con. Umax[:] = Umax
159174 end
160175 if ! isnothing (Δumin)
161- size (Δumin) == (nu,) || error ( " Δumin size must be $((nu,)) " )
176+ size (Δumin) == (nu,) || throw ( ArgumentError ( " Δumin size must be $((nu,)) " ) )
162177 ΔUmin = repeat (Δumin, Hc)
163178 con. ΔŨmin[1 : nu* Hc] = ΔUmin
164179 end
165180 if ! isnothing (Δumax)
166- size (Δumax) == (nu,) || error ( " Δumax size must be $((nu,)) " )
181+ size (Δumax) == (nu,) || throw ( ArgumentError ( " Δumax size must be $((nu,)) " ) )
167182 ΔUmax = repeat (Δumax, Hc)
168183 con. ΔŨmax[1 : nu* Hc] = ΔUmax
169184 end
170185 if ! isnothing (ymin)
171- size (ymin) == (ny,) || error ( " ymin size must be $((ny,)) " )
186+ size (ymin) == (ny,) || throw ( ArgumentError ( " ymin size must be $((ny,)) " ) )
172187 Ymin = repeat (ymin, Hp)
173188 con. Ymin[:] = Ymin
174189 end
175190 if ! isnothing (ymax)
176- size (ymax) == (ny,) || error ( " ymax size must be $((ny,)) " )
191+ size (ymax) == (ny,) || throw ( ArgumentError ( " ymax size must be $((ny,)) " ) )
177192 Ymax = repeat (ymax, Hp)
178193 con. Ymax[:] = Ymax
179194 end
180195 if ! isnothing (c_umin)
181- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
182- size (c_umin) == (nu,) || error (" c_umin size must be $((nu,)) " )
196+ size (c_umin) == (nu,) || throw (ArgumentError (" c_umin size must be $((nu,)) " ))
183197 any (c_umin .< 0 ) && error (" c_umin weights should be non-negative" )
184198 c_Umin = repeat (c_umin, Hc)
185199 con. A_Umin[:, end ] = - c_Umin
186200 end
187201 if ! isnothing (c_umax)
188- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
189- size (c_umax) == (nu,) || error (" c_umax size must be $((nu,)) " )
202+ size (c_umax) == (nu,) || throw (ArgumentError (" c_umax size must be $((nu,)) " ))
190203 any (c_umax .< 0 ) && error (" c_umax weights should be non-negative" )
191204 c_Umax = repeat (c_umax, Hc)
192205 con. A_Umax[:, end ] = - c_Umax
193206 end
194207 if ! isnothing (c_Δumin)
195- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
196- size (c_Δumin) == (nu,) || error (" c_Δumin size must be $((nu,)) " )
208+ size (c_Δumin) == (nu,) || throw (ArgumentError (" c_Δumin size must be $((nu,)) " ))
197209 any (c_Δumin .< 0 ) && error (" c_Δumin weights should be non-negative" )
198210 c_ΔUmin = repeat (c_Δumin, Hc)
199211 con. A_ΔŨmin[1 : end - 1 , end ] = - c_ΔUmin
200212 end
201213 if ! isnothing (c_Δumax)
202- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
203- size (c_Δumax) == (nu,) || error (" c_Δumax size must be $((nu,)) " )
214+ size (c_Δumax) == (nu,) || throw (ArgumentError (" c_Δumax size must be $((nu,)) " ))
204215 any (c_Δumax .< 0 ) && error (" c_Δumax weights should be non-negative" )
205216 c_ΔUmax = repeat (c_Δumax, Hc)
206217 con. A_ΔŨmax[1 : end - 1 , end ] = - c_ΔUmax
207218 end
208219 if ! isnothing (c_ymin)
209- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
210- size (c_ymin) == (ny,) || error (" c_ymin size must be $((ny,)) " )
220+ size (c_ymin) == (ny,) || throw (ArgumentError (" c_ymin size must be $((ny,)) " ))
211221 any (c_ymin .< 0 ) && error (" c_ymin weights should be non-negative" )
212222 c_Ymin = repeat (c_ymin, Hp)
213223 con. c_Ymin[:] = c_Ymin
214224 A_Ymin ,_ = relaxŶ (model, C, con. c_Ymin, con. c_Ymax, E)
215225 con. A_Ymin[:] = A_Ymin
216226 end
217227 if ! isnothing (c_ymax)
218- ! isinf (C) || error (" Slack variable Cwt must be finite to set softness parameters" )
219- size (c_ymax) == (ny,) || error (" c_ymax size must be $((ny,)) " )
228+ size (c_ymax) == (ny,) || throw (ArgumentError (" c_ymax size must be $((ny,)) " ))
220229 any (c_ymax .< 0 ) && error (" c_ymax weights should be non-negative" )
221230 c_Ymax = repeat (c_ymax, Hp)
222231 con. c_Ymax[:] = c_Ymax
@@ -226,17 +235,25 @@ function setconstraint!(
226235 i_Umin, i_Umax = .! isinf .(con. Umin), .! isinf .(con. Umax)
227236 i_ΔŨmin, i_ΔŨmax = .! isinf .(con. ΔŨmin), .! isinf .(con. ΔŨmin)
228237 i_Ymin, i_Ymax = .! isinf .(con. Ymin), .! isinf .(con. Ymax)
229- con. A[:], con. i_b[:] = init_linconstraint (model,
230- con. A_Umin, con. A_Umax, con. A_ΔŨmin, con. A_ΔŨmax, con. A_Ymin, con. A_Ymax,
231- i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax
232- )
233- A = con. A[con. i_b, :]
234- b = con. b[con. i_b]
235- ΔŨvar = mpc. optim[:ΔŨvar ]
236- delete (mpc. optim, mpc. optim[:linconstraint ])
237- unregister (mpc. optim, :linconstraint )
238- @constraint (mpc. optim, linconstraint, A* ΔŨvar .≤ b)
239- setnonlincon! (mpc, model)
238+ if notSolvedYet
239+ con. i_b[:], con. A[:] = init_linconstraint (model,
240+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax,
241+ con. A_Umin, con. A_Umax, con. A_ΔŨmin, con. A_ΔŨmax, con. A_Ymin, con. A_Ymax
242+ )
243+ A = con. A[con. i_b, :]
244+ b = con. b[con. i_b]
245+ ΔŨvar = mpc. optim[:ΔŨvar ]
246+ delete (mpc. optim, mpc. optim[:linconstraint ])
247+ unregister (mpc. optim, :linconstraint )
248+ @constraint (mpc. optim, linconstraint, A* ΔŨvar .≤ b)
249+ setnonlincon! (mpc, model)
250+ else
251+ i_b, _ = init_linconstraint (model,
252+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax,
253+ con. A_Umin, con. A_Umax, con. A_ΔŨmin, con. A_ΔŨmax, con. A_Ymin, con. A_Ymax,
254+ )
255+ i_b == con. i_b || error (" Cannot modify ±Inf constraints after calling moveinput!" )
256+ end
240257 return mpc
241258end
242259
@@ -826,11 +843,12 @@ function init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
826843 i_Umin, i_Umax = .! isinf .(Umin), .! isinf .(Umax)
827844 i_ΔŨmin, i_ΔŨmax = .! isinf .(ΔŨmin), .! isinf .(ΔŨmax)
828845 i_Ymin, i_Ymax = .! isinf .(Ymin), .! isinf .(Ymax)
829- A, i_b, b = init_linconstraint (
846+ i_b, A = init_linconstraint (
830847 model,
831- A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax ,
832- i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax
848+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax ,
849+ A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax
833850 )
851+ b = zeros (size (A, 1 )) # dummy b vector (updated just before optimization)
834852 con = ControllerConstraint (
835853 Umin , Umax , ΔŨmin , ΔŨmax , Ymin , Ymax,
836854 A_Umin , A_Umax, A_ΔŨmin, A_ΔŨmax , A_Ymin, A_Ymax,
@@ -998,34 +1016,32 @@ init_stochpred(::StateEstimator, _ ) = zeros(0, 0), zeros(0, 0)
9981016
9991017
10001018@doc raw """
1001- init_linconstraint(model::LinModel,
1019+ init_linconstraint(model::LinModel,
1020+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax,
10021021 A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax,
1003- i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax
1004- ) -> A, i_b, b
1022+ ) -> i_b, A
10051023
1006- Init `A`, `b` and `i_b ` for the linear inequality constraints (``\m athbf{A ΔŨ ≤ b}``).
1024+ Init `i_b` and `A ` for the linear inequality constraints (``\m athbf{A ΔŨ ≤ b}``).
10071025
10081026`i_b` is a `BitVector` including the indices of ``\m athbf{b}`` that are finite numbers.
10091027"""
10101028function init_linconstraint (:: LinModel ,
1029+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax,
10111030 A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax,
1012- i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax
10131031)
1014- A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax; A_Ymin; A_Ymax]
10151032 i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax; i_Ymin; i_Ymax]
1016- b = zeros ( size (A, 1 )) # dummy b vector (updated just before optimization)
1017- return A, i_b, b
1033+ A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax; A_Ymin; A_Ymax]
1034+ return i_b, A
10181035end
10191036
10201037" Init values without predicted output constraints if `model` is not a [`LinModel`](@ref)."
10211038function init_linconstraint (:: SimModel ,
1022- A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax , _ , _ ,
1023- i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax , _ , _
1039+ i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax , _ , _ ,
1040+ A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax , _ , _
10241041)
1025- A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax]
10261042 i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax]
1027- b = zeros ( size (A, 1 )) # dummy b vector (updated just before optimization)
1028- return A, i_b, b
1043+ A = [A_Umin; A_Umax; A_ΔŨmin; A_ΔŨmax]
1044+ return i_b, A
10291045end
10301046
10311047" Validate predictive controller weight and horizon specified values."
0 commit comments