Skip to content

Commit 7a9d360

Browse files
committed
added : MHE tests for constraints and getinfo
1 parent 4eb8458 commit 7a9d360

File tree

3 files changed

+111
-36
lines changed

3 files changed

+111
-36
lines changed

src/controller/execute.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,19 @@ Get additional info about `mpc` controller optimum for troubleshooting.
7373
The function should be called after calling [`moveinput!`](@ref). It returns the dictionary
7474
`info` with the following fields:
7575
76-
- `:ΔU` : optimal manipulated input increments over `Hc`, ``\mathbf{ΔU}``.
76+
- `:ΔU` : optimal manipulated input increments over ``H_c``, ``\mathbf{ΔU}``.
7777
- `:ϵ` : optimal slack variable, ``ϵ``.
7878
- `:J` : objective value optimum, ``J``.
79-
- `:U` : optimal manipulated inputs over `Hp`, ``\mathbf{U}``.
79+
- `:U` : optimal manipulated inputs over ``H_p``, ``\mathbf{U}``.
8080
- `:u` : current optimal manipulated input, ``\mathbf{u}(k)``.
8181
- `:d` : current measured disturbance, ``\mathbf{d}(k)``.
82-
- `:D̂` : predicted measured disturbances over `Hp`, ``\mathbf{D̂}``.
82+
- `:D̂` : predicted measured disturbances over ``H_p``, ``\mathbf{D̂}``.
8383
- `:ŷ` : current estimated output, ``\mathbf{ŷ}(k)``.
84-
- `:Ŷ` : optimal predicted outputs over `Hp`, ``\mathbf{Ŷ}``.
84+
- `:Ŷ` : optimal predicted outputs over ``H_p``, ``\mathbf{Ŷ}``.
8585
- `:x̂end`: optimal terminal states, ``\mathbf{x̂}_{k-1}(k+H_p)``.
86-
- `:Ŷs` : predicted stochastic output over `Hp` of [`InternalModel`](@ref), ``\mathbf{Ŷ_s}``.
87-
- `:R̂y` : predicted output setpoint over `Hp`, ``\mathbf{R̂_y}``.
88-
- `:R̂u` : predicted manipulated input setpoint over `Hp`, ``\mathbf{R̂_u}``.
86+
- `:Ŷs` : predicted stochastic output over ``H_p`` of [`InternalModel`](@ref), ``\mathbf{Ŷ_s}``.
87+
- `:R̂y` : predicted output setpoint over ``H_p``, ``\mathbf{R̂_y}``.
88+
- `:R̂u` : predicted manipulated input setpoint over ``H_p``, ``\mathbf{R̂_u}``.
8989
9090
For [`LinMPC`](@ref) and [`NonLinMPC`](@ref), the field `:sol` also contains the optimizer
9191
solution summary that can be printed. Lastly, the optimal economic cost `:JE` is also

