Android罗盘噪声algorithm

我正试图过滤掉魔术手机中的方向/指南针传感器的噪音。

有些读数似乎是90-180度,而且有很多的微动。 我已经尝试了不同的东西,取得了有限的成功,所以我想知道是否有人可以推荐一种algorithm来过滤这种噪音以获得稳定的输出。

BR,Mads

Solutions Collecting From Web of "Android罗盘噪声algorithm"

您需要低通滤波器。 wikipedia上有解释和简单的algorithm

这真的很晚,但是可能会帮助像我这样的人来解决这个问题。

使用types旋转vector传感器。 不需要使用低通滤波器或计算最后x个传感器值的平均值。

这是一些代码:

private float[] mMatrixR = new float[9]; private float[] mMatrixValues = new float[3]; @Override public void onSensorChanged(SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ROTATION_VECTOR: // Get rotation matrix SensorManager.getRotationMatrixFromVector(mMatrixR, event.values); SensorManager.getOrientation(mMatrixR, mMatrixValues); // Use this value in degrees mAzimuth = Math.toDegrees(mMatrixValues[0]); } 

我发现这些值非常快速和平滑,并在我的应用程序中使用这些值。 如果设备中没有旋转型vector,我使用加速度计和磁力计作为备用,它是一个使用磁力计,加速度计和陀螺仪(如果有的话)的基于软件的传感器(传感器融合)。

通过使用较慢的更新时间,我摆脱了大部分的噪音。 我不确定Android是否有内置的filter,但似乎很稳定。 就像是:

 mSensorManager.registerListener( mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), // SENSOR_DELAY_UI, instead of SENDOR_DELAY_FASTEST (or similar) // seems to iron out a lot of the jitter SensorManager.SENSOR_DELAY_UI ); 

SensorManager提供:

  • SENSOR_DELAY_FASTEST :尽可能快地获取传感器数据
  • SENSOR_DELAY_GAME :适合游戏的价格
  • SENSOR_DELAY_NORMAL :适用于屏幕方向更改的速率(默认)
  • SENSOR_DELAY_UI :适合用户界面的速率

你有什么尝试? 你每秒得到多less个读数?

我会根据平均最近X次的读数来提出一些build议,以摆脱“摇晃”,抛弃与当前方向大不相同的任何读数,以阻止任何疯狂的“跳跃”值。 根据您获得的阅读数量以及您所做的平均数量,您的应用可能会失去响应能力。

以下链接可能会有用。 http://www.chem.uoa.gr/applets/appletsmooth/appl_smooth2.html

如果你确实得到了大量完全错误的值,那么你可能不想仅仅对它们进行平均。 你可以尝试先应用一个中值滤波器 – 取N个样本,计算中位数,然后丢弃超过某个阈值的值。 之后您可以应用平滑filter。

如果你的读数是“90-180度”,那么你需要校准你的指南针,或者你的传感器有故障。

当然,磁性传感器有很多抖动,但这种噪声的“标准偏差”大约是4度。 您可以select多种math滤波器(低通滤波器,卡尔曼滤波器)和algorithm(求平均值,丢弃杂散读数)来应用于可以给出可接受结果的测量值。

你正在用吗:

 List<Sensor> sens = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION); 

您可能正在注册两个独立的传感器手柄,这两个手柄都指向您的onSensorChanged方法。 现在,在我的onSensorChanged方法中,我将根据供应商名称将方位值发送到主方法或次方法。 所以试试这个代码:

  Sensor sen = e.sensor; double bearing = 0; if (sen.getType()==Sensor.TYPE_ORIENTATION) { bearing = e.values[SensorManager.DATA_X]; } if (sen.getVendor().equals(sensorVendors[0])) { myCompassView.setBearing(bearing); } else { myCompassView.setSecondaryBearing(bearing); }