@@ -38,6 +38,97 @@ function StateEstimatorBuffer{NT}(
3838 return StateEstimatorBuffer {NT} (u, û, k, x̂, P̂, Q̂, R̂, K̂, ym, ŷ, d, empty)
3939end
4040
41+ " Include all the covariance matrices for the Kalman filters and moving horizon estimator."
42+ struct KalmanCovariances{
43+ NT<: Real ,
44+ # parameters to support both dense and Diagonal matrices (with specialization):
45+ Q̂C<: AbstractMatrix{NT} ,
46+ R̂C<: AbstractMatrix{NT} ,
47+ }
48+ P̂_0:: Hermitian{NT, Matrix{NT}}
49+ P̂:: Hermitian{NT, Matrix{NT}}
50+ Q̂:: Hermitian{NT, Q̂C}
51+ R̂:: Hermitian{NT, R̂C}
52+ invP̄:: Hermitian{NT, Matrix{NT}}
53+ invQ̂_He:: Hermitian{NT, Q̂C}
54+ invR̂_He:: Hermitian{NT, R̂C}
55+ function KalmanCovariances {NT} (
56+ Q̂:: Q ̂C, R̂:: R ̂C, P̂_0, He
57+ ) where {NT<: Real , Q̂C<: AbstractMatrix{NT} , R̂C<: AbstractMatrix{NT} }
58+ if isnothing (P̂_0)
59+ P̂_0 = zeros (NT, 0 , 0 )
60+ end
61+ P̂_0 = Hermitian (P̂_0, :L )
62+ P̂ = copy (P̂_0)
63+ Q̂ = Hermitian (Q̂, :L )
64+ R̂ = Hermitian (R̂, :L )
65+ # the following variables are only for the moving horizon estimator:
66+ invP̄, invQ̂, invR̂ = copy (P̂_0), copy (Q̂), copy (R̂)
67+ try
68+ inv! (invP̄)
69+ catch err
70+ if err isa PosDefException
71+ error (" P̂_0 is not positive definite" )
72+ else
73+ rethrow ()
74+ end
75+ end
76+ try
77+ inv! (invQ̂)
78+ catch err
79+ if err isa PosDefException
80+ error (" Q̂ is not positive definite" )
81+ else
82+ rethrow ()
83+ end
84+ end
85+ try
86+ inv! (invR̂)
87+ catch err
88+ if err isa PosDefException
89+ error (" R̂ is not positive definite" )
90+ else
91+ rethrow ()
92+ end
93+ end
94+ invQ̂_He = repeatdiag (invQ̂, He)
95+ invR̂_He = repeatdiag (invR̂, He)
96+ invQ̂_He = Hermitian (invQ̂_He, :L )
97+ invR̂_He = Hermitian (invR̂_He, :L )
98+ return new {NT, Q̂C, R̂C} (P̂_0, P̂, Q̂, R̂, invP̄, invQ̂_He, invR̂_He)
99+ end
100+ end
101+
102+ " Outer constructor to validate and convert covariance matrices if necessary."
103+ function KalmanCovariances (
104+ model:: SimModel{NT} , i_ym, nint_u, nint_ym, Q̂, R̂, P̂_0= nothing , He= 1
105+ ) where {NT<: Real }
106+ validate_kfcov (model, i_ym, nint_u, nint_ym, Q̂, R̂, P̂_0)
107+ Q̂, R̂ = NT .(Q̂), NT .(R̂)
108+ ! isnothing (P̂_0) && (P̂_0 = NT .(P̂_0))
109+ return KalmanCovariances {NT} (Q̂, R̂, P̂_0, He)
110+ end
111+
112+ """
113+ validate_kfcov(model, i_ym, nint_u, nint_ym, Q̂, R̂, P̂_0=nothing)
114+
115+ Validate sizes and Hermitianity of process `Q̂`` and sensor `R̂` noises covariance matrices.
116+
117+ Also validate initial estimate covariance `P̂_0`, if provided.
118+ """
119+ function validate_kfcov (model, i_ym, nint_u, nint_ym, Q̂, R̂, P̂_0= nothing )
120+ nym = length (i_ym)
121+ nx̂ = model. nx + sum (nint_u) + sum (nint_ym)
122+ size (Q̂) ≠ (nx̂, nx̂) && error (" Q̂ size $(size (Q̂)) ≠ nx̂, nx̂ $((nx̂, nx̂)) " )
123+ ! ishermitian (Q̂) && error (" Q̂ is not Hermitian" )
124+ size (R̂) ≠ (nym, nym) && error (" R̂ size $(size (R̂)) ≠ nym, nym $((nym, nym)) " )
125+ ! ishermitian (R̂) && error (" R̂ is not Hermitian" )
126+ if ~ isnothing (P̂_0)
127+ size (P̂_0) ≠ (nx̂, nx̂) && error (" P̂_0 size $(size (P̂_0)) ≠ nx̂, nx̂ $((nx̂, nx̂)) " )
128+ ! ishermitian (P̂_0) && error (" P̂_0 is not Hermitian" )
129+ end
130+ end
131+
41132@doc raw """
42133 init_estimstoch(model, i_ym, nint_u, nint_ym) -> As, Cs_u, Cs_y, nxs, nint_u, nint_ym
43134
0 commit comments