Android 如何获得磁场矢量,与设备旋转无关?

Android 如何获得磁场矢量,与设备旋转无关?,android,android-sensors,Android,Android Sensors,我想归档的是一种位置的“磁指纹”。我使用磁场传感器,如果我得到X、Y和Z轴(遗憾的是没有进一步解释)的磁场 问题是,当我旋转设备时,值会发生变化,所以我猜3轴是相对于设备的。我需要的是补偿设备的旋转,这样无论设备如何旋转,我都能得到相同的3个值 我试着和旋转矩阵相乘(我知道如何得到它),试着和倾斜矩阵相乘,等等,但没有任何效果。无论我尝试什么,当我旋转设备时,值仍然会改变 那么,有人知道如何做对吗?更喜欢代码,因为我读了很多东西,比如“那么你必须使用旋转矩阵进行补偿”,但没有找到一个具体的工作示

我想归档的是一种位置的“磁指纹”。我使用磁场传感器,如果我得到X、Y和Z轴(遗憾的是没有进一步解释)的磁场

问题是,当我旋转设备时,值会发生变化,所以我猜3轴是相对于设备的。我需要的是补偿设备的旋转,这样无论设备如何旋转,我都能得到相同的3个值

我试着和旋转矩阵相乘(我知道如何得到它),试着和倾斜矩阵相乘,等等,但没有任何效果。无论我尝试什么,当我旋转设备时,值仍然会改变


那么,有人知道如何做对吗?更喜欢代码,因为我读了很多东西,比如“那么你必须使用旋转矩阵进行补偿”,但没有找到一个具体的工作示例。

磁场矢量的坐标是相对于手机给出的,如下图所示:

要获得下图坐标系中的磁场矢量:

必须将磁矢量
m
与从like
R*m
检索的旋转矩阵
R
相乘。这个矢量将穿过地球指向磁北极

如果还将其乘以倾角
I
,则矢量将绕X轴旋转,以完全位于Y轴上:

[0 m 0]=I*R*地磁(m=地磁场的大小)


这个矢量对于地球上的每个位置都应该是恒定的。但是,手机上的结果可能会出现轻微偏差,因为旋转设备时必须非常小心,不要改变传感器的位置。

要获得磁场强度,必须获得磁场的x、y、z值(来自传感器。键入\u磁场),并应用以下公式:

double magnetic_field_strength = Math.sqrt( (Xvalue*Xvalue) + (Yvalue*Yvalue) + (Zvalue*Zvalue) );
磁场强度以微特斯拉(µT)表示
可以指出的是,地球的平均磁场强度为50µT,根据


因此,可能的代码是:

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;
        }                
    }
}
解决方案: 可能性1:

关于旋转,磁场是非常不稳定的,你不能仅仅通过一些数学来转换横向和纵向值,主要原因是硬件对不同的轴使用不同的捕捉器,那么当旋转发生时,你使用不同的硬件捕捉器,值将永远不会相同,在某些高端设备上,它将是相同的,但在大多数设备上不是

如果你想在许多设备上依赖和兼容一些东西,你需要忘记用旋转来计算磁场,而只是用你的应用程序来强制定向

可能性2:

您谈到了一个位置的“磁指纹”。如果只是关于在没有GPS的情况下识别一个位置,那么您还有很多其他信息要处理。首先是“Wifi SSID”,然后是“移动网络单元”,还有“连接的Wifi”等等。如果您对此感兴趣,我可以给您代码

可能性3:

如果你绝对需要计算你所在位置的磁场,并且不想强迫旋转。。。你可以捕捉风景画和肖像画的价值,而不是计算它们。然后,当您比较时,只需比较两个值

此外,如果您想找到有磁铁的地方或高磁位置,您可以使用高公差百分比来检测磁铁是否存在

注意:

如果你坚持数学,别忘了几乎每个设备上的函数都是不同的。。。 请不要犹豫,提供更多关于您的问题的信息。我很乐意修改我的答案;)

这样做

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

        }
    }

抱歉,没有。这个例子显示了如何获取设备的方向-但这不是我需要的。是的,我找到了这条I*R*地磁线并尝试了它,但值不是恒定的。当然,当我旋转设备时,由于传感器的位置变化,它们可能会略有变化,但在我的情况下,它们的变化幅度为20或更多,这是不正确的。另外,如果我理解正确的话,I*R*地磁的结果将是x和z始终为0的向量?是的,这可能不是你想要的。你可能只是想要Rm。从IR*m在y轴上得到的值实际上是磁场强度,这是从传感器读取的矢量的绝对值(“长度”)。奇怪的是,你得到了如此大的偏差。那么,你找到解决方案了吗?看看我的答案,你有没有找到解决这个问题的方法?没有,不幸的是没有:-/是的,这给了我力量,但没有方向。我所寻找的是强度和方向,但与设备的当前方向无关。但我还是放弃了。这看起来很有希望。我有更多的矿石少放弃该项目,但当我找到时间,我一定会测试你的解决方案。同时我给你+1。