I was digging into to the magnetic calibration part of the sensor fusion algorithm, in particular i wanted to find out the mechanism under which the magnetic buffer gets filled.
I wasn't able to find much information online apart from a document titled:
Magnetic Calibration
(magnetic.c)
Technical Note
Document TBD
Version: Draft
Authors: Mark Pedley and Michael Stanley
Date: September 2014
The general procedure works as described in the document:
The accelerometer is used to index the magnetic measurements as a function of the two 'pseudo angles' with tangents equal to the ratio of y to x and z to x accelerometer measurements. The accelerometer measurements lie of the 1g sphere and the magnetic measurements lie of the magnetic ellipsoid. The indexing by accelerometer angles therefore provides a convenient binning of the magnetic ellipsoid by PCB orientation.
But the document seems outdated, since it states that the accelerometer is being used to index the magnetic measurements, while in the current version the magnetometer measurements are being used. There's no trace of accelerometer structs being passed in the function signature:
void iUpdateMagBuffer(struct MagBuffer *pthisMagBuffer, struct MagSensor *pthisMag,int32_t loopcounter)
Instead, in the current version the MagSensor::iBc (averaged calibrated measurement (counts)) are being used to calculate the tangents like so:
int16_t itanj, itank; // indexing accelerometer ratios
// more code here(...)
if (pthisMag->iBc[CHZ] == 0) return;
itanj = (100 * (int32_t) pthisMag->iBc[CHX]) / ((int32_t) pthisMag->iBc[CHZ]);
itank = (100 * (int32_t) pthisMag->iBc[CHY]) / ((int32_t) pthisMag->iBc[CHZ]);
Here’s the issue: I was running some IMU+mag samples obtained from an LSM9DS1 sensor, which come as int16_t values. I calculated in parallel the tangents using those measurements, but I found that the values didn’t match. A big number of samples give tangent values that overflow the int16 capacity, resulting in an erroneous calculation on the tangents.
Moreover, the tangent calculation multiplied by 100 is, most of the times, orders of magnitude bigger than the values stored on the array used for indexing, the MagBuffer::tanarray
(-438, -207, -125, -79, -48, -22, 0, 22, 48, 79, 125, 207, 438)
(An explanation of where these values come from here: https://community.nxp.com/t5/Sensors/Is-there-any-reason-why-MAGBUFFSIZEX-is-14-instead-of-12-as/m-p...)
Do anyone has a clue of what's happening here? Is this an expected behavior?
This seems to cause the buffer filling mechanism to use the #4 method (the slower one) much more that what it should be. Apart from this the general algorithm works correctly
Thanks in advance
Well, after giving it a deeper look (and using a longer run) it seems like I need to correct some of my assumptions:
1. The buffer filling case #1 is more used:
Once the buffer is full the case the strategy switches completely. In this and previous runs the calibration values where added manually from a previous calibration, so the algorithm starts with `fV`, `finvW`, `fB`, `iValidMagCal`, etc already set.
2. The non overflowed (int32_t) tan values are just in some counted occasions much bigger than the overflowed ones.
But still: if someone can explain a little further why this method works I would really appreciate it.