From 47e531c65bd5f0e13e2ada35dc146add079939af Mon Sep 17 00:00:00 2001 From: franckgaga Date: Tue, 23 Jun 2026 17:04:21 -0400 Subject: [PATCH] test: improve coverage of `LinMPC` constraint violation --- test/3_test_predictive_control.jl | 119 +++++++++++++++++------------- 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/test/3_test_predictive_control.jl b/test/3_test_predictive_control.jl index bd0488513..d9c590d99 100644 --- a/test/3_test_predictive_control.jl +++ b/test/3_test_predictive_control.jl @@ -391,60 +391,77 @@ end @testitem "LinMPC constraint violation" setup=[SetupMPCtests] begin using .SetupMPCtests, ControlSystemsBase, LinearAlgebra model = LinModel(tf([2], [10, 1]), 3.0) - mpc = LinMPC(model, Hp=50, Hc=5) + mpc_soft = LinMPC(model, Hp=50, Hc=5, Cwt=1e5) - setconstraint!(mpc, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf]) - setconstraint!(mpc, umin=[-10], umax=[10]) - setconstraint!(mpc, Δumin=[-15], Δumax=[15]) - setconstraint!(mpc, ymin=[-100], ymax=[100]) - preparestate!(mpc, [0]) - - setconstraint!(mpc, umin=[-3], umax=[4]) - moveinput!(mpc, [-100]) - info = getinfo(mpc) - @test all(isapprox.(info[:U], -3; atol=1e-1)) - moveinput!(mpc, [100]) - info = getinfo(mpc) - @test all(isapprox.(info[:U], 4; atol=1e-1)) - setconstraint!(mpc, umin=[-10], umax=[10]) - - setconstraint!(mpc, Δumin=[-1.5], Δumax=[1.25]) - moveinput!(mpc, [-100]) - info = getinfo(mpc) - @test all(isapprox.(info[:ΔU], -1.5; atol=1e-1)) - moveinput!(mpc, [100]) - info = getinfo(mpc) - @test all(isapprox.(info[:ΔU], 1.25; atol=1e-1)) - setconstraint!(mpc, Δumin=[-15], Δumax=[15]) - - setconstraint!(mpc, ymin=[-0.5], ymax=[0.9]) - moveinput!(mpc, [-100]) - info = getinfo(mpc) - @test all(isapprox.(info[:Ŷ], -0.5; atol=1e-1)) - moveinput!(mpc, [100]) - info = getinfo(mpc) - @test all(isapprox.(info[:Ŷ], 0.9; atol=1e-1)) - setconstraint!(mpc, ymin=[-100], ymax=[100]) + setconstraint!(mpc_soft, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf]) + setconstraint!(mpc_soft, umin=[-10], umax=[10]) + setconstraint!(mpc_soft, Δumin=[-15], Δumax=[15]) + setconstraint!(mpc_soft, ymin=[-100], ymax=[100]) + + setconstraint!(mpc_soft, c_x̂min=[1,1], c_x̂max=[1,1]) + setconstraint!(mpc_soft, c_umin=[0.1], c_umax=[0.1]) + setconstraint!(mpc_soft, c_Δumin=[0.1], c_Δumax=[0.1]) + setconstraint!(mpc_soft, c_ymin=[1], c_ymax=[1]) - setconstraint!(mpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.9; fill(+100, 49)]) - moveinput!(mpc, [-10]) - info = getinfo(mpc) - @test info[:Ŷ][begin] ≈ -0.5 atol=1e-1 - @test info[:Ŷ][end] ≈ -10 atol=1e-1 - moveinput!(mpc, [10]) - info = getinfo(mpc) - @test info[:Ŷ][begin] ≈ 0.9 atol=1e-1 - @test info[:Ŷ][end] ≈ 10 atol=1e-1 - setconstraint!(mpc, ymin=[-100], ymax=[100]) + mpc_hard = LinMPC(model, Hp=50, Hc=5, Cwt=Inf) - setconstraint!(mpc, x̂min=[-1e-6,-Inf], x̂max=[+1e-6,+Inf]) - moveinput!(mpc, [-100]) - info = getinfo(mpc) - @test info[:x̂end][1] ≈ 0 atol=1e-1 - moveinput!(mpc, [100]) - info = getinfo(mpc) - @test info[:x̂end][1] ≈ 0 atol=1e-1 - setconstraint!(mpc, x̂min=[-1e6,-Inf], x̂max=[+1e6,+Inf]) + setconstraint!(mpc_hard, x̂min=[-1e6,-Inf], x̂max=[1e6,+Inf]) + setconstraint!(mpc_hard, umin=[-10], umax=[10]) + setconstraint!(mpc_hard, Δumin=[-15], Δumax=[15]) + setconstraint!(mpc_hard, ymin=[-100], ymax=[100]) + + function test_bound_violation(mpc) + preparestate!(mpc, [0]) + + setconstraint!(mpc, umin=[-3], umax=[4]) + moveinput!(mpc, [-100]) + info = getinfo(mpc) + @test all(isapprox.(info[:U], -3; atol=1e-1)) + moveinput!(mpc, [100]) + info = getinfo(mpc) + @test all(isapprox.(info[:U], 4; atol=1e-1)) + setconstraint!(mpc, umin=[-10], umax=[10]) + + setconstraint!(mpc, Δumin=[-1.5], Δumax=[1.25]) + moveinput!(mpc, [-100]) + info = getinfo(mpc) + @test all(isapprox.(info[:ΔU], -1.5; atol=1e-1)) + moveinput!(mpc, [100]) + info = getinfo(mpc) + @test all(isapprox.(info[:ΔU], 1.25; atol=1e-1)) + setconstraint!(mpc, Δumin=[-15], Δumax=[15]) + + setconstraint!(mpc, ymin=[-0.5], ymax=[0.9]) + moveinput!(mpc, [-100]) + info = getinfo(mpc) + @test all(isapprox.(info[:Ŷ], -0.5; atol=1e-1)) + moveinput!(mpc, [100]) + info = getinfo(mpc) + @test all(isapprox.(info[:Ŷ], 0.9; atol=1e-1)) + setconstraint!(mpc, ymin=[-100], ymax=[100]) + + setconstraint!(mpc, Ymin=[-0.5; fill(-100, 49)], Ymax=[0.9; fill(+100, 49)]) + moveinput!(mpc, [-10]) + info = getinfo(mpc) + @test info[:Ŷ][begin] ≈ -0.5 atol=1e-1 + @test info[:Ŷ][end] ≈ -10 atol=1e-1 + moveinput!(mpc, [10]) + info = getinfo(mpc) + @test info[:Ŷ][begin] ≈ 0.9 atol=1e-1 + @test info[:Ŷ][end] ≈ 10 atol=1e-1 + setconstraint!(mpc, ymin=[-100], ymax=[100]) + + setconstraint!(mpc, x̂min=[-1e-6,-Inf], x̂max=[+1e-6,+Inf]) + moveinput!(mpc, [-100]) + info = getinfo(mpc) + @test info[:x̂end][1] ≈ 0 atol=1e-1 + moveinput!(mpc, [100]) + info = getinfo(mpc) + @test info[:x̂end][1] ≈ 0 atol=1e-1 + setconstraint!(mpc, x̂min=[-1e6,-Inf], x̂max=[+1e6,+Inf]) + end + test_bound_violation(mpc_soft) + test_bound_violation(mpc_hard) model2 = LinModel([tf([2], [10, 1]) tf(0.1, [7, 1])], 3.0, i_d=[2]) model2 = setop!(model2, uop=[25], dop=[30], yop=[50])