objective-c – 如何使用CADisplayLink在CMRotationMatrix上应用过滤器

如何在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;
}

// Matrix-vector和matrix-matricx乘法例程

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];
}

解决方法

一般来说,我会区分提高信噪比和消除信号.

信号改善

如果您真的想要比已经实施传感器融合算法的Apple的Core Motion更好,请为具有不确定结果的长期项目做好准备.在这种情况下,您最好采用原始加速度计和陀螺仪信号来构建您自己的传感器融合算法,但您必须关注许多问题,如漂移,不同iPhone版本的硬件依赖性,传感器内的硬件差异一代,…所以我的建议:尽量避免它.

平滑

这只是意味着插入两个或更多信号并构建平均值.我不知道任何合适的方法直接用于旋转矩阵(可能有一个)但你可以使用quaternions(更多资源:OpenGL Tutorial Using Quaternions to represent rotationQuaternion FAQ).

这种插值的结果四元数可以与矢量相乘以获得与矩阵方式类似的投影(有关更多信息,请查看Finding normal vector to iOS device).

表示旋转的两个单位四元数之间的插值可以通过Slerp完成.实际上,您将使用维基百科中描述为Geometric Slerp的内容.如果你有两个时间点t1和t2以及相应的四元数q1和q2以及它们之间的角距离omega,则公式为:

q'(q1,q2,t)= sin((1-t)* omega)/ sin(ω)* q0 sin(t * omega)/ sin(ω)* q1

t应为0.5,因为您需要两次旋转之间的平均值.欧米茄可以通过点积计算:

cos(ω)= q1.q2 = w1 * w2 x1 * x2 y1 * y2 z1 * z2

如果使用两个四元数的方法仍然不符合您的需要,可以使用slerp(slerp(q1,q2),slerp(q3,q4))重复此操作.一些说明:

>从性能的角度来看,在你的运行循环1 /频率时间每秒执行三次sin和一次arccos调用并不便宜.因此,你应该避免使用太多的点
>在您的情况下,所有信号彼此接近,尤其是在使用高传感器频率时.你必须注意非常小的角度让1 / sin(ω)爆炸.在这种情况下,设置sin(x)≈x
>像low-pass filter等其他过滤器一样,您使用的时间越长,您获得的延迟时间就越长.因此,如果你有频率f,当使用两个点时,你将获得大约0.5 / f秒的延迟,而对于双重slerp,你将获得1.5 / f.
>如果某些内容看起来很奇怪,请检查生成的四元数是否为单位四元数,即|| q || = 1
>如果您遇到性能问题,可以查看Hacking Quaternions

github上的C项目pbrt包含一个四元数类,可以从中获得灵感.

相关文章

一.C语言中的static关键字 在C语言中,static可以用来修饰局...
浅谈C/C++中的指针和数组(二) 前面已经讨论了指针...
浅谈C/C++中的指针和数组(一)指针是C/C++...
从两个例子分析C语言的声明 在读《C专家编程》一书的第三章时...
C语言文件操作解析(一)在讨论C语言文件操作之前,先了解一下...
C语言文件操作解析(三) 在前面已经讨论了文件打开操作,下面...