Absolute position tracking using iPhone magnetometer


A recent project I was working on required absolute positioning and while waiting for Valves lighthouse and Facebooks to open source it’s tracking solutions I thought I’d take a primitive stab at EM (electro magnetic) positioning using a phone magnetometer purely for the purpose of learning the challenges involved. I’m an experienced software developer and a hobbyist hardware hacker, so I tried solving most problems using software where possible.

EM tracking has an advantage over optical tracking over that it doesn’t need line of sight but most optical tracking systems have overcome this limitation by using two base stations.

All professional EM tracking solutions like products from Polhemus, Ascension and Razor Hydra all use alternating EM fields and a receiving coil to measure induced currents and this allows for turning out or filtering out everything except for the carrier frequency. The down side is the you need more complex hardware/circuits like signal generators/oscillators for the transmitter and with op-amps with high/low pass filters etc on the receiver.

So for stage one I decided to just use the magnetometer sensor on my phone and see how far I can get. As the first step I made a quick prototype using my phone, a relay switch for the transmitter coil and a 9v battery. Due to inverse square law of magnetic field propagation I was only able to get accurate readings up to a centimeter or two.


Always try brute force first, I had to push as much current as possible and needed a bigger coil to create a much stronger magnetic field. First part is easy, 9v batteries are cheap and connect 4 in series and voila you have 36v.

The later is tricky while the EM field generated goes up with number of turns, the longer wire also increases the resistance which decreasing the current passing through. I ended up using a 100MH inductor with 76 Ohm which seems to be a good balance between generated EM field and resistance. This setup created a strong enough field to be detectable up to 5-6 cm which was enough for my project.

The coil would overheat quickly which can be solved by pulsing the coil only long enough for the magnetometer to register it, which turned out to be around 20ms for the one on iPhone 6. Trilateration in 3d requires three points of reference so I got three of these coils transmitting 20ms seconds at a time with the help of a ATTiny and a few MOSFETS.


Due to the lack of wired open input/output ports on the iPhone and lack of wifi/bluetooth on the AtTiny I decided to use a sync cycle to figure out coil is transmitting.

Transmit pulses would be evenly spaced with a empty pulse used as a sync pulse. The rest was signal processing on the iphone, which turned out to be a lot harder than I thought it would be but creating a system to record and playback data so I can rerun and debug with exact dataset helped a lot. Also adding a real time charts and a 3d scene to the iphone app was a great way to visualise what was going on. Another good way to compare the results of two methods (eg: different noise filtering algorithms) was to record videos of each one runnng in the simulator with test data and play it back side by side.

Simulator Screen Shot 31 Aug 2016, 7.39.26 PM

Since the phone is moving all the time, which changes the earth’s magnetic field, each reading had to be normalised against the background using the interquartile_mean.

In order to identify which coil is transmitting, find the highest peak and then find 3 other transmissions equal distance from it, since the time between pulses are known constant, this will give us 4 values and the lowest one will be the sync cycle which can be used to figure out which pulse came from which coil.


Now the intensity at x distance from each coil can be turned into distance from coil based on inverse square law. This is finally used to trilateration and find the absolute coordinates in 3d space relative to the transmitters.

So how well does it track? The answer is not very well, but in true sprit of brute forcing with more power, I ordered some, more accurate MLX90393 magnetometers and hope to combine input from all 3 for a more accurate result and also ordered some A23 12v batteries to push the voltage up to 48v which should improving tracking around the edges.

One more video: https://youtu.be/EHWGtElzWaY

iOS app swift source code:

Arduino Transmitter source code:

Just .