不可靠的Android Compass定位(低通滤波器)

时间:2011-01-15 11:50:43

标签: android algorithm orientation signal-processing compass-geolocation

我正在创建一个应用程序,我需要根据设备的方向定位ImageView。 我使用MagneticField和Accelerometer传感器中的值来计算设备方向

SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerValues, magneticFieldValues)
SensorManager.getOrientation(rotationMatrix, values);
double degrees = Math.toDegrees(values[0]);

我的问题是ImageView的定位对方向的变化非常敏感。使imageview不断跳到屏幕上。 (因为学位变化)

我读到这可能是因为我的设备接近可能影响磁场读数的东西。但这不是它看起来的唯一原因。

我尝试下载一些应用程序,发现“3D compass”和“Compass”的读数仍然非常稳定(当设置噪音滤镜时),我希望我的行为相同应用

我读到我可以通过添加“低通过滤器”来调整读数的“噪音”,但我不知道如何实现这一点(因为我缺乏数学)。

我希望有人可以帮助我在我的设备上创建一个更稳定的阅读,其中设备的一点点移动不会影响当前的方向。 现在我做了一个小的

if (Math.abs(lastReadingDegrees - newReadingDegrees) > 1) { updatePosition() }

过滤掉噪音。但它不能很好地工作:)

5 个答案:

答案 0 :(得分:30)

虽然我没有在Android上使用指南针,但下面显示的基本处理(在JavaScript中)可能对您有用。

它基于加速度计上的低通滤波器,Windows Phone team建议修改以适应指南针(每360度循环行为)。

我假设指南针读数是度数,浮点数在0-360之间,输出应该相似。

您希望在过滤器中完成两件事:

  
      
  1. 如果变化很小,为防止灰尘,请逐渐转向该方向。
  2.   
  3. 如果变化很大,为防止滞后,立即转向该方向(如果您希望指南针只能以平滑的方式移动,则可以取消)。
  4.   

为此我们将有2个常数:

  
      
  1. 缓动浮动,定义移动的平滑程度(1表示没有平滑,0表示永不更新,默认值为0.5)。我们将其称为SmoothFactorCompass。
  2.   
  3. 距离大到足以立即转动的阈值(0表示始终跳跃,360表示从不跳跃,默认为30)。我们将其称为SmoothThresholdCompass。
  4.   

我们在调用中保存了一个变量,一个名为oldCompass的浮点数,它是算法的结果。

所以变量defenition是:

var SmoothFactorCompass = 0.5;
var SmoothThresholdCompass = 30.0;
var oldCompass = 0.0;

并且函数接收newCompass,并返回oldCompass作为结果。

if (Math.abs(newCompass - oldCompass) < 180) {
    if (Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
        oldCompass = newCompass;
    }
    else {
        oldCompass = oldCompass + SmoothFactorCompass * (newCompass - oldCompass);
    }
}
else {
    if (360.0 - Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
        oldCompass = newCompass;
    }
    else {
        if (oldCompass > newCompass) {
            oldCompass = (oldCompass + SmoothFactorCompass * ((360 + newCompass - oldCompass) % 360) + 360) % 360;
        } 
        else {
            oldCompass = (oldCompass - SmoothFactorCompass * ((360 - newCompass + oldCompass) % 360) + 360) % 360;
        }
    }
}

我发现该问题已于5个月前开放,可能不再相关,但我确信其他程序员可能会觉得它很有用。

Oded Elyada。

答案 1 :(得分:19)

此低通滤波器适用于弧度角。对每个罗盘读数使用添加功能,然后调用平均值来获得平均值。

public class AngleLowpassFilter {

    private final int LENGTH = 10;

    private float sumSin, sumCos;

    private ArrayDeque<Float> queue = new ArrayDeque<Float>();

    public void add(float radians){

        sumSin += (float) Math.sin(radians);

        sumCos += (float) Math.cos(radians);

        queue.add(radians);

        if(queue.size() > LENGTH){

            float old = queue.poll();

            sumSin -= Math.sin(old);

            sumCos -= Math.cos(old);
        }
    }

    public float average(){

        int size = queue.size();

        return (float) Math.atan2(sumSin / size, sumCos / size);
    }
}

使用 Math.toDegrees() Math.toRadians() 进行转换。

答案 2 :(得分:4)

请记住,例如350和10的平均值不是180.我的解决方案:

int difference = 0;
for(int i= 1;i <numberOfAngles;i++){
    difference += ( (angles[i]- angles[0] + 180 + 360 ) % 360 ) - 180;
}
averageAngle = (360 + angles[0] + ( difference / numberOfAngles ) ) % 360;

答案 3 :(得分:3)

低通滤波器(LPF)阻止快速变化的信号和
只允许信号的缓慢变化。这意味着任何小的 突然的变化将被忽略。

在软件中实现这一点的标准方法是采用运行平均值 最后N个样本并报告该值。从N开始,小到3和
继续增加N,直到在您的应用中找到足够平滑的响应。

请记住,制作N越高,系统响应越慢。

答案 4 :(得分:2)

请参阅我对此相关问题的回答:Smoothing data from a sensor

软件低通滤波器基本上是其修改版本。实际上,在那个答案中,我甚至提供了另一个相关问题的链接:Low pass filter software?