@@ -166,6 +166,10 @@ function SteadyKalmanFilter(model::SM, i_ym, nint_u, nint_ym, Q̂, R̂) where {N
166166 return SteadyKalmanFilter {NT, SM} (model, i_ym, nint_u, nint_ym, Q̂, R̂)
167167end
168168
169+ " Throw an error if `setmodel!` is called on a SteadyKalmanFilter"
170+ function setmodel_estimator! (estim:: SteadyKalmanFilter , _ )
171+ error (" SteadyKalmanFilter does not support setmodel! (use KalmanFilter instead)" )
172+ end
169173
170174
171175@doc raw """
@@ -192,7 +196,7 @@ function update_estimate!(estim::SteadyKalmanFilter, u, ym, d=empty(estim.x̂))
192196 mul! (x̂next, B̂u, u, 1 , 1 )
193197 mul! (x̂next, B̂d, d, 1 , 1 )
194198 mul! (x̂next, K̂, v̂, 1 , 1 )
195- x̂ .= x̂next
199+ estim . x̂ .= x̂next
196200 return nothing
197201end
198202
@@ -347,6 +351,7 @@ function update_estimate!(estim::KalmanFilter, u, ym, d)
347351 return update_estimate_kf! (estim, u, ym, d, estim. Â, estim. Ĉm, estim. P̂, estim. x̂)
348352end
349353
354+
350355struct UnscentedKalmanFilter{NT<: Real , SM<: SimModel } <: StateEstimator{NT}
351356 model:: SM
352357 lastu0:: Vector{NT}
@@ -368,12 +373,13 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
368373 B̂d:: Matrix{NT}
369374 D̂d:: Matrix{NT}
370375 P̂0:: Hermitian{NT, Matrix{NT}}
371- Q̂ :: Hermitian{NT, Matrix{NT}}
372- R̂ :: Hermitian{NT, Matrix{NT}}
376+ Q̂:: Hermitian{NT, Matrix{NT}}
377+ R̂:: Hermitian{NT, Matrix{NT}}
373378 K̂:: Matrix{NT}
374379 M̂:: Hermitian{NT, Matrix{NT}}
375- X̂ :: Matrix{NT}
380+ X̂:: Matrix{NT}
376381 Ŷm:: Matrix{NT}
382+ sqrtP̂:: LowerTriangular{NT, Matrix{NT}}
377383 nσ:: Int
378384 γ:: NT
379385 m̂:: Vector{NT}
@@ -396,14 +402,15 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
396402 K̂ = zeros (NT, nx̂, nym)
397403 M̂ = Hermitian (zeros (NT, nym, nym), :L )
398404 X̂, Ŷm = zeros (NT, nx̂, nσ), zeros (NT, nym, nσ)
405+ sqrtP̂ = LowerTriangular (zeros (NT, nx̂, nx̂))
399406 return new {NT, SM} (
400407 model,
401408 lastu0, x̂, P̂,
402409 i_ym, nx̂, nym, nyu, nxs,
403410 As, Cs_u, Cs_y, nint_u, nint_ym,
404411 Â, B̂u, Ĉ, B̂d, D̂d,
405412 P̂0, Q̂, R̂,
406- K̂, M̂, X̂, Ŷm,
413+ K̂, M̂, X̂, Ŷm, sqrtP̂,
407414 nσ, γ, m̂, Ŝ
408415 )
409416 end
@@ -571,21 +578,23 @@ noise, respectively.
571578"""
572579function update_estimate! (estim:: UnscentedKalmanFilter{NT} , u, ym, d) where NT<: Real
573580 x̂, P̂, Q̂, R̂, K̂, M̂ = estim. x̂, estim. P̂, estim. Q̂, estim. R̂, estim. K̂, estim. M̂
574- X̂, Ŷm = estim. X̂, estim. Ŷm
575581 nym, nx̂, nσ = estim. nym, estim. nx̂, estim. nσ
576582 γ, m̂, Ŝ = estim. γ, estim. m̂, estim. Ŝ
583+ X̂, Ŷm = estim. X̂, estim. Ŷm
584+ sqrtP̂ = estim. sqrtP̂
577585 # --- initialize matrices ---
578- X̂_next = Matrix {NT} (undef, nx̂, nσ )
586+ x̂next = Vector {NT} (undef, nx̂)
579587 û = Vector {NT} (undef, estim. model. nu)
580588 ŷm = Vector {NT} (undef, nym)
581589 ŷ = Vector {NT} (undef, estim. model. ny)
582- sqrt_P̂ = LowerTriangular {NT, Matrix{NT}} (Matrix {NT} (undef, nx̂, nx̂))
583590 # --- correction step ---
584- sqrt_P̂ .= cholesky (P̂). L
585- γ_sqrt_P̂ = lmul! (γ, sqrt_P̂)
591+ P̂_chol = sqrtP̂. data
592+ P̂_chol .= P̂
593+ cholesky! (Hermitian (P̂_chol, :L )) # also modifies sqrtP̂
594+ γ_sqrtP̂ = lmul! (γ, sqrtP̂)
586595 X̂ .= x̂
587- X̂[:, 2 : nx̂+ 1 ] .+ = γ_sqrt_P̂
588- X̂[:, nx̂+ 2 : end ] .- = γ_sqrt_P̂
596+ X̂[:, 2 : nx̂+ 1 ] .+ = γ_sqrtP̂
597+ X̂[:, nx̂+ 2 : end ] .- = γ_sqrtP̂
589598 for j in axes (Ŷm, 2 )
590599 @views ĥ! (ŷ, estim, estim. model, X̂[:, j], d)
591600 @views Ŷm[:, j] .= ŷ[estim. i_ym]
@@ -594,27 +603,36 @@ function update_estimate!(estim::UnscentedKalmanFilter{NT}, u, ym, d) where NT<:
594603 X̄, Ȳm = X̂, Ŷm
595604 X̄ .= X̂ .- x̂
596605 Ȳm .= Ŷm .- ŷm
597- M̂ .= Hermitian ( Ȳm * Ŝ * Ȳm' .+ R̂)
606+ M̂. data .= Ȳm * Ŝ * Ȳm' .+ R̂
598607 mul! (K̂, X̄, lmul! (Ŝ, Ȳm' ))
599608 rdiv! (K̂, cholesky (M̂))
600609 v̂ = ŷm
601610 v̂ .= ym .- ŷm
602- x̂_cor = x̂ + K̂ * v̂
603- P̂_cor = P̂ - Hermitian (K̂ * M̂ * K̂' , :L )
611+ x̂cor = x̂next
612+ x̂cor .= x̂
613+ mul! (x̂cor, K̂, v̂, 1 , 1 )
614+ P̂cor = Hermitian (P̂ .- K̂ * M̂ * K̂' , :L )
604615 # --- prediction step ---
605- X̂_cor, sqrt_P̂_cor = X̂, sqrt_P̂
606- sqrt_P̂_cor .= cholesky (P̂_cor). L
607- γ_sqrt_P̂_cor = lmul! (γ, sqrt_P̂_cor)
608- X̂_cor .= x̂_cor
609- X̂_cor[:, 2 : nx̂+ 1 ] .+ = γ_sqrt_P̂_cor
610- X̂_cor[:, nx̂+ 2 : end ] .- = γ_sqrt_P̂_cor
611- for j in axes (X̂_next, 2 )
612- @views f̂! (X̂_next[:, j], û, estim, estim. model, X̂_cor[:, j], u, d)
616+ X̂cor, sqrtP̂cor = X̂, sqrtP̂
617+ P̂cor_chol = sqrtP̂cor. data
618+ P̂cor_chol .= P̂cor
619+ cholesky! (Hermitian (P̂cor_chol, :L )) # also modifies sqrtP̂cor
620+ γ_sqrtP̂cor = lmul! (γ, sqrtP̂cor)
621+ X̂cor .= x̂cor
622+ X̂cor[:, 2 : nx̂+ 1 ] .+ = γ_sqrtP̂cor
623+ X̂cor[:, nx̂+ 2 : end ] .- = γ_sqrtP̂cor
624+ X̂next = X̂cor
625+ for j in axes (X̂next, 2 )
626+ @views x̂cor .= X̂cor[:, j]
627+ @views f̂! (X̂next[:, j], û, estim, estim. model, x̂cor, u, d)
613628 end
614- x̂_next = mul! (x̂, X̂_next, m̂)
615- X̄_next = X̂_next
616- X̄_next .= X̂_next .- x̂_next
617- P̂ .= Hermitian (X̄_next * Ŝ * X̄_next' .+ Q̂)
629+ x̂next .= mul! (x̂, X̂next, m̂)
630+ X̄next = X̂next
631+ X̄next .= X̂next .- x̂next
632+ P̂next = P̂cor
633+ P̂next. data .= X̄next * Ŝ * X̄next' .+ Q̂
634+ estim. x̂ .= x̂next
635+ estim. P̂ .= P̂next
618636 return nothing
619637end
620638
@@ -822,17 +840,17 @@ function update_estimate_kf!(estim::StateEstimator{NT}, u, ym, d, Â, Ĉm, P̂
822840 Q̂, R̂, M̂, K̂ = estim. Q̂, estim. R̂, estim. M̂, estim. K̂
823841 nx̂, nu, ny = estim. nx̂, estim. model. nu, estim. model. ny
824842 x̂next, û, ŷ = Vector {NT} (undef, nx̂), Vector {NT} (undef, nu), Vector {NT} (undef, ny)
825- P̂next = similar (P̂)
826843 mul! (M̂, P̂. data, Ĉm' ) # the ".data" weirdly removes a type instability in mul!
827- rdiv! (M̂, cholesky! (Hermitian (Ĉm * P̂ * Ĉm' .+ R̂)))
844+ rdiv! (M̂, cholesky! (Hermitian (Ĉm * P̂ * Ĉm' .+ R̂, :L )))
828845 mul! (K̂, Â, M̂)
829846 ĥ! (ŷ, estim, estim. model, x̂, d)
830847 ŷm = @views ŷ[estim. i_ym]
831848 v̂ = ŷm
832849 v̂ .= ym .- ŷm
833850 f̂! (x̂next, û, estim, estim. model, x̂, u, d)
834851 mul! (x̂next, K̂, v̂, 1 , 1 )
852+ P̂next = Hermitian (Â * (P̂ .- M̂ * Ĉm * P̂) * Â' .+ Q̂, :L )
835853 estim. x̂ .= x̂next
836- P̂ .= Hermitian (Â * (P̂ .- M̂ * Ĉm * P̂) * Â ' .+ Q̂)
854+ estim . P̂ .= P̂next
837855 return nothing
838856end
0 commit comments