In short, we've observed some numerical stability issues with the cxx attitude filter implementation. Below are listed some potential trouble spots and any observations/alternate implementations that have been explored.
Calculation of x_bar and z_bar
There isn't a ton to say here other than in the initial attitude filter implementation switching between the below methods of calculation x_bar and z_bar results in very different values when using floats.
I think this stems from the fact that in this particular testcase the sigma points 6 away from each other tend to be the negative of their counterpart. This can result in catastrophic cancellation when all components aren't of a similar magnitude.
Kalman Gain Calculation
The Kalman gain K is defined as being equal to P_xy * inv(P_vv) where inv denotes the matrix inverse. The straightforward implementation is to calculate inv(P_vv) directly as shown below:
UkfMatrix6x5 K;
{
UkfMatrix5x5 Q, R;
lin::qr(state.P_vv, Q, R);
lin::backward_sub(R, Q, lin::transpose(Q).eval());
K = state.P_xy * Q;
}
However, it's possible to leverage the fact that P_vv is a covariance matrix and therefore should be symmetric. It's possible to write P_vv * transpose(K) = transpose(P_XY) which then let's us determine K as shown below:
UkfMatrix6x5 K;
{
UkfMatrix5x6 M, N;
UkfMatrix5x5 L = state.P_vv;
lin::chol(L);
lin::forward_sub(L, M, lin::transpose(state.P_xy).eval());
lin::backward_sub(lin::transpose(L).eval(), N, M);
K = lin::transpose(N);
}
which should be more stable. As of the initial filter implementation, however, no noticeably different in testcase output results from switching between the two methods above.
In short, we've observed some numerical stability issues with the cxx attitude filter implementation. Below are listed some potential trouble spots and any observations/alternate implementations that have been explored.
Calculation of
x_bar
andz_bar
There isn't a ton to say here other than in the initial attitude filter implementation switching between the below methods of calculation
x_bar
andz_bar
results in very different values when using floats.The following:
I think this stems from the fact that in this particular testcase the sigma points
6
away from each other tend to be the negative of their counterpart. This can result in catastrophic cancellation when all components aren't of a similar magnitude.Kalman Gain Calculation
The Kalman gain
K
is defined as being equal toP_xy * inv(P_vv)
whereinv
denotes the matrix inverse. The straightforward implementation is to calculateinv(P_vv)
directly as shown below:However, it's possible to leverage the fact that
P_vv
is a covariance matrix and therefore should be symmetric. It's possible to writeP_vv * transpose(K) = transpose(P_XY)
which then let's us determineK
as shown below:which should be more stable. As of the initial filter implementation, however, no noticeably different in testcase output results from switching between the two methods above.