如何在CMRotationMatrix上应用过滤器?也许是卡尔曼滤波器。我需要修复 CMRotationMatrix (transformFromCMRotationMatrix) 的噪声,以获得结果矩阵的线性值
这个矩阵值将转换为 XYZ,在我的例子中,我在 2D 屏幕上模拟 3D,如下所示:
// 将矩阵转换为 x, y
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, boxMatrix);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
CGPointMake(x * self.bounds.size.width, self.bounds.size.height - (y * self.bounds.size.height));
代码:
//定义变量
mat4f_t cameraTransform;
//启动显示链接循环
- (void)startDisplayLink
{
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
[displayLink setFrameInterval:1];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
//停止显示链接循环
- (void)stopDisplayLink
{
[displayLink invalidate];
displayLink = nil;
}
//显示链接事件
- (void)onDisplayLink:(id)sender
{
CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {
CMRotationMatrix r = d.attitude.rotationMatrix;
transformFromCMRotationMatrix(cameraTransform, &r);
[self setNeedsDisplay];
}
}
//函数在[self setNeedDisplay]之前触发;
void transformFromCMRotationMatrix(vec4f_t mout, const CMRotationMatrix *m)
{
mout[0] = (float)m->m11;
mout[1] = (float)m->m21;
mout[2] = (float)m->m31;
mout[3] = 0.0f;
mout[4] = (float)m->m12;
mout[5] = (float)m->m22;
mout[6] = (float)m->m32;
mout[7] = 0.0f;
mout[8] = (float)m->m13;
mout[9] = (float)m->m23;
mout[10] = (float)m->m33;
mout[11] = 0.0f;
mout[12] = 0.0f;
mout[13] = 0.0f;
mout[14] = 0.0f;
mout[15] = 1.0f;
}
// 矩阵向量和矩阵矩阵乘法例程
void multiplyMatrixAndVector(vec4f_t vout, const mat4f_t m, const vec4f_t v)
{
vout[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
vout[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
vout[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
vout[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
}
一般来说,我会区分提高信噪比和平滑信号。
信号改善
如果你真的想比苹果的 Core Motion 更好,因为它已经实现了传感器融合算法,请为结果不确定的长期项目做好准备。在这种情况下,你最好采用原始加速度计和陀螺仪信号来构建自己的传感器融合算法,但你必须关心很多问题,例如漂移、不同 iPhone 版本的硬件依赖性、同一传感器内传感器的硬件差异一代,......所以我的建议:尽一切努力避免它。
平滑
这仅意味着对两个或多个信号进行插值并建立平均值。我不知道直接用于旋转矩阵的任何合适方法(也许有一种),但您可以使用 quaternions 代替(更多资源:OpenGL 教程使用四元数表示旋转 或 四元数常见问题解答)。
这种插值所得的四元数可以与您的向量相乘,以获得类似于矩阵方式的投影(您可以查看查找 iOS 设备的法线向量以获取更多信息)。
表示旋转的两个单位四元数之间的插值可以使用Slerp来完成。在实践中,您将使用维基百科中描述的几何 Slerp。如果有两个时间点t1和t2以及相应的四元数q1和q2以及它们之间的角距离omega,则公式为:
q'(q1, q2, t) = sin((1- t) * 欧米伽) / sin(欧米伽) * q0 + sin(t * 欧米伽) / sin(欧米伽) * q1
t 应该是 0.5,因为您想要两次旋转之间的平均值。 Omega可以通过点积计算:
cos(欧米伽) = q1.q2 = w1w2 + x1x2 + y1y2 + z1z2
如果使用两个四元数的这种方法仍然不能满足您的需求,您可以使用 slerp (slerp (q1, q2), slerp (q3, q4)) 重复此操作。一些注意事项: