Skip to content

Commit 4eb8458

Browse files
committed
added: getinfo for MHE
1 parent b000a22 commit 4eb8458

File tree

6 files changed

+128
-36
lines changed

6 files changed

+128
-36
lines changed

docs/src/public/generic_func.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,9 @@ sim!
5050
```@docs
5151
SimResult
5252
```
53+
54+
## Get Additional Information
55+
56+
```@docs
57+
getinfo
58+
```

docs/src/public/predictive_control.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,3 @@ NonLinMPC
8383
```@docs
8484
moveinput!
8585
```
86-
87-
## Get Additional Information
88-
89-
```@docs
90-
getinfo
91-
```

src/controller/execute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ end
6868
@doc raw"""
6969
getinfo(mpc::PredictiveController) -> info
7070
71-
Get additional information about `mpc` controller optimum to ease troubleshooting.
71+
Get additional info about `mpc` controller optimum for troubleshooting.
7272
7373
The function should be called after calling [`moveinput!`](@ref). It returns the dictionary
7474
`info` with the following fields:

src/estimator/mhe/construct.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ end
234234
235235
Construct the MHE prediction matrices for [`LinModel`](@ref) `model`.
236236
237-
Introducing the vector ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{x̂_k}(k-H_e+1)
237+
Introducing the vector ``\mathbf{Z} = [\begin{smallmatrix} \mathbf{x̂}_k(k-H_e+1)
238238
\\ \mathbf{Ŵ} \end{smallmatrix}]`` with the decision variables, the estimated sensor
239239
noises from time ``k-H_e+1`` to ``k`` are computed by:
240240
```math
@@ -243,9 +243,9 @@ noises from time ``k-H_e+1`` to ``k`` are computed by:
243243
&= \mathbf{E Z + F}
244244
\end{aligned}
245245
```
246-
in which ``\mathbf{U, D}`` and ``\mathbf{Y^m}`` contains respectively the manipulated inputs
247-
and measured disturbances and measured outputs from time ``k-H_e+1`` to ``k``. The method
248-
also returns similar matrices but for the estimation error at arrival:
246+
in which ``\mathbf{U, D}`` and ``\mathbf{Y^m}`` contains respectively the manipulated
247+
inputs, measured disturbances and measured outputs from time ``k-H_e+1`` to ``k``. The
248+
method also returns similar matrices but for the estimation error at arrival:
249249
```math
250250
\mathbf{x̄} = \mathbf{x̂}_{k-H_e}(k-H_e+1) - \mathbf{x̂}_{k}(k-H_e+1) = \mathbf{e_x̄ Z + f_x̄}
251251
```
@@ -657,7 +657,7 @@ function setconstraint!(
657657
end
658658

659659
@doc raw"""
660-
init_matconstrain_mhe(model::LinModel,
660+
init_matconstraint_mhe(model::LinModel,
661661
i_x̂min, i_x̂max, i_X̂min, i_X̂max, i_Ŵmin, i_Ŵmax, i_V̂min, i_V̂max, args...
662662
) -> i_b, i_g, A
663663

src/estimator/mhe/execute.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,60 @@ function update_estimate!(estim::MovingHorizonEstimator{NT}, u, ym, d) where NT<
8282
return nothing
8383
end
8484

85+
86+
@doc raw"""
87+
getinfo(estim::MovingHorizonEstimator) -> info
88+
89+
Get additional info on `estim` [`MovingHorizonEstimator`](@ref) optimum for troubleshooting.
90+
91+
The function should be called after calling [`updatestate!`](@ref). It returns the
92+
dictionary `info` with the following fields:
93+
94+
- `:Ŵ` : optimal estimated process noise over `Nk`, ``\mathbf{ΔU}``.
95+
- `:x̂arr`: optimal estimated state at arrival, ``\mathbf{x̂}_k(k-N_k+1)``.
96+
- `:J` : objective value optimum, ``J``.
97+
- `:X̂` : optimal estimated states over `Nk+1`.
98+
- `:x̂` : optimal estimated state for the next time step, ``\mathbf{x̂}_k(k+1)``.
99+
- `:V̂` : optimal estimated sensor noise over `Nk`, ``\mathbf{V̂}``.
100+
- `:P̄` : estimation error covariance at arrival, ``\mathbf{P̄}``.
101+
- `: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}``.
106+
- `:sol` : solution summary of the optimizer for printing.
107+
108+
# Examples
109+
```jldoctest
110+
julia> a=1;
111+
```
112+
"""
113+
function getinfo(estim::MovingHorizonEstimator{NT}) where NT<:Real
114+
model, Nk = estim.model, estim.Nk[]
115+
nx̂, nym, nŵ = estim.nx̂, estim.nym, estim.nx̂
116+
MyTypes = Union{JuMP._SolutionSummary, Hermitian{NT, Matrix{NT}}, Vector{NT}, NT}
117+
info = Dict{Symbol, MyTypes}()
118+
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̃)
120+
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]
122+
Ŷm = Ym -
123+
info[:Ŵ] = estim.Ŵ[1:Nk*nŵ]
124+
info[:x̂arr] = x̂arr
125+
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]
128+
info[:V̂] =
129+
info[:P̄] = estim.P̂arr_old
130+
info[:x̄] = estim.x̂arr_old - x̂arr
131+
info[:Ŷm] = Ŷm
132+
info[:Ym] = Ym
133+
info[:U] = U
134+
info[:D] = D
135+
info[:sol] = solution_summary(estim.optim, verbose=true)
136+
return info
137+
end
138+
85139
"Add data to the observation windows of the moving horizon estimator."
86140
function add_data_windows!(estim::MovingHorizonEstimator, u, d, ym)
87141
model = estim.model

