Skip to content

Commit 05d439d

Browse files
committed
improve coverage for StateEstimator types
1 parent 3bfd43c commit 05d439d

File tree

7 files changed

+36
-16
lines changed

7 files changed

+36
-16
lines changed

src/estimator/kalman.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ Construct the estimator from the augmented covariance matrices `Q̂` and `R̂`.
161161
This syntax allows nonzero off-diagonal elements in ``\mathbf{Q̂, R̂}``.
162162
"""
163163
function SteadyKalmanFilter(model::SM, i_ym, nint_u, nint_ym, Q̂, R̂) where {NT<:Real, SM<:LinModel{NT}}
164+
Q̂, R̂ = to_mat(Q̂), to_mat(R̂)
164165
return SteadyKalmanFilter{NT, SM}(model, i_ym, nint_u, nint_ym, Q̂ , R̂)
165166
end
166167

@@ -302,6 +303,7 @@ Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and
302303
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
303304
"""
304305
function KalmanFilter(model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂) where {NT<:Real, SM<:LinModel{NT}}
306+
P̂0, Q̂, R̂ = to_mat(P̂0), to_mat(Q̂), to_mat(R̂)
305307
return KalmanFilter{NT, SM}(model, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂)
306308
end
307309

@@ -473,6 +475,7 @@ This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mat
473475
function UnscentedKalmanFilter(
474476
model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ
475477
) where {NT<:Real, SM<:SimModel{NT}}
478+
P̂0, Q̂, R̂ = to_mat(P̂0), to_mat(Q̂), to_mat(R̂)
476479
return UnscentedKalmanFilter{NT, SM}(model, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂, α, β, κ)
477480
end
478481

@@ -694,6 +697,7 @@ Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and
694697
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
695698
"""
696699
function ExtendedKalmanFilter(model::SM, i_ym, nint_u, nint_ym,P̂0, Q̂, R̂) where {NT<:Real, SM<:SimModel{NT}}
700+
P̂0, Q̂, R̂ = to_mat(P̂0), to_mat(Q̂), to_mat(R̂)
697701
return ExtendedKalmanFilter{NT, SM}(model, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂)
698702
end
699703

src/estimator/mhe.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ nonlinear objective function at each discrete time ``k``:
109109
+ \mathbf{Ŵ}' \mathbf{Q̂}_{N_k}^{-1} \mathbf{Ŵ}
110110
+ \mathbf{V̂}' \mathbf{R̂}_{N_k}^{-1} \mathbf{V̂}
111111
```
112-
in which the arrival costs are defined by:
112+
in which the arrival costs are evaluated from the states estimated at time ``k-N_k``:
113113
```math
114114
\begin{aligned}
115115
\mathbf{x̄} &= \mathbf{x̂}_k(k-N_k+1) - \mathbf{x̂}_{k-N_k}(k-N_k+1) \\
116-
\mathbf{P̄} &= \mathbf{P̂}_k(k-N_k+1)
116+
\mathbf{P̄} &= \mathbf{P̂}_{k-N_k}(k-N_k+1)
117117
\end{aligned}
118118
```
119119
and the covariances are repeated ``N_k`` times:
@@ -133,7 +133,12 @@ N_k = \begin{cases}
133133
```
134134
See [`SteadyKalmanFilter`](@ref) for details on ``\mathbf{R̂}, \mathbf{Q̂}`` covariances and
135135
model augmentation. The process model is identical to the one in [`UnscentedKalmanFilter`](@ref)
136-
documentation.
136+
documentation. Note that the estimation error covariance ``\mathbf{P̂}_{k-N_k}(k-N_k+1)`` is
137+
approximated with an [`ExtendedKalmanFilter`](@ref).
138+
139+
!!! warning
140+
See the Extended Help of [`NonLinMPC`](@ref) function if you get an error like:
141+
`MethodError: no method matching (::var"##")(::Vector{ForwardDiff.Dual})`.
137142
138143
# Arguments
139144
- `model::SimModel` : (deterministic) model for the estimations.
@@ -193,6 +198,7 @@ This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mat
193198
function MovingHorizonEstimator(
194199
model::SM, He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, optim::JM
195200
) where {NT<:Real, SM<:SimModel{NT}, JM<:JuMP.GenericModel}
201+
P̂0, Q̂, R̂ = to_mat(P̂0), to_mat(Q̂), to_mat(R̂)
196202
return MovingHorizonEstimator{NT, SM, JM}(
197203
model, He, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂, optim
198204
)

src/model/linmodel.jl

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct LinModel{NT<:Real} <: SimModel{NT}
1414
yop::Vector{NT}
1515
dop::Vector{NT}
1616
function LinModel{NT}(A, Bu, C, Bd, Dd, Ts) where {NT<:Real}
17+
A, Bu, C, Bd, Dd = to_mat(A), to_mat(Bu), to_mat(C), to_mat(Bd), to_mat(Dd)
1718
nu, nx, ny, nd = size(Bu,2), size(A,2), size(C,1), size(Bd,2)
1819
size(A) == (nx,nx) || error("A size must be $((nx,nx))")
1920
size(Bu) == (nx,nu) || error("Bu size must be $((nx,nu))")
@@ -192,24 +193,24 @@ The optional parameter `NT` explicitly specifies the number type of the matrices
192193
LinModel{NT}(A, Bu, C, Bd, Dd, Ts) where NT<:Real
193194

194195
function LinModel(
195-
A::Matrix{NT}, Bu::Matrix{NT}, C::Matrix{NT}, Bd::Matrix{NT}, Dd::Matrix{NT}, Ts::NT
196+
A::Array{NT}, Bu::Array{NT}, C::Array{NT}, Bd::Array{NT}, Dd::Array{NT}, Ts::Real
196197
) where {NT<:Real}
197198
return LinModel{NT}(A, Bu, C, Bd, Dd, Ts)
198199
end
199200

200201
function LinModel(
201-
A::Matrix{<:Real},
202-
Bu::Matrix{<:Real},
203-
C::Matrix{<:Real},
204-
Bd::Matrix{<:Real},
205-
Dd::Matrix{<:Real},
202+
A::Array{<:Real},
203+
Bu::Array{<:Real},
204+
C::Array{<:Real},
205+
Bd::Array{<:Real},
206+
Dd::Array{<:Real},
206207
Ts::Real
207208
)
208-
A, Bu, C, Bd, Dd, Ts_arr = promote(A, Bu, C, Bd, Dd, Ts*ones(1,1))
209-
return LinModel(A, Bu, C, Bd, Dd, Ts_arr[])
209+
A, Bu, C, Bd, Dd = to_mat(A), to_mat(Bu), to_mat(C), to_mat(Bd), to_mat(Dd)
210+
A, Bu, C, Bd, Dd = promote(A, Bu, C, Bd, Dd)
211+
return LinModel(A, Bu, C, Bd, Dd, Ts)
210212
end
211213

212-
213214
@doc raw"""
214215
steadystate!(model::LinModel, u, d)
215216

