Skip to content

Commit 6dc1196

Browse files
committed
added : support for varying constraints over Hp/Hc
1 parent 6df51d9 commit 6dc1196

File tree

3 files changed

+144
-76
lines changed

3 files changed

+144
-76
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 = "0.8.6"
4+
version = "0.9.0"
55

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

src/predictive_control.jl

Lines changed: 91 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -67,32 +67,21 @@ The predictive controllers support both soft and hard constraints, defined by:
6767
\begin{alignat*}{3}
6868
\mathbf{u_{min} - c_{u_{min}}} ϵ &≤ \mathbf{u}(k+j) &&≤ \mathbf{u_{max} + c_{u_{max}}} ϵ &&\qquad j = 0, 1 ,..., H_c - 1 \\
6969
\mathbf{Δu_{min} - c_{Δu_{min}}} ϵ &≤ \mathbf{Δu}(k+j) &&≤ \mathbf{Δu_{max} + c_{Δu_{max}}} ϵ &&\qquad j = 0, 1 ,..., H_c - 1 \\
70-
\mathbf{y_{min} - c_{y_{min}}} ϵ &≤ \mathbf{ŷ}(k+j) &&≤ \mathbf{y_{max} + c_{y_{max}}} ϵ &&\qquad j = 1, 2 ,..., H_p \\
70+
\mathbf{y_{min} - c_{y_{min}}} ϵ &≤ \mathbf{ŷ}(k+j) &&≤ \mathbf{y_{max} + c_{y_{max}}} ϵ &&\qquad j = 1, 2 ,..., H_p
7171
\end{alignat*}
7272
```
7373
and also ``ϵ ≥ 0``. All the constraint parameters are vector. Use `±Inf` values when there
7474
is no bound. The constraint softness parameters ``\mathbf{c}``, also called equal concern
7575
for relaxation, are non-negative values that specify the softness of the associated bound.
7676
Use `0.0` values for hard constraints. The output constraints ``\mathbf{y_{min}}`` and
77-
``\mathbf{y_{max}}`` are soft by default.
78-
79-
The bounds can be modified after calling [`moveinput!`](@ref), that is, at runtime, but not
80-
the softness parameters ``\mathbf{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.
77+
``\mathbf{y_{max}}`` are soft by default. See Extended Help for time-varying constraints.
9078
9179
# Arguments
9280
!!! info
9381
The default constraints are mentioned here for clarity but omitting a keyword argument
9482
will not re-assign to its default value (defaults are set at construction only).
9583
84+
- `mpc::PredictiveController` : predictive controller to set constraints.
9685
- `umin=fill(-Inf,nu)` : manipulated input lower bounds ``\mathbf{u_{min}}``
9786
- `umax=fill(+Inf,nu)` : manipulated input upper bounds ``\mathbf{u_{max}}``
9887
- `Δumin=fill(-Inf,nu)` : manipulated input increment lower bounds ``\mathbf{Δu_{min}}``
@@ -105,6 +94,8 @@ be implemented soon.
10594
- `c_Δumax=fill(0.0,nu)` : `Δumax` softness weights ``\mathbf{c_{Δu_{max}}}``
10695
- `c_ymin=fill(1.0,ny)` : `ymin` softness weights ``\mathbf{c_{y_{min}}}``
10796
- `c_ymax=fill(1.0,ny)` : `ymax` softness weights ``\mathbf{c_{y_{max}}}``
97+
- all keyword arguments above but with a capital letter e.g. `Ymax` or `c_ΔUmin` : for
98+
time-varying constraints (see Extended Help)
10899
109100
# Examples
110101
```jldoctest
@@ -122,6 +113,30 @@ LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, SteadyKalmanFil
122113
0 unmeasured outputs yu
123114
0 measured disturbances d
124115
```
116+
117+
# Extended Help
118+
The bounds can be modified after calling [`moveinput!`](@ref), that is at runtime, but not
119+
the softness parameters ``\mathbf{c}``. It is not possible to modify `±Inf` constraints
120+
at runtime.
121+
122+
!!! tip
123+
To keep a variable unconstrained while maintaining the ability to add a constraint later
124+
at runtime, set the bound to an absolute value sufficiently large when you create the
125+
controller.
126+
127+
It is also possible to specify time-varying constraints over prediction ``H_p`` and control
128+
``H_c`` horizons. In such a case, they are defined by:
129+
```math
130+
\begin{alignat*}{3}
131+
\mathbf{U_{min} - c_{U_{min}}} ϵ &≤ \mathbf{U} &&≤ \mathbf{U_{max} + c_{U_{max}}} ϵ \\
132+
\mathbf{ΔU_{min} - c_{ΔU_{min}}} ϵ &≤ \mathbf{ΔU} &&≤ \mathbf{ΔU_{max} + c_{ΔY_{max}}} ϵ \\
133+
\mathbf{Y_{min} - c_{Y_{min}}} ϵ &≤ \mathbf{Ŷ} &&≤ \mathbf{Y_{max} + c_{Y_{max}}} ϵ
134+
\end{alignat*}
135+
```
136+
For this, use the same keyword arguments as above but with a capital letter:
137+
- `Umin` \ `Umax` \ `c_Umin` \ `c_Umax` : ``\mathbf{U}`` constraints `(nu*Hp,)`.
138+
- `ΔUmin` \ `ΔUmax` \ `c_ΔUmin` \ `c_ΔUmax` : ``\mathbf{ΔU}`` constraints `(nu*Hc,)`.
139+
- `Ymin` \ `Ymax` \ `c_Ymin` \ `c_Ymax` : ``\mathbf{Ŷ}`` constraints `(nu*Hp,)`.
125140
"""
126141
function setconstraint!(
127142
mpc::PredictiveController;
@@ -131,20 +146,18 @@ function setconstraint!(
131146
c_umin = nothing, c_umax = nothing,
132147
c_Δumin = nothing, c_Δumax = nothing,
133148
c_ymin = nothing, c_ymax = nothing,
134-
# will be deleted in the future:
149+
Umin = nothing, Umax = nothing,
150+
ΔUmin = nothing, ΔUmax = nothing,
151+
Ymin = nothing, Ymax = nothing,
152+
c_Umax = nothing, c_Umin = nothing,
153+
c_ΔUmax = nothing, c_ΔUmin = nothing,
154+
c_Ymax = nothing, c_Ymin = nothing,
155+
# ------------ will be deleted in the future ---------------
135156
ŷmin = nothing, ŷmax = nothing,
136157
c_ŷmin = nothing, c_ŷmax = nothing,
158+
# ----------------------------------------------------------
137159
)
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)
141-
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
146-
147-
# these 4 `if`s will be deleted in the future:
160+
# ----- these 4 `if`s will be deleted in the future --------
148161
if !isnothing(ŷmin)
149162
Base.depwarn("keyword arg ŷmin is deprecated, use ymin instead", :setconstraint!)
150163
ymin = ŷmin
@@ -161,81 +174,89 @@ function setconstraint!(
161174
Base.depwarn("keyword arg ŷmax is deprecated, use ymax instead", :setconstraint!)
162175
c_ymax = c_ŷmax
163176
end
164-
165-
if !isnothing(umin)
166-
size(umin) == (nu,) || throw(ArgumentError("umin size must be $((nu,))"))
167-
Umin = repeat(umin, Hp)
177+
# ----------------------------------------------------------
178+
model, con, optim = mpc.estim.model, mpc.con, mpc.optim
179+
nu, ny, Hp, Hc = model.nu, model.ny, mpc.Hp, mpc.Hc
180+
notSolvedYet = (termination_status(optim) == OPTIMIZE_NOT_CALLED)
181+
C, E = mpc.C, mpc.Ẽ[:, 1:nu*Hc]
182+
isnothing(Umin) && !isnothing(umin) && (Umin = repeat(umin, Hp))
183+
isnothing(Umax) && !isnothing(umax) && (Umax = repeat(umax, Hp))
184+
isnothing(ΔUmin) && !isnothing(Δumin) && (ΔUmin = repeat(Δumin, Hc))
185+
isnothing(ΔUmax) && !isnothing(Δumax) && (ΔUmax = repeat(Δumax, Hc))
186+
isnothing(Ymin) && !isnothing(ymin) && (Ymin = repeat(ymin, Hp))
187+
isnothing(Ymax) && !isnothing(ymax) && (Ymax = repeat(ymax, Hp))
188+
isnothing(c_Umin) && !isnothing(c_umin) && (c_Umin = repeat(c_umin, Hp))
189+
isnothing(c_Umax) && !isnothing(c_umax) && (c_Umax = repeat(c_umax, Hp))
190+
isnothing(c_ΔUmin) && !isnothing(c_Δumin) && (c_ΔUmin = repeat(c_Δumin, Hc))
191+
isnothing(c_ΔUmax) && !isnothing(c_Δumax) && (c_ΔUmax = repeat(c_Δumax, Hc))
192+
isnothing(c_Ymin) && !isnothing(c_ymin) && (c_Ymin = repeat(c_ymin, Hp))
193+
isnothing(c_Ymax) && !isnothing(c_ymax) && (c_Ymax = repeat(c_ymax, Hp))
194+
if !all(isnothing.([c_Umin, c_Umax, c_ΔUmin, c_ΔUmax, c_Ymin, c_Ymax]))
195+
!isinf(C) || throw(ArgumentError("Slack variable Cwt must be finite to set softness parameters"))
196+
notSolvedYet || error("Cannot set softness parameters after calling moveinput!")
197+
end
198+
if !isnothing(Umin)
199+
size(Umin) == (nu*Hp,) || throw(ArgumentError("Umin size must be $((nu*Hp,))"))
168200
con.Umin[:] = Umin
169201
end
170-
if !isnothing(umax)
171-
size(umax) == (nu,) || throw(ArgumentError("umax size must be $((nu,))"))
172-
Umax = repeat(umax, Hp)
202+
if !isnothing(Umax)
203+
size(Umax) == (nu*Hp,) || throw(ArgumentError("Umax size must be $((nu*Hp,))"))
173204
con.Umax[:] = Umax
174205
end
175-
if !isnothing(Δumin)
176-
size(Δumin) == (nu,) || throw(ArgumentError("Δumin size must be $((nu,))"))
177-
ΔUmin = repeat(Δumin, Hc)
206+
if !isnothing(ΔUmin)
207+
size(ΔUmin) == (nu*Hc,) || throw(ArgumentError("ΔUmin size must be $((nu*Hc,))"))
178208
con.ΔŨmin[1:nu*Hc] = ΔUmin
179209
end
180-
if !isnothing(Δumax)
181-
size(Δumax) == (nu,) || throw(ArgumentError("Δumax size must be $((nu,))"))
182-
ΔUmax = repeat(Δumax, Hc)
210+
if !isnothing(ΔUmax)
211+
size(ΔUmax) == (nu*Hc,) || throw(ArgumentError("ΔUmax size must be $((nu*Hc,))"))
183212
con.ΔŨmax[1:nu*Hc] = ΔUmax
184213
end
185-
if !isnothing(ymin)
186-
size(ymin) == (ny,) || throw(ArgumentError("ymin size must be $((ny,))"))
187-
Ymin = repeat(ymin, Hp)
214+
if !isnothing(Ymin)
215+
size(Ymin) == (ny*Hp,) || throw(ArgumentError("Ymin size must be $((ny*Hp,))"))
188216
con.Ymin[:] = Ymin
189217
end
190-
if !isnothing(ymax)
191-
size(ymax) == (ny,) || throw(ArgumentError("ymax size must be $((ny,))"))
192-
Ymax = repeat(ymax, Hp)
218+
if !isnothing(Ymax)
219+
size(Ymax) == (ny*Hp,) || throw(ArgumentError("Ymax size must be $((ny*Hp,))"))
193220
con.Ymax[:] = Ymax
194221
end
195-
if !isnothing(c_umin)
196-
size(c_umin) == (nu,) || throw(ArgumentError("c_umin size must be $((nu,))"))
197-
any(c_umin .< 0) && error("c_umin weights should be non-negative")
198-
c_Umin = repeat(c_umin, Hp)
222+
if !isnothing(c_Umin)
223+
size(c_Umin) == (nu*Hp,) || throw(ArgumentError("c_Umin size must be $((nu*Hp,))"))
224+
any(c_Umin .< 0) && error("c_Umin weights should be non-negative")
199225
con.A_Umin[:, end] = -c_Umin
200226
end
201-
if !isnothing(c_umax)
202-
size(c_umax) == (nu,) || throw(ArgumentError("c_umax size must be $((nu,))"))
203-
any(c_umax .< 0) && error("c_umax weights should be non-negative")
204-
c_Umax = repeat(c_umax, Hp)
227+
if !isnothing(c_Umax)
228+
size(c_Umax) == (nu*Hp,) || throw(ArgumentError("c_Umax size must be $((nu*Hp,))"))
229+
any(c_Umax .< 0) && error("c_Umax weights should be non-negative")
205230
con.A_Umax[:, end] = -c_Umax
206231
end
207-
if !isnothing(c_Δumin)
208-
size(c_Δumin) == (nu,) || throw(ArgumentError("c_Δumin size must be $((nu,))"))
209-
any(c_Δumin .< 0) && error("c_Δumin weights should be non-negative")
210-
c_ΔUmin = repeat(c_Δumin, Hc)
232+
if !isnothing(c_ΔUmin)
233+
size(c_ΔUmin) == (nu*Hc,) || throw(ArgumentError("c_ΔUmin size must be $((nu*Hc,))"))
234+
any(c_ΔUmin .< 0) && error("c_ΔUmin weights should be non-negative")
211235
con.A_ΔŨmin[1:end-1, end] = -c_ΔUmin
212236
end
213-
if !isnothing(c_Δumax)
214-
size(c_Δumax) == (nu,) || throw(ArgumentError("c_Δumax size must be $((nu,))"))
215-
any(c_Δumax .< 0) && error("c_Δumax weights should be non-negative")
216-
c_ΔUmax = repeat(c_Δumax, Hc)
237+
if !isnothing(c_ΔUmax)
238+
size(c_ΔUmax) == (nu*Hc,) || throw(ArgumentError("c_ΔUmax size must be $((nu*Hc,))"))
239+
any(c_ΔUmax .< 0) && error("c_ΔUmax weights should be non-negative")
217240
con.A_ΔŨmax[1:end-1, end] = -c_ΔUmax
218241
end
219-
if !isnothing(c_ymin)
220-
size(c_ymin) == (ny,) || throw(ArgumentError("c_ymin size must be $((ny,))"))
221-
any(c_ymin .< 0) && error("c_ymin weights should be non-negative")
222-
c_Ymin = repeat(c_ymin, Hp)
242+
if !isnothing(c_Ymin)
243+
size(c_Ymin) == (ny*Hp,) || throw(ArgumentError("c_Ymin size must be $((ny*Hp,))"))
244+
any(c_Ymin .< 0) && error("c_Ymin weights should be non-negative")
223245
con.c_Ymin[:] = c_Ymin
224246
A_Ymin ,_ = relaxŶ(model, C, con.c_Ymin, con.c_Ymax, E)
225247
con.A_Ymin[:] = A_Ymin
226248
end
227-
if !isnothing(c_ymax)
228-
size(c_ymax) == (ny,) || throw(ArgumentError("c_ymax size must be $((ny,))"))
229-
any(c_ymax .< 0) && error("c_ymax weights should be non-negative")
230-
c_Ymax = repeat(c_ymax, Hp)
249+
if !isnothing(c_Ymax)
250+
size(c_Ymax) == (ny*Hp,) || throw(ArgumentError("c_Ymax size must be $((ny*Hp,))"))
251+
any(c_Ymax .< 0) && error("c_Ymax weights should be non-negative")
231252
con.c_Ymax[:] = c_Ymax
232253
_, A_Ymax = relaxŶ(model, C, con.c_Ymin, con.c_Ymax, E)
233254
con.A_Ymax[:] = A_Ymax
234255
end
235256
i_Umin, i_Umax = .!isinf.(con.Umin), .!isinf.(con.Umax)
236257
i_ΔŨmin, i_ΔŨmax = .!isinf.(con.ΔŨmin), .!isinf.(con.ΔŨmin)
237258
i_Ymin, i_Ymax = .!isinf.(con.Ymin), .!isinf.(con.Ymax)
238-
if notSolvedYet
259+
if notSolvedYet
239260
con.i_b[:], con.A[:] = init_linconstraint(model,
240261
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax,
241262
con.A_Umin, con.A_Umax, con.A_ΔŨmin, con.A_ΔŨmax, con.A_Ymin, con.A_Ymax
@@ -1008,7 +1029,7 @@ function init_stochpred(estim::InternalModel, Hp)
10081029
return Ks, Ps
10091030
end
10101031
"Return empty matrices if `estim` is not a [`InternalModel`](@ref)."
1011-
init_stochpred(::StateEstimator, _ ) = zeros(0, 0), zeros(0, 0)
1032+
init_stochpred(estim::StateEstimator, _ ) = zeros(0, estim.nxs), zeros(0, estim.model.ny)
10121033

10131034

10141035
@doc raw"""

test/test_predictive_control.jl

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,48 @@ end
123123
@test all((-mpc.con.A_Ymin[:, end], -mpc.con.A_Ymax[:, end]) .≈ ([1.00,1.01], [1.02,1.03]))
124124

125125
model2 = LinModel(tf([2], [10, 1]), 3.0)
126-
mpc2 = LinMPC(model2, Hp=25, Hc=2)
126+
mpc2 = LinMPC(model2, Hp=50, Hc=5)
127+
setconstraint!(mpc2, Umin=-1(1:50).-1, Umax=+1(1:50).+1)
128+
@test all((mpc2.con.Umin, mpc2.con.Umax) .≈ (-1(1:50).-1, +1(1:50).+1))
129+
setconstraint!(mpc2, ΔUmin=-1(1:5).-2, ΔUmax=+1(1:5).+2)
130+
@test all((mpc2.con.ΔŨmin, mpc2.con.ΔŨmax) .≈ ([-1(1:5).-2; 0], [+1(1:5).+2; Inf]))
131+
setconstraint!(mpc2, Ymin=-1(1:50).-3, Ymax=+1(1:50).+3)
132+
@test all((mpc2.con.Ymin, mpc2.con.Ymax) .≈ (-1(1:50).-3, +1(1:50).+3))
133+
setconstraint!(mpc2, c_Umin=+1(1:50).+4, c_Umax=+1(1:50).+4)
134+
@test all((-mpc2.con.A_Umin[:, end], -mpc2.con.A_Umax[:, end]) .≈ (+1(1:50).+4, +1(1:50).+4))
135+
setconstraint!(mpc2, c_ΔUmin=+1(1:5).+5, c_ΔUmax=+1(1:5).+5)
136+
@test all((-mpc2.con.A_ΔŨmin[1:end-1, end], -mpc2.con.A_ΔŨmax[1:end-1, end]) .≈ (+1(1:5).+5, +1(1:5).+5))
137+
setconstraint!(mpc2, c_Ymin=+1(1:50).+6, c_Ymax=+1(1:50).+6)
138+
@test all((-mpc2.con.A_Ymin[:, end], -mpc2.con.A_Ymax[:, end]) .≈ (+1(1:50).+6, +1(1:50).+6))
139+
setconstraint!(mpc2, c_umin=[0], c_umax=[0], c_Δumin=[0], c_Δumax=[0], c_ymin=[1], c_ymax=[1])
140+
141+
127142
setconstraint!(mpc2, umin=[-3], umax=[3])
128143
setconstraint!(mpc2, Δumin=[-1.5], Δumax=[1.5])
129144
setconstraint!(mpc2, ymin=[-100], ymax=[100])
130-
moveinput!(mpc2, [-20])
145+
moveinput!(mpc2, [-10])
131146
info = getinfo(mpc2)
132147
@test info[:ΔU][begin] -1.5 atol=1e-2
133148
@test info[:U][end] -3 atol=1e-2
149+
150+
134151
setconstraint!(mpc2, umin=[-10], umax=[10])
135152
setconstraint!(mpc2, Δumin=[-15], Δumax=[15])
136153
setconstraint!(mpc2, ymin=[-0.5], ymax=[0.5])
137-
moveinput!(mpc2, [-20])
154+
moveinput!(mpc2, [-10])
138155
info = getinfo(mpc2)
139156
@test info[:Ŷ][end] -0.5 atol=1e-2
140157

158+
159+
setconstraint!(mpc2, umin=[-10], umax=[10])
160+
setconstraint!(mpc2, Δumin=[-15], Δumax=[15])
161+
setconstraint!(mpc2, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
162+
moveinput!(mpc2, [-10])
163+
info = getinfo(mpc2)
164+
@test info[:Ŷ][end] -10 atol=1e-2
165+
@test info[:Ŷ][begin] -0.5 atol=1e-2
166+
167+
141168
@test_throws ArgumentError setconstraint!(mpc, umin=[0,0,0])
142169
@test_throws ArgumentError setconstraint!(mpc, umax=[0,0,0])
143170
@test_throws ArgumentError setconstraint!(mpc, Δumin=[0,0,0])
@@ -401,37 +428,57 @@ end
401428
@test all((nmpc.con.c_Ymin, nmpc.con.c_Ymax) .≈ ([1.00,1.01], [1.02,1.03]))
402429

403430
linmodel2 = LinModel(tf([2], [10, 1]), 3.0)
404-
nmpc_lin2 = NonLinMPC(linmodel2, Hp=25, Hc=2)
431+
nmpc_lin2 = NonLinMPC(linmodel2, Hp=50, Hc=5)
432+
405433
setconstraint!(nmpc_lin2, umin=[-3], umax=[3])
406434
setconstraint!(nmpc_lin2, Δumin=[-1.5], Δumax=[1.5])
407435
setconstraint!(nmpc_lin2, ymin=[-100], ymax=[100])
408436
moveinput!(nmpc_lin2, [-20])
409437
info = getinfo(nmpc_lin2)
410438
@test info[:ΔU][begin] -1.5 atol=1e-2
411439
@test info[:U][end] -3 atol=1e-2
440+
412441
setconstraint!(nmpc_lin2, umin=[-10], umax=[10])
413442
setconstraint!(nmpc_lin2, Δumin=[-15], Δumax=[15])
414443
setconstraint!(nmpc_lin2, ymin=[-0.5], ymax=[0.5])
415444
moveinput!(nmpc_lin2, [-20])
416445
info = getinfo(nmpc_lin2)
417446
@test info[:Ŷ][end] -0.5 atol=1e-2
418447

448+
setconstraint!(nmpc_lin2, umin=[-10], umax=[10])
449+
setconstraint!(nmpc_lin2, Δumin=[-15], Δumax=[15])
450+
setconstraint!(nmpc_lin2, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
451+
moveinput!(nmpc_lin2, [-10])
452+
info = getinfo(nmpc_lin2)
453+
@test info[:Ŷ][end] -10 atol=1e-2
454+
@test info[:Ŷ][begin] -0.5 atol=1e-2
455+
419456
f2(x,u,_) = linmodel2.A*x + linmodel2.Bu*u
420457
h2(x,_) = linmodel2.C*x
421458
nonlinmodel2 = NonLinModel(f2, h2, Ts, 1, 1, 1)
422-
nmpc2 = NonLinMPC(nonlinmodel2, Hp=25, Hc=2)
459+
nmpc2 = NonLinMPC(nonlinmodel2, Hp=50, Hc=5)
460+
423461
setconstraint!(nmpc2, umin=[-3], umax=[3])
424462
setconstraint!(nmpc2, Δumin=[-1.5], Δumax=[1.5])
425463
setconstraint!(nmpc2, ymin=[-100], ymax=[100])
426464
moveinput!(nmpc2, [-20])
427465
info = getinfo(nmpc2)
428466
@test info[:ΔU][begin] -1.5 atol=1e-2
429467
@test info[:U][end] -3 atol=1e-2
468+
430469
setconstraint!(nmpc2, umin=[-10], umax=[10])
431470
setconstraint!(nmpc2, Δumin=[-15], Δumax=[15])
432471
setconstraint!(nmpc2, ymin=[-0.5], ymax=[0.5])
433472
moveinput!(nmpc2, [-20])
434473
info = getinfo(nmpc2)
435474
@test info[:Ŷ][end] -0.5 atol=1e-2
436475

476+
setconstraint!(nmpc2, umin=[-10], umax=[10])
477+
setconstraint!(nmpc2, Δumin=[-15], Δumax=[15])
478+
setconstraint!(nmpc2, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
479+
moveinput!(nmpc2, [-10])
480+
info = getinfo(nmpc2)
481+
@test info[:Ŷ][end] -10 atol=1e-2
482+
@test info[:Ŷ][begin] -0.5 atol=1e-2
483+
437484
end

0 commit comments

Comments
 (0)