EKF H matrix
PeterBorisenko opened this issue · comments
While making C implementation based on documentation and references you provided I found that some terms in third row of a H(q) matrix have to be different.
While constructing the C(q) matrix you use an assumption that
So instead of
This is correct representation, but when calculating the partial derivatives of h(t) to make H(q) matrix with gravity reference (0, 0, -1) or (0, 0, 1) we are loosing 2 terms in the 3rd row of H(t).
Here are my calculations:
With gravity reference
Having the 3rd element of
A similar situation is with magnetic reference.
I have tested both version with real data streaming and the results are different.
Also tested this one with generated data. In my test the alternative version worked without errors, while the original did produce error while tracking loop.
I did check many papers and did not see any using that 1-2(q2+q2).
I tested with the jacobian from this implementation: https://thepoorengineer.com/en/ekf-impl/
This is a very interesting point. I will definitely test these two versions. If the one with
Thanks for bringing this to attention. We all improve this library.
Still, a reason has to be for the difference, even when their definition is mathematically equivalent.
The thing is that diagonal terms of the rotation matrix depend on every component of a quaternion.
Hence, use of a compact form makes this dependency implicit and leads to wrong derivatives. We do not see those elements, but the dependency still presents.
We must always remember that 1 here is not a mere constant but a specific constraint which contains all components of the quaternion.
Hi! Sorry for the late reply. I have evaluated the versions and I've made the changes in the commit 7ac5851
Here is how I approached the problem:
- I used the dataset of the repository RepoIMU, which contains sensor data of gyroscopes, accelerometers, and magnetometers.
- This dataset also contains measured Quaternions (using a Vicon system), and the data is synchronized to the same time-stamps.
With this data I tested three scenarios:
- Original, which is the implementation of the EKF, as it has been defined up to now.
- Refactored. The method
dhdq
defines the JacobianH
and has the option of a'refactored'
mode. This refactorization, as explained in the documentation, defines the Jacobian with several matrices, as opposed with a single one. Please see the documentation for further details. - New, which is the EKF with the Jacobian
H
defined as suggested by @PeterBorisenko
The errors were measured using the metric Quaternion Angle Difference, also available in the AHRS package.
The results are as follows:
Recording | Original | Refactored | New |
---|---|---|---|
TStick_Test02_Trial1.csv | 2.403839e-02 | 2.293890e-02 | 2.291552e-02 |
TStick_Test02_Trial2.csv | 5.514717e-02 | 5.167780e-02 | 5.070877e-02 |
TStick_Test03_Trial1.csv | 7.452721e-02 | 7.385620e-02 | 6.918890e-02 |
TStick_Test03_Trial2.csv | 7.594773e-02 | 7.184042e-02 | 7.414252e-02 |
TStick_Test03_Trial3.csv | 7.531226e-02 | 7.229252e-02 | 7.125031e-02 |
TStick_Test04_Trial1.csv | 1.067118e-01 | 1.200236e-01 | 1.051422e-01 |
TStick_Test04_Trial2.csv | 6.259173e-02 | 6.563081e-02 | 5.816036e-02 |
TStick_Test04_Trial3.csv | 8.373745e-02 | 9.052567e-02 | 7.654144e-02 |
TStick_Test06_Trial1.csv | 1.955587e-01 | 6.371324e-01 | 2.015852e-01 |
TStick_Test06_Trial2.csv | 1.974966e-01 | 1.723569e+00 | 1.822505e-01 |
TStick_Test07_Trial1.csv | 8.923299e-02 | 2.704295e-01 | 6.397840e-02 |
TStick_Test07_Trial2.csv | 1.040668e-01 | 3.232865e-01 | 9.499060e-02 |
TStick_Test07_Trial3.csv | 8.938379e-02 | 2.445449e-01 | 9.187592e-02 |
TStick_Test08_Trial1.csv | 8.957960e-02 | 1.394432e-01 | 3.857306e-02 |
TStick_Test08_Trial2.csv | 4.101043e-02 | 4.663590e-02 | 3.618648e-02 |
TStick_Test08_Trial3.csv | 7.104875e-02 | 8.780755e-02 | 3.690568e-02 |
TStick_Test09_Trial1.csv | 2.315799e-01 | 2.501628e-01 | 5.140734e-02 |
TStick_Test09_Trial2.csv | 1.997696e-01 | 2.253895e-01 | 3.861103e-02 |
TStick_Test09_Trial3.csv | 1.492741e-01 | 1.579206e-01 | 4.027533e-02 |
TStick_Test10_Trial1.csv | 6.521880e-02 | 6.539487e-02 | 6.756707e-02 |
TStick_Test10_Trial2.csv | 6.774476e-02 | 7.465652e-02 | 5.302413e-02 |
TStick_Test10_Trial3.csv | 6.020060e-02 | 6.207642e-02 | 5.850808e-02 |
TStick_Test11_Trial1.csv | 6.469981e-02 | 6.649664e-02 | 6.350834e-02 |
TStick_Test11_Trial2.csv | 6.388582e-02 | 7.237841e-02 | 6.302069e-02 |
TStick_Test11_Trial3.csv | 6.513871e-02 | 6.984346e-02 | 6.479358e-02 |
When plotting this information, we get:
A short description using pandas
will print:
Original Refactored New
count 25.000000 25.000000 25.000000
mean 0.096116 0.203438 0.071004
std 0.054602 0.342858 0.041352
min 0.024038 0.022939 0.022916
25% 0.064700 0.066497 0.050709
50% 0.075312 0.074657 0.063508
75% 0.104067 0.225389 0.074143
max 0.231580 1.723569 0.201585
We see the refactored mode has the worst performance, with a mean error of ~ 0.2, and a standard deviation of 0.34, while the original version has a mean error of 0.096, and the updated one is equal to 0.07.
Clearly, the updated version performs much better, and I've changed accordingly. Now the Jacobian matrix is defined as:
when using the accelerometers, and as:
when using accelerometers and magnetometers.
Thanks for bringing this topic. If there are further questions, feel free to ask them here. Otherwise, we can close this issue.
I think we can confidently close this issue. The changes have been implemented in code and in the docstrings generating the documentation.