实现卡尔曼滤波器以平滑来自 deviceOrientation API 的数据
Posted
技术标签:
【中文标题】实现卡尔曼滤波器以平滑来自 deviceOrientation API 的数据【英文标题】:Implement a Kalman filter to smooth data from deviceOrientation API 【发布时间】:2014-11-02 21:30:26 【问题描述】:我正在尝试对从 deviceOrientation API 获取的数据进行平滑处理,以便在浏览器中创建 Google Cardboard 应用程序。
我正在将加速度计数据直接输入到 ThreeJs 相机旋转中,但我们在信号上得到了很多噪声,导致视图抖动。
有人建议使用卡尔曼滤波器作为平滑信号处理噪声的最佳方法,我在 gitHub 上找到了这个简单的 javascript 库
https://github.com/itamarwe/kalman
但是,它对文档的了解确实很轻。
我知道我需要通过提供一个向量和 3 个矩阵作为参数来创建一个卡尔曼模型,然后在一个时间范围内再次使用一个向量和矩阵作为参数来更新模型。
我还了解卡尔曼滤波器方程有几个不同的部分:当前估计位置、卡尔曼增益值、来自方向 API 的当前读数和先前估计位置。
我可以看到 3D 空间中的一个点可以描述为一个向量,因此任何位置值(例如估计位置)或当前读数都可以是一个向量。
我不明白如何将这些部分转换为矩阵以形成 Javascript 库的参数。
【问题讨论】:
是的,公平地说,图书馆完全被记录在案。如果他/她/它对我有用,那将是不可以接受的!坦率地说,我会尝试联系作者,如果失败,请使用其他方式。 已在 github 存储库中添加了一个问题,希望他们会同情我。我假设如果信号处理是你的事,这可能是显而易见的,但我对矩阵的目的有点迷茫。我想知道矩阵是否代表时间状态之间的转换。因此,不是将当前位置表示为向量,而是将当前位置表示为实际读数与上次状态下的读数之间的转换? 【参考方案1】:好吧,我在几年前编写了这个记录可恶的库。如果有兴趣,我肯定愿意升级它,改进文档并编写测试。
让我简要解释一下所有不同的矩阵和向量是什么以及它们应该如何导出:
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]。在这里您需要测量加速度计的噪声程度,并计算噪声协方差矩阵。
总结一下,使用卡尔曼滤波器的步骤:
-
确定
x[0]
和P[0]
- 模型的初始状态,以及您知道x[0]
准确度的初始估计。
根据您的模型及其逐步发展的方式确定F
。
根据模型的随机性确定Q
。
根据您测量的内容与您想要估计的内容(模型与测量结果之间)之间的关系确定 H
。
根据测量噪声确定R
。您的测量结果有多嘈杂。
然后,对于每个新的观察,您可以使用卡尔曼滤波器更新模型状态估计,并对模型状态 (x[k]
) 和该估计的准确度 (P[k]
) 进行最佳估计)。
【讨论】:
感谢您抽出宝贵时间。我真的很感激,也感谢您首先制作图书馆【参考方案2】: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 轴上的变化更大。我们认为这可能是云台锁的问题。我们尚未测试,但每个轴的方差可能会根据设备的方向发生变化。
【讨论】:
您的系统是静态的吗?如果是这样,那么Q
为 0 就可以了。但是如果您的系统移动,那么您必须有一个非零的Q
,它表示加速度的协方差逐步变化。另外,我会用第一个加速度计测量值初始化x
,因为这是你最好的猜测,并且会加速滤波器的收敛。以上是关于实现卡尔曼滤波器以平滑来自 deviceOrientation API 的数据的主要内容,如果未能解决你的问题,请参考以下文章