How can I get the magnetic field vector, independent of the device rotation?
Asked Answered
T

4

10

What I want to archieve is a sort of "magnetic fingerprint" of a location. I use the MAGNETIC_FIELD sensor and in the event I get the 3 values for the (unfortunately not further explained) X, Y and Z axis.

Problem is, that the values change as I rotate the device, so I guess the 3 axis are relative to the device. What I'd need is to compensate the device rotation so that I get the same 3 values, regardless of how the device is rotated.

I tried to multiply with the rotation matrix (I know how to get that), tried to multiply with the inclination matrix and so on, but nothing works. Regardless of what I try, still the values change when I rotate the device.

So does anyone know how to do it right? Preferrably with code, because I read a lot of stuff like 'well then you'll have to compensate that using rotation matrix' but did not find a single concrete, working example.

Thinnish answered 2/8, 2012 at 7:32 Comment(4)
so, have u found a solution yet?Hueyhuff
See my answer at #15315629Seessel
Did you ever find any solution to this issue?Cretinism
Nope, unfortunately not :-/Thinnish
W
3

Solution :

Possibility 1 :

MAGNETIC_FIELD is very unstable regarding rotation you could not relate on just some math to convert landscape and portrait values, the main reason is the hardware use different captors for different axises then when rotate occur you use a different hardware captor the value will never be the same, on some hi end device it will be the same but not on most devices.

if you want something to rely on and compatible on many devices you need to forget calculating the MAGNETIC_FIELD with rotation, but just force the orientation with your application. Force "portrait" orientation mode

Possibility 2 :

You talked about "magnetic fingerprint" of a location. if it's only about identifying a location without GPS you have plenty of other informations to work with. first "Wifi SSIDs" then "Mobile Networks Cells" also "Connected Wifi" etc. if this interest you i could give you code for it.

Possibility 3 :

If you absolutely need to calculate MAGNETIC_FIELD for your location, and don't want to force rotation... you could catch both value landscape and portrait instead of calculating them. then when you compare just compare to both values.

Also if you are looking to locate place where you have magnet or hight magnetic location you could work with a hi tolerance percentage just to detect if a magnet is present or so,

Note :

If you stick with the math don't forget that the function will be different on almost every device... don't hesitate to give more infos about your question i'll be pleased to adapt my answer ;)

Warhead answered 13/6, 2015 at 3:53 Comment(0)
M
3

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]);

        }
    }
Maghutte answered 13/8, 2015 at 21:50 Comment(1)
This looks quite promising. I have more ore less abandoned the project, but when I find the time, I will definitely test your solution. In the meantime I give you +1.Thinnish
G
-1

The coordinates of the magnetic field vector are given relative to the mobile phone, like in this picture:

enter image description here

To get the magnetic field vector in the coordinate system of the following picture:

enter image description here

you have to multiply the magnetic vector m with the rotation matrix R retrieved from getRotationMatrix() like R * m. This vector will point through the earth to the magnetic north pole.

If you also multiply it with inclination I, the vector would be rotated around the X-axis to be fully on the Y-axis:

[0 m 0] = I * R * geomagnetic (m = magnitude of geomagnetic field)

This vector should be constant for each position on the earth. However, results on your mobile phone may show slight deviations, because you have to be very careful not to change the position of the sensor when rotating the device.

Gambier answered 2/8, 2012 at 8:28 Comment(3)
Sorry but no. This example shows how to get the orientation of the device - but this is not what I need.Thinnish
Yeah I found this I * R * geomagnetic line and tried it, but the values are not constant. Sure they may vary a little when I rotate the device due to position changes of the sensor, but in my case they vary by magnitudes of 20 or more, which cannot be correct. Also, if I understand it right, the result of I * R * geomagnetic would be a vector with x and z always 0?Thinnish
Yes, which is probably not what you want. You probably just want Rm. The value you get at the y-axis from IR*m is actually the magnetic field strength, which is the absolute value ("length") of the vector you read off the sensor. It's strange that you get such large deviations.Gambier
V
-1

to get the strength of the magnetic field, you have to get the x,y,z values of the magnetic field (from Sensor.TYPE_MAGNETIC_FIELD), and apply the following formula:

double magnetic_field_strength = Math.sqrt( (Xvalue*Xvalue) + (Yvalue*Yvalue) + (Zvalue*Zvalue) );

magnetic_field_strength is expressed in microtesla (µT)
It could be noted that the average magnetic field strength of the Earth is 50 µT, according to this website.


So a possible code would be:

private SensorEventListener sensorEventListener = new SensorEventListener() {   
    @Override
    public void onSensorChanged(SensorEvent event) {

        switch (event.sensor.getType()) {
        case Sensor.TYPE_MAGNETIC_FIELD:                        
            magnetic_field_strength = Math.sqrt((event.values[0]*event.values[0])+(event.values[1]*event.values[1])+(event.values[2]*event.values[2]));
            break;                      
        default: 
            return;
        }                
    }
}
Viquelia answered 7/11, 2013 at 14:23 Comment(1)
Yes that gives me the strength, but no direction. What I has looking for is strength and direction, but independent of the current orientation of the device. But I gave it up anyways.Thinnish

© 2022 - 2024 — McMap. All rights reserved.