test/test_state_estim.jl

Lines changed: 62 additions & 24 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,45 +618,43 @@ end
618618
@test_throws ArgumentError MovingHorizonEstimator(linmodel1)
619619
@test_throws ArgumentError MovingHorizonEstimator(linmodel1, He=0)
620620
end
621-
621+
=#
622622
@testset "MovingHorizonEstimator estimator methods" begin
623-
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
624-
f(x,u,_) = linmodel1.A*x + linmodel1.Bu*u
625-
h(x,_) = linmodel1.C*x
626-
nonlinmodel = setop!(NonLinModel(f, h, 1000*Ts, 2, 2, 2), uop=[10,50], yop=[50,30])
623+
linmodel1 = LinModel(sys,Ts,i_u=[1,2], i_d=[3])
624+
f(x,u,d) = linmodel1.A*x + linmodel1.Bu*u + linmodel1.Bd*d
625+
h(x,d) = linmodel1.C*x + linmodel1.Dd*d
626+
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]) zeros(4) atol=1e-9
629-
@test updatestate!(mhe1, [10, 50], [50, 30], Float64[]) zeros(4) atol=1e-9
630-
@test mhe1. zeros(4) atol=1e-9
631-
@test evaloutput(mhe1) mhe1() [50, 30]
632-
@test evaloutput(mhe1, Float64[]) mhe1(Float64[]) [50, 30]
633-
@test initstate!(mhe1, [10, 50], [50, 30+1]) zeros(4) atol=1e-9
634-
setstate!(mhe1, [1,2,3,4])
635-
@test mhe1. [1,2,3,4]
628+
@test updatestate!(mhe1, [10, 50], [50, 30], [5]) zeros(6) atol=1e-9
629+
@test mhe1. zeros(6) atol=1e-9
630+
@test evaloutput(mhe1, [5]) mhe1([5]) [50, 30]
631+
@test initstate!(mhe1, [10, 50], [50, 30+1], [5]) zeros(6) atol=1e-9
632+
setstate!(mhe1, [1,2,3,4,5,6])
633+
@test mhe1. [1,2,3,4,5,6]
636634
for i in 1:100
637-
updatestate!(mhe1, [11, 52], [50, 30])
635+
updatestate!(mhe1, [11, 52], [50, 30], [5])
638636
end
639-
@test mhe1() [50, 30] atol=1e-3
637+
@test mhe1([5]) [50, 30] atol=1e-3
640638
for i in 1:100
641-
updatestate!(mhe1, [10, 50], [51, 32])
639+
updatestate!(mhe1, [10, 50], [51, 32], [5])
642640
end
643-
@test mhe1() [51, 32] atol=1e-3
641+
@test mhe1([5]) [51, 32] atol=1e-3
644642
mhe2 = MovingHorizonEstimator(linmodel1, He=2, nint_u=[1, 1], nint_ym=[0, 0])
645643
for i in 1:100
646-
updatestate!(mhe2, [11, 52], [50, 30])
644+
updatestate!(mhe2, [11, 52], [50, 30], [5])
647645
end
648-
@test mhe2() [50, 30] atol=1e-3
646+
@test mhe2([5]) [50, 30] atol=1e-3
649647
for i in 1:100
650-
updatestate!(mhe2, [10, 50], [51, 32])
648+
updatestate!(mhe2, [10, 50], [51, 32], [5])
651649
end
652-
@test mhe2() [51, 32] atol=1e-3
650+
@test mhe2([5]) [51, 32] atol=1e-3
653651
linmodel3 = LinModel{Float32}(0.5*ones(1,1), ones(1,1), ones(1,1), zeros(1,0), zeros(1,0), 1.0)
654652
mhe3 = MovingHorizonEstimator(linmodel3, He=1)
655653
= updatestate!(mhe3, [0], [0])
656654
@test [0, 0] atol=1e-3
657655
@test isa(x̂, Vector{Float32})
658656

