Skip to content

Commit 293ef23

Browse files
committed
avoid invoke call for time varying kalman filters initialization
1 parent aca8990 commit 293ef23

File tree

3 files changed

+44
-33
lines changed

3 files changed

+44
-33
lines changed

src/controller/nonlinmpc.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ This method uses the default state estimator :
111111
- else, an [`UnscentedKalmanFilter`](@ref) with default arguments.
112112
113113
!!! warning
114-
See Extended Help if you get an error like `MethodError: no method matching
115-
Float64(::ForwardDiff.Dual)`.
114+
See Extended Help if you get an error like:
115+
`MethodError: no method matching Float64(::ForwardDiff.Dual)`.
116116
117117
# Arguments
118118
- `model::SimModel` : model used for controller predictions and state estimations.

src/estimator/kalman.jl

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,13 @@ function UnscentedKalmanFilter(
420420
end
421421

422422
@doc raw"""
423-
UnscentedKalmanFilter{M<:SimModel}(model, i_ym, nint_ym, P̂0, Q̂, R̂, α, β, κ)
423+
UnscentedKalmanFilter{M<:SimModel}(model::M, i_ym, nint_ym, P̂0, Q̂, R̂, α, β, κ)
424424
425425
Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and `R̂`.
426426
427427
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
428428
"""
429-
UnscentedKalmanFilter{M}(model::SimModel, i_ym, nint_ym, P̂0, Q̂, R̂, α, β, κ) where {M}
429+
UnscentedKalmanFilter{M}(model::M, i_ym, nint_ym, P̂0, Q̂, R̂, α, β, κ) where {M<:SimModel}
430430

431431

432432
@doc raw"""
@@ -584,8 +584,8 @@ identical to [`UnscentedKalmanFilter`](@ref). The Jacobians of the augmented mod
584584
automatic differentiation.
585585
586586
!!! warning
587-
See Extended Help if you get an error like `MethodError: no method matching (::var"##")
588-
(::Vector{ForwardDiff.Dual})`.
587+
See Extended Help if you get an error like:
588+
`MethodError: no method matching (::var"##")(::Vector{ForwardDiff.Dual})`.
589589
590590
# Arguments
591591
- `model::SimModel` : (deterministic) model for the estimations.
@@ -610,7 +610,6 @@ ExtendedKalmanFilter estimator with a sample time Ts = 5.0 s, NonLinModel and:
610610
Automatic differentiation (AD) allows exact Jacobians. The [`NonLinModel`](@ref) `f` and `h`
611611
functions must be compatible with this feature though. See [Automatic differentiation](https://jump.dev/JuMP.jl/stable/manual/nlp/#Automatic-differentiation)
612612
for common mistakes when writing these functions.
613-
```
614613
"""
615614
function ExtendedKalmanFilter(
616615
model::M;
@@ -629,22 +628,43 @@ function ExtendedKalmanFilter(
629628
return ExtendedKalmanFilter{M}(model, i_ym, nint_ym, P̂0, Q̂ , R̂)
630629
end
631630

631+
@doc raw"""
632+
ExtendedKalmanFilter{M<:SimModel}(model::M, i_ym, nint_ym, P̂0, Q̂, R̂)
633+
634+
Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and `R̂`.
635+
636+
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
637+
"""
638+
ExtendedKalmanFilter{M}(model::M, i_ym, nint_ym, P̂0 ,Q̂, R̂) where {M<:SimModel}
639+
632640
@doc raw"""
633641
update_estimate!(estim::ExtendedKalmanFilter, u, ym, d=Float64[])
634642
635-
Update [`ExtendedKalmanFilter`](@ref) state `estim.x̂` and estimation error covariance `estim.P̂`.
643+
Update [`ExtendedKalmanFilter`](@ref) state `estim.x̂` and covariance `estim.P̂`.
636644
637-
The equations are identical to [`update_estimate!(::KalmanFilter)`](@ref) with the
638-
substitutions ``\mathbf{Â = F̂}(k)`` and ``\mathbf{Ĉ^m = Ĥ^m}(k)``, and the Jacobians:
645+
The equations are similar to [`update_estimate!(::KalmanFilter)`](@ref) but with the
646+
substitutions ``\mathbf{Â = F̂}(k)`` and ``\mathbf{Ĉ^m = Ĥ^m}(k)``:
647+
```math
648+
\begin{aligned}
649+
\mathbf{M}(k) &= \mathbf{P̂}_{k-1}(k)\mathbf{Ĥ^m}'
650+
[\mathbf{Ĥ^m P̂}_{k-1}(k)\mathbf{Ĥ^m + R̂}]^{-1} \\
651+
\mathbf{K}(k) &= \mathbf{F̂ M(k)} \\
652+
\mathbf{ŷ^m}(k) &= \mathbf{ĥ^m}\Big( \mathbf{x̂}_{k-1}(k), \mathbf{d}(k) \Big) \\
653+
\mathbf{x̂}_{k}(k+1) &= \mathbf{f̂}\Big( \mathbf{x̂}_{k-1}(k), \mathbf{u}(k), \mathbf{d}(k) \Big)
654+
+ \mathbf{K}(k)[\mathbf{y^m}(k) - \mathbf{ŷ^m}(k)] \\
655+
\mathbf{P̂}_{k}(k+1) &= \mathbf{F̂}[\mathbf{P̂}_{k-1}(k) -
656+
\mathbf{M}(k)\mathbf{Ĥ^m P̂}_{k-1}(k)]\mathbf{F̂}' + \mathbf{Q̂}
657+
\end{aligned}
658+
```
659+
[`ForwardDiff.jacobian`](https://juliadiff.org/ForwardDiff.jl/stable/user/api/#ForwardDiff.jacobian)
660+
automatically computes the Jacobians:
639661
```math
640662
\begin{aligned}
641663
\mathbf{F̂}(k) &= \left. \frac{∂\mathbf{f̂}(\mathbf{x̂}, \mathbf{u}, \mathbf{d})}{∂\mathbf{x̂}} \right|_{\mathbf{x̂ = x̂}_{k-1}(k),\, \mathbf{u = u}(k),\, \mathbf{d = d}(k)} \\
642664
\mathbf{Ĥ}(k) &= \left. \frac{∂\mathbf{ĥ}(\mathbf{x̂}, \mathbf{d})}{∂\mathbf{x̂}} \right|_{\mathbf{x = x̂}_{k-1}(k),\, \mathbf{d = d}(k)}
643665
\end{aligned}
644666
```
645-
The matrix ``\mathbf{Ĥ^m}(k)`` is the rows of ``\mathbf{Ĥ}(k)`` that are measured outputs.
646-
The function [`ForwardDiff.jacobian`](https://juliadiff.org/ForwardDiff.jl/stable/user/api/#ForwardDiff.jacobian)
647-
computes ``\mathbf{F̂}(k)`` and ``\mathbf{Ĥ}(k)``.
667+
The matrix ``\mathbf{Ĥ^m}`` is the rows of ``\mathbf{Ĥ}`` that are measured outputs.
648668
"""
649669
function update_estimate!(estim::ExtendedKalmanFilter, u, ym, d=Float64[])
650670
x̂, P̂, Q̂, R̂ = estim.x̂, estim.P̂, estim.Q̂, estim.
@@ -659,28 +679,14 @@ function update_estimate!(estim::ExtendedKalmanFilter, u, ym, d=Float64[])
659679
return x̂, P̂
660680
end
661681

662-
663-
"""
664-
initstate!(
665-
estim::Union{KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFilter},
666-
u,
667-
ym,
668-
d=Float64[]
669-
)
670-
671-
Initialize covariance `estim.P̂` and invoke [`initstate!(::StateEstimator)`](@ref).
672-
"""
673-
function initstate!(
674-
estim::Union{KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFilter},
675-
u,
676-
ym,
677-
d=Float64[]
678-
)
679-
estim..data[:] = estim.P̂0 # .data is necessary for Hermitian matrices
680-
invoke(initstate!, Tuple{StateEstimator, Any, Any, Any}, estim, u, ym, d)
682+
"Initialize the covariance estimate `P̂` for the time-varying Kalman Filters"
683+
function initstate_cov!(
684+
estim::Union{KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFilter}
685+
)
686+
estim..data[:] = estim.P̂0
687+
return nothing
681688
end
682689

683-
684690
"""
685691
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0=nothing)
686692

src/state_estim.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ julia> x̂ = initstate!(estim, [1], [3 - 0.1])
225225
"""
226226
function initstate!(estim::StateEstimator, u, ym, d=Float64[])
227227
model = estim.model
228+
# --- init covariance error estimate (if applicable) ---
229+
initstate_cov!(estim)
228230
# --- init lastu0 for PredictiveControllers ---
229231
estim.lastu0[:] = u - model.uop
230232
# --- deterministic model states ---
@@ -242,6 +244,9 @@ function initstate!(estim::StateEstimator, u, ym, d=Float64[])
242244
return estim.
243245
end
244246

247+
"By default, state estimators do not need initialization of covariance estimate."
248+
initstate_cov!(estim::StateEstimator) = nothing
249+
245250
"Init deterministic state `x̂d` with steady-state value for `LinModel`."
246251
init_deterstate(model::LinModel, _ , u, d) = steadystate(model, u, d)
247252
"Keep current deterministic state unchanged for `NonLinModel`."

0 commit comments

Comments
 (0)