我需要根据加速度计,陀螺仪和磁力计计算线性加速度。我发现了一个Android应用程序,它正是我想要实现的目标:
https://play.google.com/store/apps/details?id=com.kircherelectronics.fusedlinearacceleration。 https://github.com/KEOpenSource/FusedLinearAcceleration
我试图将它移植到纯java。由于代码的某些元素基于虚拟传感器(重力传感器),我希望通过基于三个基本传感器的计算重力方法获得相同的结果。我读到可以使用低通滤波器(与Android< 4.0相同)计算重力,但这种方法不能给出非常准确的结果。
从android 4.0开始,使用传感器融合计算每个轴上的重力。我找到了负责这些测量的代码,但它写在CPP中:
使用的方法称为" getRotationMatrix"。 SensorManager.java中的相同方法:https://gitorious.org/android-eeepc/base/source/9cb3e09ec49351401cf19b5ae5092dd9ca90a538:core/java/android/hardware/SensorManager.java#L1034
public static boolean getRotationMatrix(float[] R, float[] I,
float[] gravity, float[] geomagnetic) {
// TODO: move this to native code for efficiency
float Ax = gravity[0];
float Ay = gravity[1];
float Az = gravity[2];
final float Ex = geomagnetic[0];
final float Ey = geomagnetic[1];
final float Ez = geomagnetic[2];
float Hx = Ey*Az - Ez*Ay;
float Hy = Ez*Ax - Ex*Az;
float Hz = Ex*Ay - Ey*Ax;
final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
if (normH < 0.1f) {
// device is close to free fall (or in space?), or close to
// magnetic north pole. Typical values are > 100.
return false;
}
final float invH = 1.0f / normH;
Hx *= invH;
Hy *= invH;
Hz *= invH;
final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
Ax *= invA;
Ay *= invA;
Az *= invA;
final float Mx = Ay*Hz - Az*Hy;
final float My = Az*Hx - Ax*Hz;
final float Mz = Ax*Hy - Ay*Hx;
if (R != null) {
if (R.length == 9) {
R[0] = Hx; R[1] = Hy; R[2] = Hz;
R[3] = Mx; R[4] = My; R[5] = Mz;
R[6] = Ax; R[7] = Ay; R[8] = Az;
} else if (R.length == 16) {
R[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0;
R[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0;
R[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0;
R[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1;
}
}
if (I != null) {
// compute the inclination matrix by projecting the geomagnetic
// vector onto the Z (gravity) and X (horizontal component
// of geomagnetic vector) axes.
final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
if (I.length == 9) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[3] = 0; I[4] = c; I[5] = s;
I[6] = 0; I[7] =-s; I[8] = c;
} else if (I.length == 16) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[4] = 0; I[5] = c; I[6] = s;
I[8] = 0; I[9] =-s; I[10]= c;
I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
I[15] = 1;
}
}
return true;
}
有四个参数:
float [] R, float [] I, float [] gravity, float [] Geomagnetic.
其中一个只是引力......我目前正在处理的代码类似于
,但引用SensorManager的方法除外。这些是从android源代码复制的:
我没有找到任何关于如何在Java中实现它的例子。
所以我的问题是:如何实现方法(在java中),仅基于三个基本传感器,它返回重力方向(x,y,z)的数组,类似于Android一个,但不使用Android API
答案 0 :(得分:1)
重力是加速度计信号(x,y和amp; z)中的稳定贡献。 因此,从逻辑上讲,为了将重力值与时间相关联,只需对3个加速度计信号进行低通滤波,例如频率为2Hz。 一个简单的FIR可以完成这项工作。
在此site 我计算了以下系数:
[0.000381, 0.001237, 0.002634, 0.004607, 0.007100, 0.009956, 0.012928,
0.015711, 0.017987, 0.019480, 0.020000, 0.019480, 0.017987, 0.015711,
0.012928, 0.009956, 0.007100, 0.004607, 0.002634, 0.001237, 0.000381]
基于这些特征: Fa = 0Hz,Fb = 1Hz,长度= 21Pts,Fs = 100Hz,Att = 60dB。
你将得到一个信号,它将是时间函数的三个重力值。
您可以找到here一些FIR解释和Java实现。