src/estimator/mhe/execute.jl

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,43 +91,59 @@ Get additional info on `estim` [`MovingHorizonEstimator`](@ref) optimum for trou
9191
The function should be called after calling [`updatestate!`](@ref). It returns the
9292
dictionary `info` with the following fields:
9393
94-
- `:Ŵ` : optimal estimated process noise over `Nk`, ``\mathbf{ΔU}``.
94+
- `:Ŵ` : optimal estimated process noise over ``N_k``, ``\mathbf{}``.
9595
- `:x̂arr`: optimal estimated state at arrival, ``\mathbf{x̂}_k(k-N_k+1)``.
9696
- `:J` : objective value optimum, ``J``.
97-
- `:X̂` : optimal estimated states over `Nk+1`.
97+
- `:X̂` : optimal estimated states over ``N_k+1``, ``\mathbf{X̂}``.
9898
- `:x̂` : optimal estimated state for the next time step, ``\mathbf{x̂}_k(k+1)``.
99-
- `:V̂` : optimal estimated sensor noise over `Nk`, ``\mathbf{V̂}``.
99+
- `:V̂` : optimal estimated sensor noise over ``N_k``, ``\mathbf{V̂}``.
100100
- `:P̄` : estimation error covariance at arrival, ``\mathbf{P̄}``.
101101
- `:x̄` : optimal estimation error at arrival, ``\mathbf{x̄}``.
102-
- `:Ŷm` : optimal estimated measured outputs over `Nk`, ``\mathbf{Ŷ^m}``.
103-
- `:Ym` : measured outputs over `Nk`, ``\mathbf{Y^m}``.
104-
- `:U` : manipulated inputs over `Hp`, ``\mathbf{U}``.
105-
- `:D` : measured disturbances over `Nk`, ``\mathbf{D}``.
102+
- `:Ŷ` : optimal estimated outputs over ``N_k``, ``\mathbf{Ŷ}``.
103+
- `:Ŷm` : optimal estimated measured outputs over ``N_k``, ``\mathbf{Ŷ^m}``.
104+
- `:Ym` : measured outputs over ``N_k``, ``\mathbf{Y^m}``.
105+
- `:U` : manipulated inputs over ``N_k``, ``\mathbf{U}``.
106+
- `:D` : measured disturbances over ``N_k``, ``\mathbf{D}``.
106107
- `:sol` : solution summary of the optimizer for printing.
107108
108109
# Examples
109110
```jldoctest
110-
julia> a=1;
111+
julia> estim = MovingHorizonEstimator(LinModel(ss(1.0, 1.0, 1.0, 0, 1)), He=1, nint_ym=0);
112+
113+
julia> updatestate!(estim, [0], [1]);
114+
115+
julia> round.(getinfo(estim)[:Ŷ], digits=3)
116+
1-element Vector{Float64}:
117+
0.5
111118
```
112119
"""
113120
function getinfo(estim::MovingHorizonEstimator{NT}) where NT<:Real
114121
model, Nk = estim.model, estim.Nk[]
122+
nu, ny, nd = model.nu, model.ny, model.nd
115123
nx̂, nym, nŵ = estim.nx̂, estim.nym, estim.nx̂
116124
MyTypes = Union{JuMP._SolutionSummary, Hermitian{NT, Matrix{NT}}, Vector{NT}, NT}
117125
info = Dict{Symbol, MyTypes}()
118126
V̂, X̂ = similar(estim.Ym[1:nym*Nk]), similar(estim.X̂[1:nx̂*Nk])
119-
V̂, X̂ = predict!(V̂, X̂, estim, estim.model, estim.Z̃)
127+
V̂, X̂ = predict!(V̂, X̂, estim, model, estim.Z̃)
120128
x̂arr = estim.Z̃[1:nx̂]
121-
Ym, U, D = estim.Ym[1:nym*Nk], estim.U[1:model.nu*Nk], estim.D[1:model.nd*Nk]
129+
= [x̂arr; X̂]
130+
Ym, U, D = estim.Ym[1:nym*Nk], estim.U[1:nu*Nk], estim.D[1:nd*Nk]
131+
= Vector{NT}(undef, ny*Nk)
132+
for i=1:Nk
133+
d = @views D[(1 + nd*(i-1)):(nd*i)] # operating point already removed in estim.D
134+
= @views X̂[(1 + nx̂*(i-1)):(nx̂*i)]
135+
Ŷ[(1 + ny*(i-1)):(ny*i)] = (estim, model, x̂, d) + model.yop
136+
end
122137
Ŷm = Ym -
123138
info[:Ŵ] = estim.Ŵ[1:Nk*nŵ]
124139
info[:x̂arr] = x̂arr
125140
info[:J] = obj_nonlinprog(estim, estim.model, V̂, estim.Z̃)
126-
info[:X̂] = [x̂arr; X̂]
127-
info[:x̂] = X̂[end-estim.nx̂+1:end]
141+
info[:X̂] =
142+
info[:x̂] = estim.
128143
info[:V̂] =
129144
info[:P̄] = estim.P̂arr_old
130145
info[:x̄] = estim.x̂arr_old - x̂arr
146+
info[:Ŷ] =
131147
info[:Ŷm] = Ŷm
132148
info[:Ym] = Ym
133149
info[:U] = U

test/test_state_estim.jl

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Ts = 4.0
22
sys = [ tf(1.90,[18.0,1]) tf(1.90,[18.0,1]) tf(1.90,[18.0,1]);
33
tf(-0.74,[8.0,1]) tf(0.74,[8.0,1]) tf(-0.74,[8.0,1]) ]
4-
#=
4+
55
@testset "SteadyKalmanFilter construction" begin
66
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
77
skalmanfilter1 = SteadyKalmanFilter(linmodel1)
@@ -618,16 +618,21 @@ end
618618
@test_throws ArgumentError MovingHorizonEstimator(linmodel1)
619619
@test_throws ArgumentError MovingHorizonEstimator(linmodel1, He=0)
620620
end
621-
=#
622-
@testset "MovingHorizonEstimator estimator methods" begin
623-
linmodel1 = LinModel(sys,Ts,i_u=[1,2], i_d=[3])
621+
622+
@testset "MovingHorizonEstimator estimation and getinfo" begin
623+
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2], i_d=[3]), uop=[10,50], yop=[50,30], dop=[5])
624624
f(x,u,d) = linmodel1.A*x + linmodel1.Bu*u + linmodel1.Bd*d
625625
h(x,d) = linmodel1.C*x + linmodel1.Dd*d
626626
nonlinmodel = setop!(NonLinModel(f, h, Ts, 2, 4, 2, 1), uop=[10,50], yop=[50,30], dop=[5])
627627
mhe1 = MovingHorizonEstimator(nonlinmodel, He=2)
628-
@test updatestate!(mhe1, [10, 50], [50, 30], [5]) zeros(6) atol=1e-9
628+
= updatestate!(mhe1, [10, 50], [50, 30], [5])
629+
@test zeros(6) atol=1e-9
629630
@test mhe1. zeros(6) atol=1e-9
630631
@test evaloutput(mhe1, [5]) mhe1([5]) [50, 30]
632+
info = getinfo(mhe1)
633+
@test info[:x̂] x̂ atol=1e-9
634+
@test info[:Ŷ][end-1:end] [50, 30] atol=1e-9
635+
631636
@test initstate!(mhe1, [10, 50], [50, 30+1], [5]) zeros(6) atol=1e-9
632637
setstate!(mhe1, [1,2,3,4,5,6])
633638
@test mhe1. [1,2,3,4,5,6]
@@ -639,7 +644,15 @@ end
639644
updatestate!(mhe1, [10, 50], [51, 32], [5])
640645
end
641646
@test mhe1([5]) [51, 32] atol=1e-3
647+
642648
mhe2 = MovingHorizonEstimator(linmodel1, He=2, nint_u=[1, 1], nint_ym=[0, 0])
649+
= updatestate!(mhe2, [10, 50], [50, 30], [5])
650+
@test zeros(6) atol=1e-9
651+
@test mhe2. zeros(6) atol=1e-9
652+
@test evaloutput(mhe2, [5]) mhe2([5]) [50, 30]
653+
info = getinfo(mhe2)
654+
@test info[:x̂] x̂ atol=1e-9
655+
@test info[:Ŷ][end-1:end] [50, 30] atol=1e-9
643656
for i in 1:100
644657
updatestate!(mhe2, [11, 52], [50, 30], [5])
645658
end
@@ -698,41 +711,87 @@ end
698711
end
699712

700713
@testset "MovingHorizonEstimator constraint violation" begin
701-
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
702-
f(x,u,_) = linmodel1.A*x + linmodel1.Bu*u
703-
h(x,_) = linmodel1.C*x
704-
nonlinmodel = setop!(NonLinModel(f, h, Ts, 2, 2, 2), uop=[10,50], yop=[50,30])
705-
mhe = MovingHorizonEstimator(nonlinmodel, He=1, nint_ym=0)
714+
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2]), uop=[10,50], yop=[50,30])
715+
mhe = MovingHorizonEstimator(linmodel1, He=1, nint_ym=0)
706716

707717
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
708718
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
709719
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
710720

711721
setconstraint!(mhe, x̂min=[1,1], x̂max=[100,100])
712722
= updatestate!(mhe, [10, 50], [50, 30])
713-
@test [1, 1] atol=1e-3
723+
@test [1, 1] atol=1e-2
714724

715725
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[-1,-1])
716726
= updatestate!(mhe, [10, 50], [50, 30])
717-
@test [-1, -1] atol=1e-3
727+
@test [-1, -1] atol=1e-2
718728

719729
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
720730
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
721731
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
722732

723733
setconstraint!(mhe, ŵmin=[1,1], ŵmax=[100,100])
724734
= updatestate!(mhe, [10, 50], [50, 30])
725-
@test mhe. [1,1] atol=1e-3
735+
@test mhe. [1,1] atol=1e-2
726736

727737
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[-1,-1])
728738
= updatestate!(mhe, [10, 50], [50, 30])
729-
@test mhe. [-1,-1] atol=1e-3
739+
@test mhe. [-1,-1] atol=1e-2
730740

731741
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
732742
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
733743
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
734744

735-
#setconstraint!(mhe, v̂min=[1,1], v̂max=[100,100])
736-
#x̂ = updatestate!(mhe, [10, 50], [50, 30])
737-
#@test [50,30] - ModelPredictiveControl.ĥ(mhe,mhe.mode,X̂ ≈ [1,1] atol=1e-3
745+
setconstraint!(mhe, v̂min=[1,1], v̂max=[100,100])
746+
= updatestate!(mhe, [10, 50], [50, 30])
747+
info = getinfo(mhe)
748+
@test info[:V̂] [1,1] atol=1e-2
749+
750+
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[-1,-1])
751+
= updatestate!(mhe, [10, 50], [50, 30])
752+
info = getinfo(mhe)
753+
@test info[:V̂] [-1,-1] atol=1e-2
754+
755+
f(x,u,_) = linmodel1.A*x + linmodel1.Bu*u
756+
h(x,_) = linmodel1.C*x
757+
nonlinmodel = setop!(NonLinModel(f, h, Ts, 2, 2, 2), uop=[10,50], yop=[50,30])
758+
mhe2 = MovingHorizonEstimator(nonlinmodel, He=1, nint_ym=0)
759+
760+
setconstraint!(mhe2, x̂min=[-100,-100], x̂max=[100,100])
761+
setconstraint!(mhe2, ŵmin=[-100,-100], ŵmax=[100,100])
762+
setconstraint!(mhe2, v̂min=[-100,-100], v̂max=[100,100])
763+
764+
setconstraint!(mhe2, x̂min=[1,1], x̂max=[100,100])
765+
= updatestate!(mhe2, [10, 50], [50, 30])
766+
@test [1, 1] atol=1e-2
767+
768+
setconstraint!(mhe2, x̂min=[-100,-100], x̂max=[-1,-1])
769+
= updatestate!(mhe2, [10, 50], [50, 30])
770+
@test [-1, -1] atol=1e-2
771+
772+
setconstraint!(mhe2, x̂min=[-100,-100], x̂max=[100,100])
773+
setconstraint!(mhe2, ŵmin=[-100,-100], ŵmax=[100,100])
774+
setconstraint!(mhe2, v̂min=[-100,-100], v̂max=[100,100])
775+
776+
setconstraint!(mhe2, ŵmin=[1,1], ŵmax=[100,100])
777+
= updatestate!(mhe2, [10, 50], [50, 30])
778+
@test mhe2. [1,1] atol=1e-2
779+
780+
setconstraint!(mhe2, ŵmin=[-100,-100], ŵmax=[-1,-1])
781+
= updatestate!(mhe2, [10, 50], [50, 30])
782+
@test mhe2. [-1,-1] atol=1e-2
783+
784+
setconstraint!(mhe2, x̂min=[-100,-100], x̂max=[100,100])
785+
setconstraint!(mhe2, ŵmin=[-100,-100], ŵmax=[100,100])
786+
setconstraint!(mhe2, v̂min=[-100,-100], v̂max=[100,100])
787+
788+
setconstraint!(mhe2, v̂min=[1,1], v̂max=[100,100])
789+
= updatestate!(mhe2, [10, 50], [50, 30])
790+
info = getinfo(mhe2)
791+
@test info[:V̂] [1,1] atol=1e-2
792+
793+
setconstraint!(mhe2, v̂min=[-100,-100], v̂max=[-1,-1])
794+
= updatestate!(mhe2, [10, 50], [50, 30])
795+
info = getinfo(mhe2)
796+
@test info[:V̂] [-1,-1] atol=1e-2
738797
end

0 commit comments

Comments
 (0)