# Convert magnetic field X, Y, Z values from device into global reference frame

As per the above explanation, do this

```
private static final int TEST_GRAV = Sensor.TYPE_ACCELEROMETER;
private static final int TEST_MAG = Sensor.TYPE_MAGNETIC_FIELD;
private final float alpha = (float) 0.8;
private float gravity[] = new float[3];
private float magnetic[] = new float[3];
public void onSensorChanged(SensorEvent event) {
Sensor sensor = event.sensor;
if (sensor.getType() == TEST_GRAV) {
// Isolate the force of gravity with the low-pass filter.
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
} else if (sensor.getType() == TEST_MAG) {
magnetic[0] = event.values[0];
magnetic[1] = event.values[1];
magnetic[2] = event.values[2];
float[] R = new float[9];
float[] I = new float[9];
SensorManager.getRotationMatrix(R, I, gravity, magnetic);
float [] A_D = event.values.clone();
float [] A_W = new float[3];
A_W[0] = R[0] * A_D[0] + R[1] * A_D[1] + R[2] * A_D[2];
A_W[1] = R[3] * A_D[0] + R[4] * A_D[1] + R[5] * A_D[2];
A_W[2] = R[6] * A_D[0] + R[7] * A_D[1] + R[8] * A_D[2];
Log.d("Field","\nX :"+A_W[0]+"\nY :"+A_W[1]+"\nZ :"+A_W[2]);
}
}
```

In my comment on the checked answer on the link you provided above, I referred to my simple answer at calculate acceleration in reference to true north

Let me answer here again with more clarification. The answer is the product of the **rotation matrix** and the **magnetic field values**. If you read further on the "X is always very small" is the correct value.

The accelerometer and magnetic field sensors measure the acceleration of the device and the magnetic field of the earth at the device location respectively. They are vectors in 3 dimentional space, let call them **a** and **m** respectively.

If you stand still and rotate your device, theoretically **m** does not change assuming there are no magnetic interference from surrounding objects (actually **m** should change little, if you move around since the magnetic field of the earth should change little in a short distance). But `a`

does change, even though it should not be drastic in most situation.

Now a vector **v** in 3 dimensional space can be represented by a 3-tuples (v_1, v_2, v_3) with respect to some basis (**e_1**, **e_2**, **e_3**), i.e **v** = v_1 **e_1** + v_2 **e_2** + v_3 **e_3**. (v_1, v_2, v_3) are called the coordinates of **v** with respect to the basis (**e_1**, **e_2**, **e_3**).

In Android devices, the basis is (**x**, **y**, **z**) where, for most phone, **x** is along the shorter side and pointing right, **y** is along the longer side and pointing up and **z** is perpendicular to the screen and pointing out.

Now this basis changes as the position of the device changes. One can think these bases as a function of time (**x**(t), **y**(t), **z**(t)), in mathematics term it is a moving coordinate system.

Thus even though **m** does not change, but the **event.values** returns by the sensors are different because the basis is different (I will talk about fluctuation later). As is, the **event.values** are useless because it gives us the coordinates but we do not know what the basis is, i.e with respect to some basis we know.

Now the question is: is it possible to find the coordinates of **a** and **m** with respect to the fixed world basis (**w_1**, **w_2**, **w_3**) where **w_1** points toward East, **w_2** points toward magnetic North and **w_3** points up toward the sky?

**The answer is yes provided 2 important assumptions are satisfied.**

With these 2 assumptions it is simple to calculate (just a few cross products) the change of basis matrix **R** from the basis (**x**, **y**, **z**) to the basis (**w_1**, **w_2**, **w_3**), which in Android is called the **Rotation matrix**. Then the coordinates of a vector **v** with respect to the basis (**w_1**, **w_2**, **w_3**) is obtained by multiply **R** with the coordinates of **v** with respect to (**x**, **y**, **z**). Thus the coordinates of **m** with respect to the world coordinates system is just the product of the **rotation matrix** and the **event.values** returned by the TYPE_MAGNETIC_FIELD sensor and similarly for **a**.

In android the **rotation matrix** is obtained by calling **getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic)** and we normally pass in the returned accelerometer values for the gravity parameter and the magnetic field values for the geomagnetic.

The **2 important assumptions** are:**1-** The **gravity parameter** represents a vector lying in **w_3**, more particular it is the minus of the vector influenced by gravity alone.

Thus if you pass in the accelerometer values without filtering, the **rotation matrix** will be slightly off. That is why you need to filter the accelerometer so that the filter values are approximately just the minus gravity vector. Since the gravitational acceleration is the dominant factor in the accelerometer vector, normally low pass filter is sufficient.**2-** The **geomagnetic parameter** represents a vector lying in the plane spanned by the **w_2** and the **w_3** vectors. That is it lies in the North-Sky plane. Thus in term of the (**w_1**, **w_2**, **w_3**) basis, the first coordinate should be 0. Therefore, the "X is always very small" as you stated it above is the correct value, ideally it should be 0. Now the magnetic field values will fluctuate quite a bit. This is kind of expected, just as a regular compass needle will not stand still if you keep it in your hand and your hand shakes a little. Also, you may get interference from objects surround you and in this case the magnetic field values are unpredictable. I once test my compass app sitting near a "stone" table and my compass was off by more than 90 degrees, only by using a real compass that I found out that there is nothing wrong with my app and the "stone" table produces a real strong magnetic field.

With gravity as a dominant factor you can filter accelerometer values, but without any other knowledge, how do you fitler magnetic values? How do you know if there is or isn't any interference from surrounding objects?

You can do a lot more like complete knowledge of your device spatial position etc with the understanding of **rotation matrix**.