Skip to content

Commit 957a028

Browse files
committed
test: improve constraint violation tests (to catch the last bug)
- verify that the constraint are not violated over all the horizons - use different upper and lower bound values to catch copy-paste error
1 parent a3940fb commit 957a028

File tree

2 files changed

+127
-120
lines changed

2 files changed

+127
-120
lines changed

src/controller/construct.jl

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -459,29 +459,30 @@ are calculated by:
459459
The ``\mathbf{S}`` and ``\mathbf{T}`` matrices are defined in the Extended Help section.
460460
461461
# Extended Help
462-
The ``\mathbf{U}`` vector and the two conversion matrices are defined as:
463-
```math
464-
\mathbf{U} = \begin{bmatrix}
465-
\mathbf{u}(k + 0) \\
466-
\mathbf{u}(k + 1) \\
467-
\vdots \\
468-
\mathbf{u}(k + H_c - 1) \\
469-
\vdots \\
470-
\mathbf{u}(k + H_p - 1) \end{bmatrix} , \quad
471-
\mathbf{S} = \begin{bmatrix}
472-
\mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\
473-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{0} \\
474-
\vdots & \vdots & \ddots & \vdots \\
475-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \\
476-
\vdots & \vdots & \ddots & \vdots \\
477-
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \end{bmatrix} , \quad
478-
\mathbf{T} = \begin{bmatrix}
479-
\mathbf{I} \\
480-
\mathbf{I} \\
481-
\vdots \\
482-
\mathbf{I} \\
483-
\vdots \\
484-
\mathbf{I} \end{bmatrix}
462+
!!! details "Extended Help"
463+
The ``\mathbf{U}`` vector and the two conversion matrices are defined as:
464+
```math
465+
\mathbf{U} = \begin{bmatrix}
466+
\mathbf{u}(k + 0) \\
467+
\mathbf{u}(k + 1) \\
468+
\vdots \\
469+
\mathbf{u}(k + H_c - 1) \\
470+
\vdots \\
471+
\mathbf{u}(k + H_p - 1) \end{bmatrix} , \quad
472+
\mathbf{S} = \begin{bmatrix}
473+
\mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\
474+
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{0} \\
475+
\vdots & \vdots & \ddots & \vdots \\
476+
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \\
477+
\vdots & \vdots & \ddots & \vdots \\
478+
\mathbf{I} & \mathbf{I} & \cdots & \mathbf{I} \end{bmatrix} , \quad
479+
\mathbf{T} = \begin{bmatrix}
480+
\mathbf{I} \\
481+
\mathbf{I} \\
482+
\vdots \\
483+
\mathbf{I} \\
484+
\vdots \\
485+
\mathbf{I} \end{bmatrix}
485486
```
486487
"""
487488
function init_ΔUtoU(model::SimModel{NT}, Hp, Hc) where {NT<:Real}

test/test_predictive_control.jl

Lines changed: 103 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -221,52 +221,58 @@ end
221221
model = LinModel(tf([2], [10, 1]), 3.0)
222222
mpc = LinMPC(model, Hp=50, Hc=5)
223223

224-
setconstraint!(mpc, x̂min=[-1e3,-Inf], x̂max=[1e3,+Inf])
225-
setconstraint!(mpc, umin=[-3], umax=[3])
226-
setconstraint!(mpc, Δumin=[-1.5], Δumax=[1.5])
224+
setconstraint!(mpc, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf])
225+
setconstraint!(mpc, umin=[-10], umax=[10])
226+
setconstraint!(mpc, Δumin=[-15], Δumax=[15])
227227
setconstraint!(mpc, ymin=[-100], ymax=[100])
228228
preparestate!(mpc, [0])
229-
moveinput!(mpc, [-10])
229+
230+
setconstraint!(mpc, umin=[-3], umax=[4])
231+
moveinput!(mpc, [-100])
230232
info = getinfo(mpc)
231-
@test info[:ΔU][begin] -1.5 atol=1e-1
232-
@test info[:U][end] -3 atol=1e-1
233-
moveinput!(mpc, [10])
233+
@test all(isapprox.(info[:U], -3; atol=1e-1))
234+
moveinput!(mpc, [100])
234235
info = getinfo(mpc)
235-
@test info[:ΔU][begin] 1.5 atol=1e-1
236-
@test info[:U][end] 3 atol=1e-1
237-
236+
@test all(isapprox.(info[:U], 4; atol=1e-1))
238237
setconstraint!(mpc, umin=[-10], umax=[10])
238+
239+
setconstraint!(mpc, Δumin=[-1.5], Δumax=[1.25])
240+
moveinput!(mpc, [-100])
241+
info = getinfo(mpc)
242+
@test all(isapprox.(info[:ΔU], -1.5; atol=1e-1))
243+
moveinput!(mpc, [100])
244+
info = getinfo(mpc)
245+
@test all(isapprox.(info[:ΔU], 1.25; atol=1e-1))
239246
setconstraint!(mpc, Δumin=[-15], Δumax=[15])
240-
setconstraint!(mpc, ymin=[-0.5], ymax=[0.5])
241-
moveinput!(mpc, [-10])
247+
248+
setconstraint!(mpc, ymin=[-0.5], ymax=[0.9])
249+
moveinput!(mpc, [-100])
242250
info = getinfo(mpc)
243-
@test info[:Ŷ][end] -0.5 atol=1e-1
244-
moveinput!(mpc, [10])
251+
@test all(isapprox.(info[:Ŷ], -0.5; atol=1e-1))
252+
moveinput!(mpc, [100])
245253
info = getinfo(mpc)
246-
@test info[:Ŷ][end] 0.5 atol=1e-1
254+
@test all(isapprox.(info[:Ŷ], 0.9; atol=1e-1))
255+
setconstraint!(mpc, ymin=[-100], ymax=[100])
247256

248-
setconstraint!(mpc, umin=[-10], umax=[10])
249-
setconstraint!(mpc, Δumin=[-15], Δumax=[15])
250-
setconstraint!(mpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
257+
setconstraint!(mpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.9; fill(+100, 49)])
251258
moveinput!(mpc, [-10])
252259
info = getinfo(mpc)
253-
@test info[:Ŷ][end] -10 atol=1e-1
254260
@test info[:Ŷ][begin] -0.5 atol=1e-1
261+
@test info[:Ŷ][end] -10 atol=1e-1
255262
moveinput!(mpc, [10])
256263
info = getinfo(mpc)
264+
@test info[:Ŷ][begin] 0.9 atol=1e-1
257265
@test info[:Ŷ][end] 10 atol=1e-1
258-
@test info[:Ŷ][begin] 0.5 atol=1e-1
266+
setconstraint!(mpc, ymin=[-100], ymax=[100])
259267

260-
setconstraint!(mpc, umin=[-1e3], umax=[+1e3])
261-
setconstraint!(mpc, Δumin=[-1e3], Δumax=[+1e3])
262-
setconstraint!(mpc, ymin=[-1e3], ymax=[+1e3])
263268
setconstraint!(mpc, x̂min=[-1e-6,-Inf], x̂max=[+1e-6,+Inf])
264-
moveinput!(mpc, [-10])
269+
moveinput!(mpc, [-100])
265270
info = getinfo(mpc)
266271
@test info[:x̂end][1] 0 atol=1e-1
267-
moveinput!(mpc, [10])
272+
moveinput!(mpc, [100])
268273
info = getinfo(mpc)
269274
@test info[:x̂end][1] 0 atol=1e-1
275+
setconstraint!(mpc, x̂min=[-1e6,-Inf], x̂max=[+1e6,+Inf])
270276
end
271277

272278
@testset "LinMPC terminal cost" begin
@@ -719,138 +725,138 @@ end
719725
linmodel = LinModel(tf([2], [10000, 1]), 3000.0)
720726
nmpc_lin = NonLinMPC(linmodel, Hp=50, Hc=5, gc=gc, nc=2*(50+1), p=[0; 0])
721727

722-
setconstraint!(nmpc_lin, x̂min=[-1e3,-Inf], x̂max=[1e3,+Inf])
723-
setconstraint!(nmpc_lin, umin=[-3], umax=[3])
724-
setconstraint!(nmpc_lin, Δumin=[-1.5], Δumax=[1.5])
728+
setconstraint!(nmpc_lin, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf])
729+
setconstraint!(nmpc_lin, umin=[-10], umax=[10])
730+
setconstraint!(nmpc_lin, Δumin=[-15], Δumax=[15])
725731
setconstraint!(nmpc_lin, ymin=[-100], ymax=[100])
726732
preparestate!(nmpc_lin, [0])
727-
moveinput!(nmpc_lin, [-20])
733+
734+
setconstraint!(nmpc_lin, umin=[-3], umax=[4])
735+
moveinput!(nmpc_lin, [-100])
728736
info = getinfo(nmpc_lin)
729-
@test info[:ΔU][begin] -1.5 atol=1e-1
730-
@test info[:U][end] -3 atol=1e-1
731-
moveinput!(nmpc_lin, [20])
737+
@test all(isapprox.(info[:U], -3; atol=1e-1))
738+
moveinput!(nmpc_lin, [100])
732739
info = getinfo(nmpc_lin)
733-
@test info[:ΔU][begin] 1.5 atol=1e-1
734-
@test info[:U][end] 3 atol=1e-1
735-
740+
@test all(isapprox.(info[:U], 4; atol=1e-1))
736741
setconstraint!(nmpc_lin, umin=[-10], umax=[10])
742+
743+
setconstraint!(nmpc_lin, Δumin=[-1.5], Δumax=[1.25])
744+
moveinput!(nmpc_lin, [-100])
745+
info = getinfo(nmpc_lin)
746+
@test all(isapprox.(info[:ΔU], -1.5; atol=1e-1))
747+
moveinput!(nmpc_lin, [100])
748+
info = getinfo(nmpc_lin)
749+
@test all(isapprox.(info[:ΔU], 1.25; atol=1e-1))
737750
setconstraint!(nmpc_lin, Δumin=[-15], Δumax=[15])
738-
setconstraint!(nmpc_lin, ymin=[-0.5], ymax=[0.5])
739-
moveinput!(nmpc_lin, [-20])
751+
752+
setconstraint!(nmpc_lin, ymin=[-0.5], ymax=[0.9])
753+
moveinput!(nmpc_lin, [-100])
740754
info = getinfo(nmpc_lin)
741-
@test info[:Ŷ][end] -0.5 atol=1e-1
742-
moveinput!(nmpc_lin, [20])
755+
@test all(isapprox.(info[:Ŷ], -0.5; atol=1e-1))
756+
moveinput!(nmpc_lin, [100])
743757
info = getinfo(nmpc_lin)
744-
@test info[:Ŷ][end] 0.5 atol=1e-1
758+
@test all(isapprox.(info[:Ŷ], 0.9; atol=1e-1))
759+
setconstraint!(nmpc_lin, ymin=[-100], ymax=[100])
745760

746-
setconstraint!(nmpc_lin, umin=[-10], umax=[10])
747-
setconstraint!(nmpc_lin, Δumin=[-15], Δumax=[15])
748-
setconstraint!(nmpc_lin, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
761+
setconstraint!(nmpc_lin, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.9; fill(+100, 49)])
749762
moveinput!(nmpc_lin, [-10])
750763
info = getinfo(nmpc_lin)
751764
@test info[:Ŷ][end] -10 atol=1e-1
752765
@test info[:Ŷ][begin] -0.5 atol=1e-1
753766
moveinput!(nmpc_lin, [10])
754767
info = getinfo(nmpc_lin)
755768
@test info[:Ŷ][end] 10 atol=1e-1
756-
@test info[:Ŷ][begin] 0.5 atol=1e-1
769+
@test info[:Ŷ][begin] 0.9 atol=1e-1
770+
setconstraint!(nmpc_lin, ymin=[-100], ymax=[100])
757771

758-
setconstraint!(nmpc_lin, umin=[-1e3], umax=[+1e3])
759-
setconstraint!(nmpc_lin, Δumin=[-1e3], Δumax=[+1e3])
760-
setconstraint!(nmpc_lin, ymin=[-1e3], ymax=[+1e3])
761772
setconstraint!(nmpc_lin, x̂min=[-1e-6,-Inf], x̂max=[+1e-6,+Inf])
762-
moveinput!(nmpc_lin, [-10])
773+
moveinput!(nmpc_lin, [-100])
763774
info = getinfo(nmpc_lin)
764775
@test info[:x̂end][1] 0 atol=1e-1
765-
moveinput!(nmpc_lin, [10])
776+
moveinput!(nmpc_lin, [100])
766777
info = getinfo(nmpc_lin)
767778
@test info[:x̂end][1] 0 atol=1e-1
768-
769-
setconstraint!(nmpc_lin, x̂min=[-1e3,-Inf], x̂max=[1e3,+Inf])
770-
setconstraint!(nmpc_lin, umin=[-10], umax=[10])
771-
setconstraint!(nmpc_lin, Δumin=[-15], Δumax=[15])
772-
setconstraint!(nmpc_lin, ymin=[-100], ymax=[100])
779+
setconstraint!(nmpc_lin, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf])
773780

774781
nmpc_lin.p .= [1; 0]
775-
moveinput!(nmpc_lin, [20])
782+
moveinput!(nmpc_lin, [100])
776783
info = getinfo(nmpc_lin)
777-
@test info[:U][end] 4.2 atol=1e-1
778-
@test info[:U][begin] 4.2 atol=1e-1
784+
@test all(isapprox.(info[:U], 4.2; atol=1e-1))
779785

780786
nmpc_lin.p .= [0; 1]
781-
moveinput!(nmpc_lin, [20])
787+
moveinput!(nmpc_lin, [100])
782788
info = getinfo(nmpc_lin)
783-
@test info[:Ŷ][end] 3.14 atol=1e-1
784-
@test info[:Ŷ][begin] 3.14 atol=1e-1
789+
@test all(isapprox.(info[:Ŷ], 3.14; atol=1e-1))
785790

786-
f = (x,u,_,_) -> linmodel.A*x + linmodel.Bu*u
787-
h = (x,_,_) -> linmodel.C*x
788-
nonlinmodel = NonLinModel(f, h, linmodel.Ts, 1, 1, 1, solver=nothing)
791+
792+
f = (x,u,_,p) -> p.A*x + p.Bu*u
793+
h = (x,_,p) -> p.C*x
794+
nonlinmodel = NonLinModel(f, h, linmodel.Ts, 1, 1, 1, solver=nothing, p=linmodel)
789795
nmpc = NonLinMPC(nonlinmodel, Hp=50, Hc=5, gc=gc, nc=2*(50+1), p=[0; 0])
790796

791-
setconstraint!(nmpc, x̂min=[-1e3,-Inf], x̂max=[1e3,+Inf])
792-
setconstraint!(nmpc, umin=[-3], umax=[3])
793-
setconstraint!(nmpc, Δumin=[-1.5], Δumax=[1.5])
797+
setconstraint!(nmpc, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf])
798+
setconstraint!(nmpc, umin=[-10], umax=[10])
799+
setconstraint!(nmpc, Δumin=[-15], Δumax=[15])
794800
setconstraint!(nmpc, ymin=[-100], ymax=[100])
795801
preparestate!(nmpc, [0])
796-
moveinput!(nmpc, [-20])
802+
803+
setconstraint!(nmpc, umin=[-3], umax=[4])
804+
moveinput!(nmpc, [-100])
797805
info = getinfo(nmpc)
798-
@test info[:ΔU][begin] -1.5 atol=1e-1
799-
@test info[:U][end] -3 atol=1e-1
800-
moveinput!(nmpc, [20])
806+
@test all(isapprox.(info[:U], -3; atol=1e-1))
807+
moveinput!(nmpc, [100])
801808
info = getinfo(nmpc)
802-
@test info[:ΔU][begin] 1.5 atol=1e-1
803-
@test info[:U][end] 3 atol=1e-1
804-
809+
@test all(isapprox.(info[:U], 4; atol=1e-1))
805810
setconstraint!(nmpc, umin=[-10], umax=[10])
806-
setconstraint!(nmpc, Δumin=[-15], Δumax=[15])
807-
setconstraint!(nmpc, ymin=[-0.5], ymax=[0.5])
808-
moveinput!(nmpc, [-20])
811+
812+
setconstraint!(nmpc, Δumin=[-1.5], Δumax=[1.25])
813+
moveinput!(nmpc, [-100])
809814
info = getinfo(nmpc)
810-
@test info[:][end] -0.5 atol=1e-1
811-
moveinput!(nmpc, [20])
815+
@test all(isapprox.(info[:ΔU], -1.5; atol=1e-1))
816+
moveinput!(nmpc, [100])
812817
info = getinfo(nmpc)
813-
@test info[:Ŷ][end] 0.5 atol=1e-1
814-
815-
setconstraint!(nmpc, umin=[-10], umax=[10])
818+
@test all(isapprox.(info[:ΔU], 1.25; atol=1e-1))
816819
setconstraint!(nmpc, Δumin=[-15], Δumax=[15])
817-
setconstraint!(nmpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.5; fill(+100, 49)])
820+
821+
setconstraint!(nmpc, ymin=[-0.5], ymax=[0.9])
822+
moveinput!(nmpc, [-100])
823+
info = getinfo(nmpc)
824+
@test all(isapprox.(info[:Ŷ], -0.5; atol=1e-1))
825+
moveinput!(nmpc, [100])
826+
info = getinfo(nmpc)
827+
@test all(isapprox.(info[:Ŷ], 0.9; atol=1e-1))
828+
setconstraint!(nmpc, ymin=[-100], ymax=[100])
829+
830+
setconstraint!(nmpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.9; fill(+100, 49)])
818831
moveinput!(nmpc, [-10])
819832
info = getinfo(nmpc)
820833
@test info[:Ŷ][end] -10 atol=1e-1
821834
@test info[:Ŷ][begin] -0.5 atol=1e-1
822835
moveinput!(nmpc, [10])
823836
info = getinfo(nmpc)
824837
@test info[:Ŷ][end] 10 atol=1e-1
825-
@test info[:Ŷ][begin] 0.5 atol=1e-1
838+
@test info[:Ŷ][begin] 0.9 atol=1e-1
839+
setconstraint!(nmpc, ymin=[-100], ymax=[100])
826840

827-
setconstraint!(nmpc, umin=[-1e3], umax=[+1e3])
828-
setconstraint!(nmpc, Δumin=[-1e3], Δumax=[+1e3])
829-
setconstraint!(nmpc, ymin=[-1e3], ymax=[+1e3])
830841
setconstraint!(nmpc, x̂min=[-1e-6,-Inf], x̂max=[+1e-6,+Inf])
831842
moveinput!(nmpc, [-10])
832843
info = getinfo(nmpc)
833844
@test info[:x̂end][1] 0 atol=1e-1
834845
moveinput!(nmpc, [10])
835846
info = getinfo(nmpc)
836847
@test info[:x̂end][1] 0 atol=1e-1
837-
838-
setconstraint!(nmpc, x̂min=[-1e3,-Inf], x̂max=[1e3,+Inf])
839-
setconstraint!(nmpc, umin=[-10], umax=[10])
840-
setconstraint!(nmpc, Δumin=[-15], Δumax=[15])
841-
setconstraint!(nmpc, ymin=[-100], ymax=[100])
848+
setconstraint!(nmpc, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf])
842849

843850
nmpc.p .= [1; 0]
844-
moveinput!(nmpc, [20])
851+
moveinput!(nmpc, [100])
845852
info = getinfo(nmpc)
846-
@test info[:U][end] 4.2 atol=1e-1
847-
@test info[:U][begin] 4.2 atol=1e-1
853+
@test all(isapprox.(info[:U], 4.2; atol=1e-1))
848854

849855
nmpc.p .= [0; 1]
850-
moveinput!(nmpc, [20])
856+
moveinput!(nmpc, [100])
851857
info = getinfo(nmpc)
852-
@test info[:Ŷ][end] 3.14 atol=1e-1
853-
@test info[:Ŷ][begin] 3.14 atol=1e-1
858+
@test all(isapprox.(info[:Ŷ], 3.14; atol=1e-1))
859+
854860
end
855861

856862
@testset "NonLinMPC set model" begin

0 commit comments

Comments
 (0)