Mad*_*sen 15 algorithm android signal-processing orientation compass-geolocation
我正在创建一个应用程序,我需要根据设备的方向定位ImageView.我使用MagneticField和Accelerometer Sensors中的值来计算设备方向
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerValues, magneticFieldValues)
SensorManager.getOrientation(rotationMatrix, values);
double degrees = Math.toDegrees(values[0]);
Run Code Online (Sandbox Code Playgroud)
我的问题是ImageView的定位对方向的变化非常敏感.使imageview不断跳到屏幕上.(因为度数变化)
我读到这可能是因为我的设备接近可能影响磁场读数的东西.但这不是它看起来的唯一原因.
我尝试下载一些应用程序,发现" 3D罗盘 "和" 指南针 "的读数仍然非常稳定(当设置噪声滤波器时),我想在我的应用程序中使用相同的行为.
我读到我可以通过添加" 低通滤波器 " 来调整读数的"噪音" ,但我不知道如何实现这一点(因为我缺乏数学).
我希望有人可以帮助我在我的设备上创建更稳定的读数,其中设备的一点点移动不会影响当前的方向.现在我做了一个小
if (Math.abs(lastReadingDegrees - newReadingDegrees) > 1) { updatePosition() }
Run Code Online (Sandbox Code Playgroud)
过滤噪音的升值.但它不能很好地工作:)
小智 30
虽然我没有在Android上使用指南针,但下面显示的基本处理(用JavaScript)可能对你有用.
它基于加速度计上的低通滤波器,由Windows Phone团队推荐,经过修改以适应指南针(每360个循环行为).
我假设罗盘读数是以度为单位,浮点数在0-360之间,输出应该相似.
您想在过滤器中完成两件事:
- 如果变化很小,为了防止灰尘,逐渐转向那个方向.
- 如果变化很大,为防止滞后,立即转向该方向(如果您希望指南针仅以平滑的方式移动,则可以取消).
为此,我们将有2个常量:
- 缓动浮动定义了移动的平滑程度(1表示没有平滑,0表示永不更新,默认值为0.5).我们将其称为SmoothFactorCompass.
- 距离大到足以立即转动的阈值(0总是跳跃,360永远不会跳跃,我的默认值是30).我们将其称为SmoothThresholdCompass.
我们在调用中保存了一个变量,一个名为oldCompass的浮点数,它是算法的结果.
所以变量防御是:
var SmoothFactorCompass = 0.5;
var SmoothThresholdCompass = 30.0;
var oldCompass = 0.0;
Run Code Online (Sandbox Code Playgroud)
并且函数接收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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我看到问题是在5个月前开放的,可能不再相关,但我确信其他程序员可能会发现它很有用.
Oded Elyada.
Sha*_*ley 20
该低通滤波器适用于弧度角.使用每个罗盘读数的添加功能,然后调用平均值来获得平均值.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
使用Math.toDegrees()
或Math.toRadians()
转换.
小智 5
请记住,例如 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;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12066 次 |
最近记录: |