@@ -313,6 +313,8 @@ transcription for now.
313313- `hessian=false` : an `AbstractADType` backend for the Hessian of the Lagrangian, see
314314 `gradient` above for the options. The default `false` skip it and use the quasi-Newton
315315 method of `optim` (see Extended Help).
316+ - `covestim=nothing`: a [`StateEstimator`](@ref) object for the arrival covariance estimation
317+ ``\m athbf{P̂}_{k-N_k}(k-N_k+p)``, `nothing` means the default choice (see Extended Help).
316318- `direct=true`: construct with a direct transmission from ``\m athbf{y^m}`` (a.k.a. current
317319 estimator, in opposition to the delayed/predictor form).
318320
@@ -449,7 +451,7 @@ MovingHorizonEstimator estimator with a sample time Ts = 10.0 s:
449451 [`JuMP` documentation](@extref JuMP Common-mistakes-when-writing-a-user-defined-operator)
450452 for common mistakes when writing these functions. Also, an [`UnscentedKalmanFilter`](@ref)
451453 estimates the arrival covariance by default.
452-
454+
453455 One exception about AD: the selected backend for the Hessian of the Lagrangian function
454456 with `hessian=true` options is sparse:
455457 ```julia
@@ -469,7 +471,14 @@ MovingHorizonEstimator estimator with a sample time Ts = 10.0 s:
469471 )
470472 )
471473 ```
472- that is, it will test many coloring orders at preparation and keep the best.
474+ that is, it will test many coloring orders at preparation and keep the best. The
475+ argument `covestim` customizes the arrival covariance estimator. The supported types are
476+ [`SteadyKalmanFilter`](@ref), [`KalmanFilter`](@ref), [`UnscentedKalmanFilter`](@ref)
477+ and [`ExtendedKalmanFilter`](@ref). A constant arrival covariance is supported with
478+ [`SteadyKalmanFilter`](@ref), and by setting the `P̂` argument of [`setstate!`](@ref)
479+ method at the desired value. For [`NonLinModel`](@ref), construct a
480+ [`SteadyKalmanFilter`](@ref) with an arbitrary [`LinModel`](@ref), as long as the number
481+ of estimated states `nx̂` matches the MHE.
473482
474483 Note that if `Cwt≠Inf`, the attribute `nlp_scaling_max_gradient` of `Ipopt` is set to
475484 `10/Cwt` (if not already set), to scale the small values of ``ε``. Use the second
@@ -497,6 +506,7 @@ function MovingHorizonEstimator(
497506 gradient:: AbstractADType = DEFAULT_NONLINMHE_GRADIENT,
498507 jacobian:: AbstractADType = DEFAULT_NONLINMHE_JACOBIAN,
499508 hessian:: Union{AbstractADType, Bool, Nothing} = false ,
509+ covestim:: Union{StateEstimator, Nothing} = nothing ,
500510 direct = true ,
501511 σP_0 = sigmaP_0,
502512 σQ = sigmaQ,
@@ -513,19 +523,10 @@ function MovingHorizonEstimator(
513523 isnothing (He) && throw (ArgumentError (" Estimation horizon He must be explicitly specified" ))
514524 return MovingHorizonEstimator (
515525 model, He, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂, Cwt;
516- gc, gc!, nc, p, direct, optim, gradient, jacobian, hessian
526+ gc, gc!, nc, p, optim, gradient, jacobian, hessian, covestim, direct
517527 )
518528end
519529
520- " Default optimizer for MHE, depending on the model and the number of custom NL constraints."
521- function default_optim_mhe (model:: SimModel , nc)
522- if model isa LinModel && iszero (nc)
523- return JuMP. Model (DEFAULT_LINMHE_OPTIMIZER, add_bridges= false )
524- else
525- return JuMP. Model (DEFAULT_NONLINMHE_OPTIMIZER, add_bridges= false )
526- end
527- end
528-
529530@doc raw """
530531 MovingHorizonEstimator(
531532 model, He, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂, Cwt=Inf;
@@ -536,20 +537,14 @@ end
536537 gradient=AutoForwardDiff(),
537538 jacobian=AutoForwardDiff(),
538539 hessian=false,
540+ covestim=nothing,
539541 direct=true,
540- covestim=default_covestim_mhe(model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
541542 )
542543
543544Construct the estimator from the augmented covariance matrices `P̂_0`, `Q̂` and `R̂`.
544545
545546This syntax allows nonzero off-diagonal elements in ``\m athbf{P̂_i}, \m athbf{Q̂, R̂}``,
546- where ``\m athbf{P̂_i}`` is the initial estimation covariance, provided by `P̂_0` argument. The
547- keyword argument `covestim` also allows specifying a custom [`StateEstimator`](@ref) object
548- for the estimation of covariance at the arrival ``\m athbf{P̂}_{k-N_k}(k-N_k+p)``. The
549- supported types are [`SteadyKalmanFilter`](@ref), [`KalmanFilter`](@ref),
550- [`UnscentedKalmanFilter`](@ref) and [`ExtendedKalmanFilter`](@ref). A constant arrival
551- covariance is supported with [`SteadyKalmanFilter`](@ref), and by setting the `P̂` argument
552- of [`setstate!`](@ref) at the desired value.
547+ where ``\m athbf{P̂_i}`` is the initial estimation covariance, provided by `P̂_0` argument.
553548"""
554549function MovingHorizonEstimator (
555550 model:: SM , He, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂, Cwt= Inf ;
@@ -561,13 +556,16 @@ function MovingHorizonEstimator(
561556 gradient:: AbstractADType = DEFAULT_NONLINMHE_GRADIENT,
562557 jacobian:: AbstractADType = DEFAULT_NONLINMHE_JACOBIAN,
563558 hessian:: Union{AbstractADType, Bool, Nothing} = false ,
559+ covestim:: Union{StateEstimator, Nothing} = nothing ,
564560 direct = true ,
565- covestim:: CE = default_covestim_mhe (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
566- ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel , CE<: StateEstimator{NT} }
561+ ) where {NT<: Real , SM<: SimModel{NT} , JM<: JuMP.GenericModel }
567562 P̂_0, Q̂, R̂ = to_mat (P̂_0), to_mat (Q̂), to_mat (R̂)
568563 cov = KalmanCovariances (model, i_ym, nint_u, nint_ym, Q̂, R̂, P̂_0, He)
569564 gc! = get_mutating_gc_mhe (NT, gc)
570565 hessian = validate_hessian (hessian, gradient, DEFAULT_NONLINMHE_HESSIAN)
566+ if isnothing (covestim)
567+ covestim = default_covestim_mhe (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
568+ end
571569 validate_covestim (cov, covestim)
572570 return MovingHorizonEstimator {NT} (
573571 model,
@@ -578,17 +576,30 @@ function MovingHorizonEstimator(
578576 )
579577end
580578
581- function default_covestim_mhe (model:: LinModel , i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
582- return KalmanFilter (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
579+ " Default optimizer for MHE, depending on the model and the number of custom NL constraints."
580+ function default_optim_mhe (model:: SimModel , nc)
581+ if model isa LinModel && iszero (nc)
582+ return JuMP. Model (DEFAULT_LINMHE_OPTIMIZER, add_bridges= false )
583+ else
584+ return JuMP. Model (DEFAULT_NONLINMHE_OPTIMIZER, add_bridges= false )
585+ end
583586end
587+
588+ " Default arrival covariance estimator for MHE, depending on the model type only."
584589function default_covestim_mhe (model:: SimModel , i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
585- return UnscentedKalmanFilter (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
590+ if model isa LinModel
591+ return KalmanFilter (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
592+ else
593+ return UnscentedKalmanFilter (model, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂; direct)
594+ end
586595end
587596
588597" Validate covestim type and dimensions."
589598function validate_covestim (cov:: KalmanCovariances , covestim:: KalmanEstimator )
590- if size (cov. P̂) != size (covestim. cov. P̂)
591- throw (ArgumentError (" estimation covariance covestim.cov.P̂ size does not match the MHE" ))
599+ invP̄, P̂ = cov. invP̄, covestim. cov. P̂
600+ nx̂ = size (invP̄, 1 )
601+ if size (invP̄) != size (P̂)
602+ throw (ArgumentError (" P̂ covariance size $(size (P̂)) of covestim does match nx̂=$nx̂ " ))
592603 end
593604 return nothing
594605end
0 commit comments