【发布时间】:2009-12-10 22:59:35
【问题描述】:
我正在尝试过滤掉我的魔法手机中方向/罗盘传感器的噪音。
一些读数似乎偏离了 90-180 度,并且有很多抖动。我尝试了不同的方法,但效果有限,所以我想知道是否有人可以推荐一种算法来过滤这种噪音以获得稳定的输出。
BR,马德斯
【问题讨论】:
标签: android
我正在尝试过滤掉我的魔法手机中方向/罗盘传感器的噪音。
一些读数似乎偏离了 90-180 度,并且有很多抖动。我尝试了不同的方法,但效果有限,所以我想知道是否有人可以推荐一种算法来过滤这种噪音以获得稳定的输出。
BR,马德斯
【问题讨论】:
标签: android
您需要低通滤波器。 wikipedia上有解释和简单算法
【讨论】:
这真的很晚了,但它可能会帮助像我这样提出这个问题的人。
使用类型旋转矢量传感器。无需使用低通滤波器或计算最后 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]);
}
我发现这些值非常快速和流畅,并在我的应用程序中使用它们。如果设备中不存在旋转类型矢量,我使用加速度计和磁力计作为备份,它是基于软件的传感器(传感器融合),它使用磁力计、加速度计和陀螺仪(如果存在)。
【讨论】:
我只是通过使用较慢的更新时间来消除大部分噪音。我不确定 Android 是否有针对这些的内置过滤器,但它似乎稳定了很多。比如:
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:适合用户界面的速率【讨论】:
你试过什么?你每秒得到多少读数?
我会建议按照最后 X 次读数的平均值来消除“抖动”并丢弃任何与当前方向大不相同的读数,以阻止任何疯狂的“跳跃”值. 根据您获得的读数数量和平均水平,您的应用可能会失去响应能力。
以下链接可能有用。 http://www.chem.uoa.gr/applets/appletsmooth/appl_smooth2.html
【讨论】:
如果您确实得到了大量完全错误的值,您可能不想只对它们进行平均。您可以先尝试应用中值滤波器 - 取 N 个样本,计算中值,然后丢弃超过 +- 某个阈值的任何内容。之后您可以应用平滑过滤器。
【讨论】:
如果您的读数“偏离 90-180 度”,那么您需要校准指南针,或者您的传感器出现故障。
当然,磁传感器有很多抖动,但这种噪音的“标准偏差”大约有 4 度偏差。您可以选择各种数学滤波器(低通、卡尔曼)和算法(平均、下降杂散读数)来应用到可以为您提供可接受结果的测量。
【讨论】:
你正在使用:
List<Sensor> sens = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
您可能正在注册 2 个单独的传感器句柄,它们都被定向到您的 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);
}
【讨论】: