Как получить вектор магнитного поля, не зависящий от вращения устройства?
То, что я хочу заархивировать, это своего рода "магнитный отпечаток" места. Я использую датчик MAGNETIC_FIELD, и в случае, если я получаю 3 значения для (к сожалению, не объяснено далее) осей X, Y и Z.
Проблема в том, что значения меняются при повороте устройства, поэтому я предполагаю, что 3 оси относятся к устройству. Мне нужно компенсировать вращение устройства, чтобы получить те же 3 значения, независимо от того, как устройство вращается.
Я пытался умножить с матрицей вращения (я знаю, как получить это), пытался умножить с матрицей наклона и так далее, но ничего не работает. Независимо от того, что я пытаюсь сделать, значения меняются при повороте устройства.
Так кто-нибудь знает, как это сделать правильно? Предпочтительно с кодом, потому что я читал много вещей типа "ну, тогда вам придется компенсировать это, используя матрицу вращения", но не нашел ни одного конкретного, рабочего примера.
4 ответа
Сделай это
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]);
}
}
Решение:
Возможность 1:
MAGNETIC_FIELD очень нестабилен в отношении поворота, который вы не могли бы использовать для вычисления значений ландшафта и портрета просто по какой-то математике, основная причина в том, что аппаратное обеспечение использует разные захватчики для разных осей, тогда, когда происходит поворот, вы используете другой аппаратный захватчик, значение никогда не будет одинаковым, на некоторых устройствах высокого класса это будет то же самое, но не на большинстве устройств.
если вы хотите, чтобы что-то полагалось и было совместимо на многих устройствах, вам нужно забыть вычисление MAGNETIC_FIELD с вращением, а просто настроить ориентацию в вашем приложении. Принудительно установить портретную ориентацию
Возможность 2:
Ты говорил о "magnetic fingerprint" of a location.
если речь идет только об определении местоположения без GPS, у вас есть много другой информации для работы. сначала "SSID Wifi", затем "Ячейки мобильных сетей", а также "Подключенный Wi-Fi" и т. д. Если вас это интересует, я могу дать вам код для него.
Возможность 3:
Если вам абсолютно необходимо рассчитать MAGNETIC_FIELD для вашего местоположения, и вы не хотите принудительно вращать... вы можете поймать как ландшафт, так и портрет вместо их вычисления. затем при сравнении просто сравните оба значения.
Кроме того, если вы хотите найти место, где у вас есть магнит или магнитное местоположение, вы можете работать с высоким процентом толерантности, просто чтобы определить, присутствует ли магнит или около того,
Замечания:
Если вы придерживаетесь математики, не забывайте, что функция будет отличаться практически на каждом устройстве... не стесняйтесь давать больше информации по вашему вопросу, я буду рад адаптировать мой ответ;)
Чтобы получить силу магнитного поля, вы должны получить значения магнитного поля x,y,z (из Sensor.TYPE_MAGNETIC_FIELD) и применить следующую формулу:
double magnetic_field_strength = Math.sqrt( (Xvalue*Xvalue) + (Yvalue*Yvalue) + (Zvalue*Zvalue) );
Сила магнитного поля выражена в микротеслах (мкТл)
Можно отметить, что средняя напряженность магнитного поля Земли составляет 50 мкТл, согласно этому сайту.
Таким образом, возможный код будет:
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;
}
}
}
Координаты вектора магнитного поля даны относительно мобильного телефона, как на этом рисунке:
Чтобы получить вектор магнитного поля в системе координат следующей картины:
Вы должны умножить магнитный вектор m
с матрицей вращения R
извлекается из getRotationMatrix() как R * m
, Этот вектор будет указывать через землю на северный магнитный полюс.
Если вы также умножаете это с наклоном I
вектор будет вращаться вокруг оси X, чтобы быть полностью на оси Y:
[0 m 0] = I * R * геомагнитный (m = величина геомагнитного поля)
Этот вектор должен быть постоянным для каждой позиции на земле. Тем не менее, результаты на вашем мобильном телефоне могут показать небольшие отклонения, потому что вы должны быть очень осторожны, чтобы не изменить положение датчика при вращении устройства.