11function manifoldupdate! (integ, residualf; maxiters= 100 , ϵ₁= 1e-25 , ϵ₂= 1e-15 )
2- @unpack x, SolProj = integ. cache
3- f (m) = residualf (SolProj * m)
4- return copy! (x, manifoldupdate (x, f; maxiters= maxiters, ϵ₁= ϵ₁, ϵ₂= ϵ₂))
5- end
2+ m, C = integ. cache. x
63
7- function manifoldupdate (x, f; maxiters= 100 , ϵ₁= 1e-25 , ϵ₂= 1e-15 )
8- m, C = x
9- m_i = copy (m)
4+ # Create some caches
5+ @unpack SolProj, tmp, H, x_tmp, x_tmp2 = integ. cache
6+ z_tmp = residualf (mul! (tmp, SolProj, m))
7+ result = DiffResults. JacobianResult (z_tmp, tmp)
8+ d = length (z_tmp)
9+ H = H[1 : d, :]
10+ S = SquarerootMatrix (C. squareroot[1 : d, :], C. mat[1 : d, 1 : d])
11+ m_tmp, C_tmp = x_tmp
1012
13+ m_i = copy (m)
1114 local m_i_new, C_i_new
1215 for i in 1 : maxiters
13- z = f (m_i)
14- J = ForwardDiff. jacobian (f, m_i)
15- S = X_A_Xt (C, J)
16+ u_i = mul! (tmp, SolProj, m_i)
17+
18+ ForwardDiff. jacobian! (result, residualf, u_i)
19+ z = DiffResults. value (result)
20+ J = DiffResults. jacobian (result)
1621
17- m_i_new, C_i_new = update (x, Gaussian (z .+ (J * (m - m_i)), S), J)
22+ mul! (H, J, SolProj)
23+ X_A_Xt! (S, C, H)
1824
19- if norm (m_i_new .- m_i) < ϵ₁ && norm (z) < ϵ₂
25+ # m_i_new, C_i_new = update(x, Gaussian(z .+ (H * (m - m_i)), S), H)
26+ # More efficient update with less allocations:
27+ K = C * (H' / S)
28+ m_tmp .= m_i .- m
29+ mul! (z_tmp, H, m_tmp)
30+ z_tmp .- = z
31+ mul! (m_tmp, K, z_tmp)
32+ m_i_new = m_tmp .+ = m
33+
34+ if (norm (m_i_new .- m_i) < ϵ₁ && norm (z) < ϵ₂) || (i == maxiters)
35+ C_i_new = X_A_Xt! (C_tmp, C, (I - K * H))
2036 break
2137 end
2238 m_i = m_i_new
2339 end
24- return Gaussian (m_i_new, C_i_new)
40+
41+ copy! (integ. cache. x, Gaussian (m_i_new, C_i_new))
42+
43+ return nothing
2544end
2645
2746"""
@@ -33,6 +52,11 @@ Update the state to satisfy a zero residual function via iterated extended Kalma
3352performs an iterated extended Kalman filter update to keep the residual measurement to be
3453zero. Additional arguments and keyword arguments for the `DiscreteCallback` can be passed.
3554
55+ The residual function should be `residual(u::AbstractVector)::AbstractVector`, that is
56+ _it should not be in-place_ (whereas DiffEqCallback.jl's `ManifoldProjection`) is.
57+ If you encounter `SingularException`s, make sure that the residual function is such that
58+ its Jacobian has full rank.
59+
3660# Additional keyword arguments
3761- `maxiters::Int`: Maximum number of IEKF iterations.
3862 Setting this to 1 results in a single standard EKF update.
0 commit comments