实现卡尔曼滤波器以平滑来自deviceOrientation API的数据

时间:2014-09-09 12:42:54

标签: javascript device-orientation kalman-filter virtual-reality

我试图平滑我从deviceOrientation API获取的数据,以便在浏览器中制作Google Cardboard应用程序。

我将加速度计数据直接输入到ThreeJs相机旋转中,但是我们在信号上产生了很多噪音,导致视图抖动。

有人建议使用卡尔曼滤波器作为处理平滑信号处理噪声的最佳方法,我在gitHub上找到了这个简单的Javascript库

https://github.com/itamarwe/kalman

然而,它对文档非常清楚。

我理解我需要通过提供Vector和3矩阵作为参数来创建Kalman模型,然后再次使用向量和矩阵作为时间范围内的参数来更新模型。

我也理解卡尔曼滤波器方程有几个不同的部分:当前估计位置,卡尔曼增益值,来自方向API的当前读数和先前估计的位置。

我可以看到3D空间中的一个点可以被描述为一个Vector,因此任何位置值,例如估计位置或当前读数都可以是Vector。

我不明白的是这些部分如何被翻译成矩阵以形成Javascript库的参数。

2 个答案:

答案 0 :(得分:13)

好吧,几年前我写了一篇令人厌恶的文档库。如果有兴趣,我肯定愿意升级它,改进文档并编写测试。

让我简要解释一下所有不同的矩阵和向量以及它们应该如何推导出来:

x - 这是您尝试估算的向量。在你的情况下,它可能是3个角加速度。

P - 是估计的协方差矩阵,意味着估计的不确定性。卡尔曼滤波器的每个步骤也会与x一起估算。

F - 描述X如何根据模型发展。通常,模型为x[k] = Fx[k-1]+w[k]。在您的情况下,F可能是单位矩阵,如果您希望角加速度相对平滑,或者零矩阵,如果您希望角加速度完全不可预测。在任何情况下,w都表示您希望加速度从一步到另一步变化的程度。

w - 描述过程噪音,即模型与“完美”模型的差异程度。它被定义为具有协方差矩阵Q的零均值多元正态分布。

上面的所有变量都定义了您的模型,这意味着您要估算的内容。在下一部分中,我们将讨论观察的模型 - 您为了估计模型而测量的内容。

z - 这是你衡量的。在您的情况下,由于您使用的是加速度计,因此您正在测量您正在估算的内容。这将是角加速度。

H - 描述您的模型与观察之间的关系。 z[k]=H[k]x[k]+v[k]。在您的情况下,它是单位矩阵。

v - 是测量噪声,并假设为具有协方差R [k]的零均值高斯白噪声。在这里,您需要测量加速度计的噪声程度,并计算噪声协方差矩阵。

总结一下,使用卡尔曼滤波器的步骤:

  1. 确定x[0]P[0] - 模型的初始状态,以及您对x[0]的准确程度的初步估计。
  2. 根据您的模型确定F以及它是如何逐步发展的。
  3. 根据模型的随机性确定Q
  4. 根据您测量的内容与您想要估算的内容(模型与测量之间)之间的关系确定H
  5. 根据测量噪音确定R。你的测量结果有多嘈杂。
  6. 然后,对于每个新观察,您可以使用卡尔曼滤波器更新模型状态估计,并对模型的状态(x[k])和该估计的准确性进行最佳估计({ {1}})。

答案 1 :(得分:3)

var acc = {
 x:0,
 y:0,
 z:0
};

var count = 0;

if (window.DeviceOrientationEvent) {
  window.addEventListener('deviceorientation', getDeviceRotation, false);
}else{
  $(".accelerometer").html("NOT SUPPORTED")
}

var x_0 = $V([acc.x, acc.y, acc.z]); //vector. Initial accelerometer values

//P prior knowledge of state
var P_0 = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. Initial covariance. Set to 1
var F_k = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. How change to model is applied. Set to 1
var Q_k = $M([
              [0,0,0],
              [0,0,0],
              [0,0,0]
            ]); //empty matrix. Noise in system is zero

var KM = new KalmanModel(x_0,P_0,F_k,Q_k);

var z_k = $V([acc.x, acc.y, acc.z]); //Updated accelerometer values
var H_k = $M([
              [1,0,0],
              [0,1,0],
              [0,0,1]
            ]); //identity matrix. Describes relationship between model and observation
var R_k = $M([
              [2,0,0],
              [0,2,0],
              [0,0,2]
            ]); //2x Scalar matrix. Describes noise from sensor. Set to 2 to begin
var KO = new KalmanObservation(z_k,H_k,R_k);

//each 1/10th second take new reading from accelerometer to update
var getNewPos = window.setInterval(function(){

    KO.z_k = $V([acc.x, acc.y, acc.z]); //vector to be new reading from x, y, z
    KM.update(KO);

    $(".kalman-result").html(" x:" +KM.x_k.elements[0]+", y:" +KM.x_k.elements[1]+", z:" +KM.x_k.elements[2]);
    $(".difference").html(" x:" +(acc.x-KM.x_k.elements[0])+", y:" +(acc.y-KM.x_k.elements[1])+", z:" +(acc.z-KM.x_k.elements[2]))


}, 100);

 //read event data from device
function getDeviceRotation(evt){

    // gamma is the left-to-right tilt in degrees, where right is positive
    // beta is the front-to-back tilt in degrees, where front is positive
    // alpha is the compass direction the device is facing in degrees
    acc.x = evt.alpha;
    acc.y = evt.beta;
    acc.z = evt.gamma; 
    $(".accelerometer").html(" x:" +acc.x+", y:" +acc.y+", z:" +acc.z);
}

这是一个显示我的结果的演示页

http://cardboard-hand.herokuapp.com/kalman.html

我现在将传感器噪音设置为2个标量矩阵,看看卡尔曼是否正在做它的事情,但我们注意到当手机平放在桌子上时,传感器的x轴变化较大。我们认为这可能是Gimbal锁定的一个问题。我们尚未对其进行测试,但根据设备的方向,每个轴的方差可能会发生变化。