## Friday, March 16, 2012

### Magnetometer Calibration Error

In building my Sparkfun AVC robot, I wanted to investigate the effects of magnetometer calibration on heading error.

I've been working on calibrating my compass and have run into some snags along the way. I'm working on a calibration machine to measure real world error but I thought it'd be interesting to model calibration error first. Here's how. Time for Octave and and simple trig....
To keep things simple, I assumed a 2d compass, and modeled only hard iron offset and scale issues. I wrote an Octave script to do the work. In the script, I wrote a function that computes the heading error per degree of true heading given an x and y offset and x and y scale.


H=[-180:2:180]';
x=xscale*cos(H*pi/180) + xoff;
y=yscale*sin(H*pi/180) + yoff;
mag=atan2(y,x)*180/pi; % Range: 0 to 2*pi radians
err=H-mag;


For scale error, heading error maximums occur at 45°, 135°, 225°, 315°. Minimums occur 45° apart from maximums. Here's a plot of heading error due to a 10% scale calibration error:

To plot the relationship between scale error and maximum heading error, call this function for values of xscale that range from 100% to 120% of yscale, and offset of 0.  Then, obtain max(err) and plot maximum error vs heading. If axes are mis-scaled by 10% the error exceeds 5°.

Next, I run the same function with an x axis offset of 0-10% (of the radius) and matching x and y scale, and plot the result. An offset of 10% results in over 2.5° of error.

Understanding the sensitivity of maximum heading error to scale and offset calibration gives me some clear goals for magnetometer calibration.

Meanwhile I will soon investigate the approach of swinging the compass: collecting real world error data after initial calibration that I can use to further correct magnetometer readings at runtime.

Here's the Octave script:

% MagError
% Figure out theoretical magnetometer heading error vs offset,
% scale calibration errors
%
% Michael Shimniok
% www.bot-thoughts.com
%
function MAG=simplemagerr(xscale, xoff, yscale, yoff)
H=[-180:2:180]';
x=xscale*cos(H*pi/180) + xoff;
y=yscale*sin(H*pi/180) + yoff;
mag=atan2(y,x)*180/pi; % Range: 0 to 2*pi radians
err=H-mag;
%close all;
%figure;
%plot(H, mod(err-180,360)-180 )
%axis([-180,180,-10,10]);
%axis("auto y");
%xlabel("true heading", "fontsize", 14);
%ylabel("heading error", "fontsize", 14);
%grid on;
%figure;
%plot(x, y);
MAG=[H, mag, err];
end

% to plot magnetometer error vs. offset/scale calibration use
% this function
%
function ERR=MagError
ERR1=[];
for xscale=100:1:110
e=simplemagerr(xscale,0,100,0);
ERR1=[ERR1; xscale max(e(:,3))];
end

ERR2=[];
for xoff=0:0.1:10
e=simplemagerr(100,xoff,100,0);
ERR2=[ERR2; xoff max(e(:,3))];
end
figure;
plot(ERR1(:,1),ERR1(:,2));
xlabel("Scale (%)", "fontsize", 14);
ylabel("Heading error (deg)", "fontsize", 14);
title("Single axis scale vs error", "fontsize", 18);
figure;
plot(ERR2(:,1),ERR2(:,2));
xlabel("Offset (%)", "fontsize", 14);
ylabel("Heading error (deg)", "fontsize", 14);
title("Single axis offset vs error", "fontsize", 18);
end