Skip to content

Commit e18ab07

Browse files
committed
test: wip new tests for MHE custom constraints
1 parent 339ca24 commit e18ab07

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

test/2_test_state_estim.jl

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,142 @@ end
15661566
@test X̂_lin X̂_nonlin atol=1e-3 rtol=1e-3
15671567
end
15681568

1569+
1570+
@testitem "MovingHorizonEstimator construction with custom constraint (LinModel)" setup=[SetupMPCtests] begin
1571+
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
1572+
linmodel = LinModel(sys, Ts, i_u=[1,2], i_d=[3])
1573+
linmodel = setop!(linmodel, uop=[10,50], yop=[50,30], dop=[5])
1574+
1575+
# Custom constraint: simple bound on states using only X̂e and ε
1576+
function gc_lin(X̂e, _ , _ , _ , _ , _ , _ , _ ,nX̂e , ε)
1577+
gc = X̂e .- 100 .- ε # all states must be <= 100
1578+
return [gc; zeros(nX̂e .- length(X̂e))]
1579+
end
1580+
He = 3
1581+
nx̂ = length(linmodel.A) + 2 # number of states (with augmentation)
1582+
nc = nx̂ * (He+1) # Approximate constraint count for He=3
1583+
nX̂e = nx̂ * (He+1)
1584+
mhe = MovingHorizonEstimator(linmodel, Cwt=1e5, He=He, gc=gc_lin, nc=nc, p=nX̂e)
1585+
1586+
@test mhe.con.nc == nc
1587+
@test mhe.> 0
1588+
@test mhe.He == 3
1589+
end
1590+
1591+
@testitem "MovingHorizonEstimator custom constraint violation (LinModel)" setup=[SetupMPCtests] begin
1592+
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
1593+
linmodel = LinModel(sys, Ts, i_u=[1,2], i_d=[3])
1594+
linmodel = setop!(linmodel, uop=[10,50], yop=[50,30], dop=[5])
1595+
1596+
# Custom constraint function using only X̂e and ε
1597+
# This constraint enforces that the first state must be >= 0.5
1598+
function gc_constraint!(LHS, X̂e, V̂e, Ŵe, Ue, Yem, De, P̄, x̄, p, ε)
1599+
nx̂ = 4 # number of states (with augmentation)
1600+
# Extract and constrain first state at each time step
1601+
for i in 1:div(length(X̂e), nx̂)
1602+
LHS[(i-1)+1] = 0.5 - X̂e[(i-1)*nx̂ + 1] # First state >= 0.5
1603+
end
1604+
return nothing
1605+
end
1606+
1607+
nc = 3 # One constraint per time step (He=1 initially, but grows)
1608+
mhe = MovingHorizonEstimator(linmodel, He=1, gc=gc_constraint!, nc=nc, Cwt=1e3, nint_ym=0)
1609+
1610+
preparestate!(mhe, [50, 30], [5])
1611+
= updatestate!(mhe, [10, 50], [50, 30], [5])
1612+
# The constraint should be satisfied (first state should be >= 0.5)
1613+
@test x̂[1] >= 0.5 - 0.1 # Allow some tolerance
1614+
end
1615+
1616+
@testitem "MovingHorizonEstimator custom constraint violation (NonLinModel)" setup=[SetupMPCtests] begin
1617+
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
1618+
using JuMP, Ipopt
1619+
linmodel = LinModel(sys, Ts, i_u=[1,2], i_d=[3])
1620+
linmodel = setop!(linmodel, uop=[10,50], yop=[50,30], dop=[5])
1621+
1622+
f = (x,u,d,model) -> model.A*x + model.Bu*u + model.Bd*d
1623+
h = (x,d,model) -> model.C*x + model.Dd*d
1624+
nonlinmodel = NonLinModel(f, h, Ts, 2, 4, 2, 1, solver=nothing, p=linmodel)
1625+
nonlinmodel = setop!(nonlinmodel, uop=[10,50], yop=[50,30], dop=[5])
1626+
1627+
# Custom constraint function using only X̂e and ε
1628+
# This constraint enforces that the first state must be >= 0.5
1629+
function gc_constraint_nl!(LHS, X̂e, V̂e, Ŵe, Ue, Yem, De, P̄, x̄, p, ε)
1630+
nx̂ = 6 # number of states (with augmentation)
1631+
# Extract and constrain first state at each time step
1632+
for i in 1:div(length(X̂e), nx̂)
1633+
LHS[(i-1)+1] = 0.5 - X̂e[(i-1)*nx̂ + 1] # First state >= 0.5
1634+
end
1635+
return nothing
1636+
end
1637+
1638+
nc = 3 # One constraint per time step
1639+
optim = Model(Ipopt.Optimizer)
1640+
mhe = MovingHorizonEstimator(nonlinmodel, He=1, gc=gc_constraint_nl!, nc=nc, Cwt=1e3, nint_ym=0; optim)
1641+
1642+
preparestate!(mhe, [50, 30], [5])
1643+
= updatestate!(mhe, [10, 50], [50, 30], [5])
1644+
# The constraint should be satisfied (first state should be >= 0.5)
1645+
@test x̂[1] >= 0.5 - 0.1 # Allow some tolerance
1646+
end
1647+
1648+
@testitem "MovingHorizonEstimator custom constraint on noise (LinModel)" setup=[SetupMPCtests] begin
1649+
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
1650+
linmodel = LinModel(sys, Ts, i_u=[1,2], i_d=[3])
1651+
linmodel = setop!(linmodel, uop=[10,50], yop=[50,30], dop=[5])
1652+
1653+
# Custom constraint function using Ŵe and ε
1654+
# This constraint enforces that process noise must be <= 0
1655+
function gc_noise_constraint!(LHS, X̂e, V̂e, Ŵe, Ue, Yem, De, P̄, x̄, p, ε)
1656+
nx̂ = 4 # number of states (with augmentation)
1657+
# Constraint: all process noise components must be <= 0
1658+
for i in 1:length(Ŵe)
1659+
LHS[i] = Ŵe[i] # Ŵe <= 0
1660+
end
1661+
return nothing
1662+
end
1663+
1664+
nc = 4 * 2 # Two time steps with 4 states each
1665+
mhe = MovingHorizonEstimator(linmodel, He=1, gc=gc_noise_constraint!, nc=nc, Cwt=1e3, nint_ym=0)
1666+
1667+
preparestate!(mhe, [50, 30], [5])
1668+
= updatestate!(mhe, [10, 50], [50, 30], [5])
1669+
# The constraint should be satisfied (process noise should be <= 0)
1670+
@test all(mhe.Ŵ .<= 0.1) # Allow some tolerance
1671+
end
1672+
1673+
@testitem "MovingHorizonEstimator custom constraint on noise (NonLinModel)" setup=[SetupMPCtests] begin
1674+
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
1675+
using JuMP, Ipopt
1676+
linmodel = LinModel(sys, Ts, i_u=[1,2], i_d=[3])
1677+
linmodel = setop!(linmodel, uop=[10,50], yop=[50,30], dop=[5])
1678+
1679+
f = (x,u,d,model) -> model.A*x + model.Bu*u + model.Bd*d
1680+
h = (x,d,model) -> model.C*x + model.Dd*d
1681+
nonlinmodel = NonLinModel(f, h, Ts, 2, 4, 2, 1, solver=nothing, p=linmodel)
1682+
nonlinmodel = setop!(nonlinmodel, uop=[10,50], yop=[50,30], dop=[5])
1683+
1684+
# Custom constraint function using Ŵe and ε
1685+
# This constraint enforces that process noise must be <= 0
1686+
function gc_noise_constraint_nl!(LHS, X̂e, V̂e, Ŵe, Ue, Yem, De, P̄, x̄, p, ε)
1687+
nx̂ = 6 # number of states (with augmentation)
1688+
# Constraint: all process noise components must be <= 0
1689+
for i in 1:length(Ŵe)
1690+
LHS[i] = Ŵe[i] # Ŵe <= 0
1691+
end
1692+
return nothing
1693+
end
1694+
1695+
nc = 6 * 2 # Two time steps with 6 states each
1696+
optim = Model(Ipopt.Optimizer)
1697+
mhe = MovingHorizonEstimator(nonlinmodel, He=1, gc=gc_noise_constraint_nl!, nc=nc, Cwt=1e3, nint_ym=0; optim)
1698+
1699+
preparestate!(mhe, [50, 30], [5])
1700+
= updatestate!(mhe, [10, 50], [50, 30], [5])
1701+
# The constraint should be satisfied (process noise should be <= 0)
1702+
@test all(mhe.Ŵ .<= 0.1) # Allow some tolerance
1703+
end
1704+
15691705
@testitem "ManualEstimator construction" setup=[SetupMPCtests] begin
15701706
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
15711707
linmodel = LinModel(sys,Ts,i_u=[1,2])

0 commit comments

Comments
 (0)