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

Implement a Kalman filter to smooth data from deviceOrientation API

本文关键字:deviceOriented API 数据 平滑 滤波器 实现      更新时间:2023-09-26

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

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

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

https://github.com/itamarwe/kalman

但是,它在文档中真的很轻。

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

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

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

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

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

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

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](进行最佳估计。

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 轴上具有更大的方差。我们认为这可能是万向节锁的问题。我们还没有测试过,但每个轴的方差可能会根据设备的方向而变化。