且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Android的指南针方向上不可靠的(低通滤波器)

更新时间:2023-02-09 22:52:04

虽然我没有带用在Android的指南针,如下所示的基本程序(在JavaScript)可能会为你工作。

它基于上加速度计的低通滤波器,建议由Windows手机团队进行了修改,以适应罗盘(循环行为每360)。

我想罗盘读数为度,0-360之间浮动,而输出应该是相似的。

您要完成两件事情中的过滤器:

  
      
  1. 如果变化很小,为prevent小胶质,逐渐转向这个方向。
  2.   
  3. 如果变化大,以prevent滞后,转向那个方向立刻(它可以,如果你想指南针在一个平稳的方式只能移动被取消)​​。
  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作为结果。

 如果(Math.abs(newCompass  -  oldCompass)< 180){
    如果(Math.abs(newCompass  -  oldCompass)> SmoothThresholdCompass){
        oldCompass = newCompass;
    }
    其他 {
        oldCompass = oldCompass + SmoothFactorCompass *(newCompass  -  oldCompass);
    }
}
其他 {
    如果(360.0  -  Math.abs(newCompass  -  oldCompass)> SmoothThresholdCompass){
        oldCompass = newCompass;
    }
    其他 {
        如果(oldCompass> newCompass){
            oldCompass =(oldCompass + SmoothFactorCompass *((360 + newCompass  -  oldCompass)%360)+ 360)%360;
        }
        其他 {
            oldCompass =(oldCompass  -  SmoothFactorCompass *((360  -  newCompass + oldCompass)%360)+ 360)%360;
        }
    }
}
 

我看,这个问题被打开了5个月之前,可能是不相关了,但我敢肯定,其他程序员可能会发现它有用。

奥德Elyada。

Im creating an application where i need to position a ImageView depending on the Orientation of the device. I use the values from a MagneticField and Accelerometer Sensors to calculate the device orientation with

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

My problem is that the positioning of the ImageView is very sensitive to changes in the orientation. Making the imageview constantly jumping around the screen. (because the degrees change)

I read that this can be because my device is close to things that can affect the magneticfield readings. But this is not the only reason it seems.

I tried downloading some applications and found that the "3D compass" and "Compass" remains extremely steady in its readings (when setting the noise filter up), i would like the same behavior in my application.

I read that i can tweak the "noise" of my readings by adding a "Low pass filter", but i have no idea how to implement this (because of my lack of Math).

Im hoping someone can help me creating a more steady reading on my device, Where a little movement to the device wont affect the current orientation. Right now i do a small

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

To filter abit of the noise. But its not working very well :)

Though I havn't used the compass on Android, the basic processing shown below (in JavaScript) will probably work for you.

It's based on the low pass filter on the accelerometer that's recommended by the Windows Phone team with modifications to suit a compass (the cyclic behavior every 360").

I assume the compass reading is in degrees, a float between 0-360, and the output should be similar.

You want to accomplish 2 things in the filter:

  1. If the change is small, to prevent gitter, gradually turn to that direction.
  2. If the change is big, to prevent lag, turn to that direction immediatly (and it can be canceled if you want the compass to move only in a smooth way).

For that we will have 2 constants:

  1. The easing float that defines how smooth the movement will be (1 is no smoothing and 0 is never updating, my default is 0.5). We will call it SmoothFactorCompass.
  2. The threshold in which the distance is big enough to turn immediatly (0 is jump always, 360 is never jumping, my default is 30). We will call it SmoothThresholdCompass.

We have one variable saved across the calls, a float called oldCompass and it is the result of the algorithm.

So the variable defenition is:

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

and the function recieves newCompass, and returns oldCompass as the result.

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;
        }
    }
}

I see that the issue was opened 5 months ago and probably isn't relevant anymore, but I'm sure other programmers might find it useful.

Oded Elyada.