How to:Analyze compass performance./precision

what’s the correct way to analyze logs to check if magnetometer is 100% well calibrated, and reliable ?
I am thinking mainly about detection of deviation between compass indicated heading vs actual heading.

[quote=“Andre-K”]what’s the correct way to analyze logs to check if magnetometer is 100% well calibrated, and reliable ?
I am thinking mainly about detection of deviation between compass indicated heading vs actual heading.[/quote]

I use the pymavlink set of tools to analyze logs. It is built for analyzing tlogs, we’ve added dataflash log support to it, but I’m sort of implementing new functions as I go. So, there’s not a lot of stuff for df logs in the distributed version. All this can probably be done with other tools as well.

The sources of compass error that we care about are:

  • Incorrect offsets (“hard-iron” calibration)
  • Motor interference
  • Incorrect declination
  • Incorrect orientation
  • One that we don’t care about (yet) is scale factor (“soft-iron” calibration), which may eventually add another 3 parameters. In the process of preparing for this post, I’ve found the APM 2.5 that I’m testing on the bench to have a 12.3% difference in scaling between the Y and Z axes. If we were to implement mag scaling in APM, its scaling parameters would need to be set to (1.041,1.000,1.123)

Ok, on to the things that actually matter for our purposes:

In order to diagnose incorrect offsets, you want to graph the magnitude of the magnetic field. In pymavlink, there’s a function called mag_field, which you can use like this:

That’ll get you a graph like fig. 1 You can also graph sqrt(RAW_IMU.xmag2+RAW_IMU.ymag2+RAW_IMU.zmag**2) - same thing, but mag_field has some useful features that we’ll see in a second.
We are trying to measure earth’s magnetic field only. Earth’s magnetic field is on constant magnitude, so if the graph is squiggly we have a problem. Real graphs will have much more squiggly… we’re going to come up with pretty small offsets. We run magfit.py over the log (tlog only), and like magic we get the offsets (30.50, -20.30, -6.77). Of note, “perfect” hand-calibrated offsets for this board are (15.5, -18, -31) - as noted above, it has scaling issues that magfit doesn’t account for, and these are throwing everything off. We can check what change our offsets made using mag_field - I’ll put these 3 graphs in figure 2:

[code]- no offsets: mag_field(RAW_IMU)

  • computed offsets: mag_field(RAW_IMU,SENSOR_OFFSETS,(30.50, -20.30, -6.77))
  • perfect offsets: mag_field(RAW_IMU,SENSOR_OFFSETS,(15.5, -18, -31))
  • bad offsets: mag_field(RAW_IMU,SENSOR_OFFSETS,(-100, 50, 150))[/code]
    Perfect offsets is still squiggly because of the scale factor. I’ve written a version of mag_field that lets me add scale factors, and I can get a perfectly flat line.

We can graph the magnetic heading as well. mag_heading takes similar arguments, but it needs our attitude as well. Fig. 3 has the previous 4 graphs, but instead of field strength, we’re graphing heading. The bad offsets are very bad. The other 3 are close, but they can get 5 or so degrees apart.

Motor interference will also manifest as a variation in magnetic field strength, but this time it will correlate to current draw or throttle. I don’t have graphs for you on this one, but ultimately if you see throttle correlating with mag_field, you have interference from nearby high-current wires and the user has to run compassmot or physically change something to fix it.

Incorrect declination is rare because of autodec. We see it when people decide that declination is the only thing that matters for compass and they stick it on CH6 and try to tune it.

Incorrect orientation is an obvious one that seems like it should be easy to test for, but it is a bit tricky. You can compare to the gyros.
I’ve been using something like this (this is tlog-specific, but can be adapted for df logs):

mavgraph.py [filename] --marker=. \ "delta_angle(degrees(-atan2(RAW_IMU.ymag, RAW_IMU.xmag)),1) if sqrt(RAW_IMU.ymag**2+RAW_IMU.xmag**2) > sqrt(RAW_IMU.ymag**2+RAW_IMU.xmag**2+RAW_IMU.zmag**2)*0.3 else 0" \ "delay_1(degrees(RAW_IMU.zgyro*0.001),2) if sqrt(RAW_IMU.ymag**2+RAW_IMU.xmag**2) > sqrt(RAW_IMU.ymag**2+RAW_IMU.xmag**2+RAW_IMU.zmag**2)*0.3 else 0"

This is for rotation about the z axis specifically. It will give you a graph that looks like figure 4. I am working on creating an algorithm that will do this at the same time as the compass offset routine. Here’s sample output from the same log: pastebin.com/sN9Lh2Kz (column 1 is orientation, column 2 is the total rotation error between the compass data and the gyro data, column 3 is the amount of rotation data in each axis in radians.) So far it isn’t working great (I think maybe it needs higher rate gyro data), but I’m hoping to get there.

I’ll attach the log that I’m using as well.

Thank you for this very detailed info.