17

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

我将加速度计数据直接传送到 ThreeJs 相机旋转中,但我们在信号上得到了很多噪声,导致视图抖动。

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

https://github.com/itamarwe/kalman

然而,它在文档上真的很轻。

我知道我需要通过提供向量和 3 个矩阵作为参数来创建卡尔曼模型,然后更新模型,再次使用向量和矩阵作为时间范围内的参数。

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

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

我不明白的是如何将这些部分转换为矩阵以形成 Javascript 库的参数。

4

2 回答 2

15

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

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

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根据测量噪声确定。您的测量结果有多嘈杂。

然后,对于每个新的观察,您可以使用卡尔曼滤波器更新模型状态估计,并对模型的状态 ( x[k]) 和该估计的准确性() 进行最佳估计P[k]

于 2014-09-09T15:05:29.237 回答
4
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 轴上的变化更大。我们认为这可能是云台锁的问题。我们尚未测试,但每个轴的方差可能会根据设备的方向发生变化。

于 2014-09-10T09:26:40.070 回答