4343
4444struct MovingHorizonEstimator{
4545 NT<: Real ,
46- SM<: SimModel ,
47- JM<: JuMP.GenericModel
46+ SM<: SimModel ,
47+ JM<: JuMP.GenericModel ,
48+ CE<: StateEstimator ,
4849} <: StateEstimator{NT}
4950 model:: SM
5051 # note: `NT` and the number type `JNT` in `JuMP.GenericModel{JNT}` can be
5152 # different since solvers that support non-Float64 are scarce.
5253 optim:: JM
5354 con:: EstimatorConstraint{NT}
55+ covestim:: CE
5456 Z̃:: Vector{NT}
5557 lastu0:: Vector{NT}
5658 x̂:: Vector{NT}
@@ -95,17 +97,16 @@ struct MovingHorizonEstimator{
9597 x̂arr_old:: Vector{NT}
9698 P̂arr_old:: Hermitian{NT, Matrix{NT}}
9799 Nk:: Vector{Int}
98- function MovingHorizonEstimator {NT, SM, JM} (
99- model:: SM , He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim:: JM
100- ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel }
100+ function MovingHorizonEstimator {NT, SM, JM, CE } (
101+ model:: SM , He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim:: JM , covestim :: CE
102+ ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel , CE <: StateEstimator{NT} }
101103 nu, nd = model. nu, model. nd
102104 He < 1 && throw (ArgumentError (" Estimation horizon He should be ≥ 1" ))
103105 Cwt < 0 && throw (ArgumentError (" Cwt weight should be ≥ 0" ))
104106 nym, nyu = validate_ym (model, i_ym)
105107 As, Cs_u, Cs_y, nint_u, nint_ym = init_estimstoch (model, i_ym, nint_u, nint_ym)
106108 nxs = size (As, 1 )
107109 nx̂ = model. nx + nxs
108- nŵ = nx̂
109110 Â, B̂u, Ĉ, B̂d, D̂d = augment_model (model, As, Cs_u, Cs_y)
110111 validate_kfcov (nym, nx̂, Q̂, R̂, P̂0)
111112 lastu0 = zeros (NT, model. nu)
@@ -129,8 +130,8 @@ struct MovingHorizonEstimator{
129130 x̂arr_old = zeros (NT, nx̂)
130131 P̂arr_old = copy (P̂0)
131132 Nk = [0 ]
132- estim = new {NT, SM, JM} (
133- model, optim, con,
133+ estim = new {NT, SM, JM, CE } (
134+ model, optim, con, covestim,
134135 Z̃, lastu0, x̂,
135136 He,
136137 i_ym, nx̂, nym, nyu, nxs,
@@ -188,7 +189,7 @@ The vectors ``\mathbf{Ŵ}`` and ``\mathbf{V̂}`` encompass the estimated proces
188189``\m athbf{ŵ}(k-j)`` and sensor noise ``\m athbf{v̂}(k-j)`` from ``j=N_k-1`` to ``0``. The
189190Extended Help defines the two vectors and the scalar ``ϵ``. See [`UnscentedKalmanFilter`](@ref)
190191for details on the augmented process model and ``\m athbf{R̂}, \m athbf{Q̂}`` covariances. The
191- matrix ``\m athbf{P̂}_{k-N_k}(k-N_k+1)`` is estimated with an [`ExtendedKalmanFilter`](@ref).
192+ covariance ``\m athbf{P̂}_{k-N_k}(k-N_k+1)`` is estimated with an [`ExtendedKalmanFilter`](@ref).
192193
193194!!! warning
194195 See the Extended Help if you get an error like:
@@ -262,7 +263,7 @@ MovingHorizonEstimator estimator with a sample time Ts = 10.0 s, Ipopt optimizer
262263"""
263264function MovingHorizonEstimator (
264265 model:: SM ;
265- He:: Union{Int, Nothing} = nothing ,
266+ He:: Union{Int, Nothing} = nothing ,
266267 i_ym:: IntRangeOrVector = 1 : model. ny,
267268 σP0:: Vector = fill (1 / model. nx, model. nx),
268269 σQ :: Vector = fill (1 / model. nx, model. nx),
@@ -280,33 +281,40 @@ function MovingHorizonEstimator(
280281 P̂0 = Hermitian (diagm (NT[σP0; σP0int_u; σP0int_ym]. ^ 2 ), :L )
281282 Q̂ = Hermitian (diagm (NT[σQ; σQint_u; σQint_ym ]. ^ 2 ), :L )
282283 R̂ = Hermitian (diagm (NT[σR;]. ^ 2 ), :L )
283- isnothing (He) && throw (ArgumentError (" Estimation horizon He must be explicitly specified" ))
284- return MovingHorizonEstimator {NT, SM, JM} (
285- model, He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim
286- )
284+ isnothing (He) && throw (ArgumentError (" Estimation horizon He must be explicitly specified" ))
285+ return MovingHorizonEstimator (model, He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim)
287286end
288287
289- " Return a `JuMP.Model` with OSQP optimizer if `model` is a [`LinModel`](@ref)."
290288default_optim_mhe (:: LinModel ) = JuMP. Model (DEFAULT_LINMHE_OPTIMIZER, add_bridges= false )
291- " Else, return it with Ipopt optimizer."
292289default_optim_mhe (:: SimModel ) = JuMP. Model (DEFAULT_NONLINMHE_OPTIMIZER, add_bridges= false )
293290
294291@doc raw """
295- MovingHorizonEstimator(model, He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim)
292+ MovingHorizonEstimator(model, He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim[, covestim] )
296293
297294Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and `R̂`.
298295
299296This syntax allows nonzero off-diagonal elements in ``\m athbf{P̂}_{-1}(0), \m athbf{Q̂, R̂}``.
297+ The final argument `covestim` also allows specifying a custom [`StateEstimator`](@ref)
298+ object for the estimation of covariance at the arrival ``\m athbf{P̂}_{k-N_k}(k-N_k+1)``. The
299+ supported types are [`KalmanFilter`](@ref), [`UnscentedKalmanFilter`](@ref) and
300+ [`ExtendedKalmanFilter`](@ref).
300301"""
301302function MovingHorizonEstimator (
302- model:: SM , He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim:: JM
303- ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel }
303+ model:: SM , He, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, Cwt, optim:: JM ,
304+ covestim:: CE = default_covestim_mhe (model, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
305+ ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel , CE<: StateEstimator{NT} }
304306 P̂0, Q̂, R̂ = to_mat (P̂0), to_mat (Q̂), to_mat (R̂)
305- return MovingHorizonEstimator {NT, SM, JM} (
306- model, He, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂, Cwt, optim
307+ return MovingHorizonEstimator {NT, SM, JM, CE } (
308+ model, He, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂, Cwt, optim, covestim
307309 )
308310end
309311
312+ function default_covestim_mhe (model:: LinModel , i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
313+ return KalmanFilter (model, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
314+ end
315+ function default_covestim_mhe (model:: SimModel , i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
316+ return UnscentedKalmanFilter (model, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
317+ end
310318
311319@doc raw """
312320 setconstraint!(estim::MovingHorizonEstimator; <keyword arguments>) -> estim
0 commit comments