All of our smartphones have an integrated compass. It can be very useful when you are looking for in which direction you should start heading while walking. However, you have probably noticed that sometimes, the direction showed by our phones can be quite...wrong! It happens when the compass has not been calibrated correctly. But if you try to turn the compass around in every direction, you'll probably notice that the direction arrow finally takes the right direction. Why? Because the smartphone is doing a "live" calibration as you move the compass.

What you should keep from this introduction is that **compass calibration is fundamental** ! Don't intend on using a magnetic sensor in your project unless you have it calibrated. Otherwise, the data you'll be using will probably be inaccurate, if not completely random 😀

##### Back to basics

###### What does a magnetometer do?

"Well, it obviously gives you your heading!"

"NOPE! (*Chuck Testa*)"

The magnetometer gives you a three dimensional vector of the magnetic field it senses. This magnetic field is a combination of both the earth's field and of the magnetic field created by all the surrounding objects. And this second magnetic field is far from being negligible, especially in our hobbyist projects where there's electronics (and motors) all around.

Theoretically, the measured magnetic field should :

- be centered around 0
- always have the same strength

If we could represent it in 3D, it should basically look like a perfect sphere centered in 0.

In reality :

- it is not centered around 0, because of the presence of other magnetic fields around the sensors(such as other magnets, electric wires) : it is
*hard iron distortion*. - it does not have a constant strength, because of the presence of other ferromagnetic materials around the sensors, which skew the magnetic field. This is
*soft iron distortion.*

What we get is essentially a potato-shaped magnetic field (because of soft iron distortion), that is not even centered (because of hard iron distortion).

##### Calibration techniques

###### Hard Iron distortion

Hard iron errors introduce an offset in the magnetometer data

To get this offset is pretty simple : we keep track of the maximum and minimum values the magnetometer outputs on each axis while moving it in space. From what we know the maximum and minimum should be centered around 0, so we get the offset by :

We can then subtract the measured offset from each raw measurement in order to get hard iron free data.

###### Soft Iron distortion

Here, the work consist in transforming a potato in an orange. Or, transforming an ellipsoid into a sphere, if you prefer. It's actually easier than it sounds. There are obviously mathematical formulas that involve matrices but let's keep it simple here.

Let's say earth magnetic field's value is F. It is the norm of the vector given by the magnetometer. While we've seen it should be the same on the three axes, experience shows it's not. So let's assume we have measured the maximum magnetic field Fx for the x axis,Fy for the y axis, Fz for the z axis.

We then calculate the average field value F by :

Let's assume that F = 1. If F_x = 0.8, it means that F_x is only 80% of the average field value. Hence the potato. Now if we simply multiply all the incoming x values by F/F_x, the potato effect, will be gone, as we expand the range of the x values so that it is no longer 80% of what it should be, but 100%.

###### Final equation

If we no combine the two equations and use vectors, we get:

Scale transforms the potato into an orange(soft iron distortion) and the Offsets vector brings it back in the center(hard iron).

###### Calibration process

The calibration consist in getting the min/max values of x/y/z fields, and then calculations the offsets and scale factors. The more you move the magnetometer in all directions, the more efficient your calibration will be.

###### Using calibration data

// We get the raw values here in mx,my,mz //(this is pseudo code) mag.getHeading(); // Now we apply the calibration data mx = (int)((scale_x)*(mx-x_offset)); my = (int)((scale_y)*(my-y_offset)); mz = (int)((scale_y)*(mz-z_offset));

##### Results

Using Processing and a slightly modified version of this program, I was able to quickly draw the 3D representation of the magnetic field. The video shows the before/after.

As you can see, hard irons distortion was HUGE before calibration. I could never have gotten reliable readings without correcting them. Soft iron errors were also present, and completely removed by the calibration. 🙂