src/model/nonlinmodel.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ manually call a differential equation solver in `f` (see [Manual](@ref man_nonli
4747
4848
!!! warning
4949
`f` and `h` must be pure Julia functions to use the model in [`NonLinMPC`](@ref),
50-
[`ExtendedKalmanFilter`](@ref) and [`linearize`](@ref).
50+
[`ExtendedKalmanFilter`](@ref), [`MovingHorizonEstimator`](@ref) and [`linearize`](@ref).
5151
5252
See also [`LinModel`](@ref).
5353

src/sim_model.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ function validate_args(model::SimModel, u, d)
177177
size(d) (nd,) && throw(DimensionMismatch("d size $(size(d)) ≠ meas. dist. size ($nd,)"))
178178
end
179179

180+
"Convert vectors to single column matrices when necessary."
181+
to_mat(A::AbstractVector) = reshape(A, length(A), 1)
182+
to_mat(A::AbstractMatrix) = A
183+
180184
"Functor allowing callable `SimModel` object as an alias for `evaloutput`."
181185
(model::SimModel)(d=empty(model.x)) = evaloutput(model::SimModel, d)
182186

test/test_sim_model.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ Gss2 = c2d(sys_ss[:,1:2], 0.5Ts, :zoh)
6666
@test linmodel7.A diagm( .1: .1: .3)
6767
@test linmodel7.C diagm( .4: .1: .6)
6868

69-
linmodel8 = LinModel{Float32}(Gss.A, Gss.B, Gss.C, zeros(2, 0), zeros(2, 0), Ts)
70-
@test isa(linmodel8, LinModel{Float32})
69+
linmodel8 = LinModel(Gss.A, Gss.B, Gss.C, zeros(Float32, 2, 0), zeros(Float32, 2, 0), Ts)
70+
@test isa(linmodel8, LinModel{Float64})
71+
72+
linmodel9 = LinModel{Float32}(Gss.A, Gss.B, Gss.C, zeros(2, 0), zeros(2, 0), Ts)
73+
@test isa(linmodel9, LinModel{Float32})
7174

7275
@test_throws ErrorException LinModel(sys)
7376
@test_throws ErrorException LinModel(sys,-Ts)

test/test_state_estim.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ sys = [ tf(1.90,[18.0,1]) tf(1.90,[18.0,1]) tf(1.90,[18.0,1]);
5757
@test_throws ErrorException SteadyKalmanFilter(linmodel1, nint_ym=0, σQ=[1])
5858
@test_throws ErrorException SteadyKalmanFilter(linmodel1, nint_ym=0, σR=[1,1,1])
5959
@test_throws ErrorException SteadyKalmanFilter(linmodel3, nint_ym=[1, 0, 0])
60-
model_unobs = LinModel([1 0;0 1.5], [1;0][:,:], [1 0], zeros(2,0), zeros(1,0), 1.0)
60+
model_unobs = LinModel([1 0;0 1.5], [1; 0], [1 0], zeros(2,0), zeros(1,0), 1.0)
6161
@test_throws ErrorException SteadyKalmanFilter(model_unobs, nint_ym=[1])
62+
@test_throws ErrorException SteadyKalmanFilter(LinModel(tf(1,[10, 1]), 1.0), 1:1, 0, 0, [-1], [1])
6263
@test_throws ErrorException SteadyKalmanFilter(LinModel(tf(1, [1,0]), 1), nint_ym=[1])
6364
@test_throws ErrorException SteadyKalmanFilter(linmodel1, nint_u=[1,1], nint_ym=[1,1])
6465
end
@@ -229,6 +230,7 @@ end
229230
@test_throws ErrorException Luenberger(linmodel1, p̂=[0.5])
230231
@test_throws ErrorException Luenberger(linmodel1, p̂=fill(1.5, lo1.nx̂))
231232
@test_throws ErrorException Luenberger(LinModel(tf(1,[1, 0]),0.1), p̂=[0.5,0.6])
233+
@test_throws ErrorException Luenberger(linmodel1, p̂=[0,0,0,0])
232234
end
233235

234236
@testset "Luenberger estimator methods" begin

0 commit comments

Comments
 (0)