659-
mhe4 = setconstraint!(MovingHorizonEstimator(nonlinmodel, He=1, nint_ym=0), x̂max=[50,50])
657+
mhe4 = setconstraint!(MovingHorizonEstimator(nonlinmodel, He=1, nint_ym=0), x̂max=[50,50,50,50])
660658
g_X̂max_end = mhe4.optim.nlp_model.operators.registered_multivariate_operators[end].f
661659
@test g_X̂max_end((1.0, 1.0, 1.0, 1.0)) 0.0 # test gfunc_i(i,::NTuple{N, Float64})
662660
# test gfunc_i(i,::NTuple{N, ForwardDiff.Dual}) :
@@ -669,18 +667,34 @@ end
669667
setconstraint!(mhe1, x̂min=[-51,-52], x̂max=[53,54])
670668
@test all((mhe1.con.X̂min, mhe1.con.X̂max) .≈ ([-51,-52], [53,54]))
671669
@test all((mhe1.con.x̂min, mhe1.con.x̂max) .≈ ([-51,-52], [53,54]))
670+
setconstraint!(mhe1, ŵmin=[-55,-56], ŵmax=[57,58])
671+
@test all((mhe1.con.Ŵmin, mhe1.con.Ŵmax) .≈ ([-55,-56], [57,58]))
672+
setconstraint!(mhe1, v̂min=[-59,-60], v̂max=[61,62])
673+
@test all((mhe1.con.V̂min, mhe1.con.V̂max) .≈ ([-59,-60], [61,62]))
672674

673675
mhe2 = MovingHorizonEstimator(linmodel1, He=4, nint_ym=0)
674676
setconstraint!(mhe2, X̂min=-1(1:10), X̂max=1(1:10))
675677
@test all((mhe2.con.X̂min, mhe2.con.X̂max) .≈ (-1(3:10), 1(3:10)))
676678
@test all((mhe2.con.x̂min, mhe2.con.x̂max) .≈ (-1(1:2), 1(1:2)))
679+
setconstraint!(mhe2, Ŵmin=-1(11:18), Ŵmax=1(11:18))
680+
@test all((mhe2.con.Ŵmin, mhe2.con.Ŵmax) .≈ (-1(11:18), 1(11:18)))
681+
setconstraint!(mhe2, V̂min=-1(31:38), V̂max=1(31:38))
682+
@test all((mhe2.con.V̂min, mhe2.con.V̂max) .≈ (-1(31:38), 1(31:38)))
677683

678684
@test_throws ArgumentError setconstraint!(mhe2, x̂min=[-1])
679685
@test_throws ArgumentError setconstraint!(mhe2, x̂max=[+1])
686+
@test_throws ArgumentError setconstraint!(mhe2, ŵmin=[-1])
687+
@test_throws ArgumentError setconstraint!(mhe2, ŵmax=[+1])
688+
@test_throws ArgumentError setconstraint!(mhe2, v̂min=[-1])
689+
@test_throws ArgumentError setconstraint!(mhe2, v̂max=[+1])
680690

681691
updatestate!(mhe1, [10, 50], [50, 30])
682692
@test_throws ErrorException setconstraint!(mhe1, x̂min=[-Inf,-Inf])
683693
@test_throws ErrorException setconstraint!(mhe1, x̂max=[+Inf,+Inf])
694+
@test_throws ErrorException setconstraint!(mhe1, ŵmin=[-Inf,-Inf])
695+
@test_throws ErrorException setconstraint!(mhe1, ŵmax=[+Inf,+Inf])
696+
@test_throws ErrorException setconstraint!(mhe1, v̂min=[-Inf,-Inf])
697+
@test_throws ErrorException setconstraint!(mhe1, v̂max=[+Inf,+Inf])
684698
end
685699

686700
@testset "MovingHorizonEstimator constraint violation" begin
@@ -690,11 +704,35 @@ end
690704
nonlinmodel = setop!(NonLinModel(f, h, Ts, 2, 2, 2), uop=[10,50], yop=[50,30])
691705
mhe = MovingHorizonEstimator(nonlinmodel, He=1, nint_ym=0)
692706

707+
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
708+
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
709+
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
710+
693711
setconstraint!(mhe, x̂min=[1,1], x̂max=[100,100])
694712
= updatestate!(mhe, [10, 50], [50, 30])
695713
@test [1, 1] atol=1e-3
696714

697715
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[-1,-1])
698716
= updatestate!(mhe, [10, 50], [50, 30])
699717
@test [-1, -1] atol=1e-3
700-
end
718+
719+
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
720+
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
721+
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
722+
723+
setconstraint!(mhe, ŵmin=[1,1], ŵmax=[100,100])
724+
= updatestate!(mhe, [10, 50], [50, 30])
725+
@test mhe. [1,1] atol=1e-3
726+
727+
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[-1,-1])
728+
= updatestate!(mhe, [10, 50], [50, 30])
729+
@test mhe. [-1,-1] atol=1e-3
730+
731+
setconstraint!(mhe, x̂min=[-100,-100], x̂max=[100,100])
732+
setconstraint!(mhe, ŵmin=[-100,-100], ŵmax=[100,100])
733+
setconstraint!(mhe, v̂min=[-100,-100], v̂max=[100,100])
734+
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
738+
end

0 commit comments

Comments
 (0)