四元数和标准化

时间:2012-07-26 10:57:42

标签: normalization quaternions

我知道如果我想旋转矢量,则需要对四元数进行标准化。

但有没有理由不自动规范化四元数?如果有,那么四元数运算会导致非标准化四元数?

  • 乘以两个四元数?
  • Dot product?

对不起,如果这个问题有点模糊。我仍然试着绕着四元数包围。

6 个答案:

答案 0 :(得分:29)

迟到的反应;这个答案适用于将来遇到这个问题的人,而不是提问者。

我不同意另外两个关于仅偶尔标准化四元数的答案。使用四元数来旋转/变换矢量或生成旋转/变换矩阵的标准公式隐含地假设四元数是标准化的。使用非标准化四元数产生的误差与四元数的平方成正比。最好避免二次误差增长。

如果经常标准化,则不需要平方根。一阶近似非常有效。以下是我用于四元数的IEEE加倍,有点风格化:

double qmagsq = quat.square_magnitude();
if (std::abs(1.0 - qmagsq) < 2.107342e-08) {
    quat.scale (2.0 / (1.0 + qmagsq));
}
else {
    quat.scale (1.0 / std::sqrt(qmagsq));
}

请注意,我使用的是第一阶Padé逼近2.0/(1.0+qmagsq)而不是第一阶泰勒展开0.5*(3.0-qmagsq)来估算1.0/std::sqrt(qmagsq)。该近似值如果有效,则通过简单除法替换平方根调用。关键是找到何时有效,这就是幻数2.107342e-08发挥作用的地方。

为什么Padé接近?两个原因。一个是qmagsq的值接近一,1+qmagsq的精度低于3-qmagsq。另一个是,与泰勒展开相比,Padé近似将误差减少了三倍。对于介于0和2之间的qmagsq的值,此近似值中的误差小于(1-qmagsq)^2 / 8。幻数2.107342e-08表示此错误超过IEEE的ULP的一半。如果采取合理的小步骤,四元数量值的平方将始终在该限制范围内。你永远不会打电话给sqrt

这种“常规规范化”范例的一个例外可能是你使用李群集成技术来传播四元数。如果您不知道这意味着什么,您可能使用等效的q(t+Δt) = q(t) + dq(t)/dt*Δt来传播四元数。即使您使用的是不是李群集成器的高阶积分技术,您仍然在某处使用欧拉步骤。

答案 1 :(得分:8)

产生四元数的任何操作都需要进行规范化,因为浮点进动错误会导致它不是单位长度。

我建议不要出于性能原因自动执行标准化的标准例程。任何有能力的程序员都应该了解精度问题并在必要时对数量进行标准化 - 并不总是需要单位长度的四元数。

矢量运算也是如此。

答案 2 :(得分:5)

有趣的是,构建旋转矩阵是一种不需要规范化四元数的操作,为您节省一个sqrt

M = [w*w+x*x-y*y-z*z, 2*(-w*z+x*y),    2*(w*y+x*z);
     2*(w*z+x*y),     w*w-x*x+y*y-z*z, 2*(-w*x+y*z);
     2*(-w*y+x*z),    2*(w*x+y*z),     w*w-x*x-y*y+z*z] / (w*w+x*x+y*y+z*z)
对于四元数w+x*i+y*j+z*k

(在MATLAB-ish表示法中)。

此外,如果你使用齐次坐标和4x4变换矩阵,你也可以保存一些除法运算:只需制作一个3x3旋转部分就像四元数被标准化一样,然后将其平方长度放入(4,4) ) - 元素:

M = [w*w+x*x-y*y-z*z, 2*(-w*z+x*y),    2*(w*y+x*z),     0;
     2*(w*z+x*y),     w*w-x*x+y*y-z*z, 2*(-w*x+y*z),    0;
     2*(-w*y+x*z),    2*(w*x+y*z),     w*w-x*x-y*y+z*z, 0;
     0,               0,               0,               w*w+x*x+y*y+z*z].

乘以翻译矩阵等,像往常一样进行完全转换。这样你就可以做到,例如,

[xh yh zh wh]' = ... * OtherM * M * [xold yold zold 1]';
[xnew ynew znew] = [xh yh zh] / wh.

当然,仍然建议至少偶尔对四元数进行归一化(其他操作也可能需要它)。

答案 3 :(得分:2)

如果通过数值积分其第一时间导数获得单位四元数,则积分器可以使用简单的误差反馈自动对其进行归一化。

q 表示四元数的4乘1列矩阵和 dq 其时间导数。然后将 dq + 0.5(1-qq)q / tau 发送到积分器以代替 dq 并使用合适的时间常数 tau 将持续规范化 q q.q 代表内在产品。

我模拟了一个保守的,清晰的Bricard机制,在无重力空间中漂浮了360万秒,这将近42天。四元数代表浮动基体的方向。使用0.5秒的时间常数 tau ,总能量保持恒定在百万分之一。在数值积分器DE中使用了10 ^ -12的绝对误差容差和零的相对误差容差。

http://www.amazon.com/Computer-Solution-Ordinary-Differential-Equations/dp/0716704617/

四元数通常通过数值积分获得。如果它们在积分器内没有标准化,那么幅度和相位误差将累积。标准化四元数沿单位球体移动,其第一时间导数与该球体相切。如果四元数偏离单位球体,它将开始累积相位误差,积分器外部的归一化无法校正。因此,四元数必须在数值积分器内连续归一化,以最大限度地减少相位误差。

答案 4 :(得分:0)

你的问题是暧昧的,但如果你需要规范化四元数很简单

q_normalized = q / square(norm(q))

with,q = q1 + q2i + q3 j + q4 k  范数(q)=(q1)^ 2 +(q2)^ 2 +(q3)^ 2)+(q4)^ 4

如果别向我解释你的问题

答案 5 :(得分:-1)

使用NONunit四元数可能很有效。

只有少数操作需要单位长度,例如插值。

一些提示:

  1. 创建和转换为非单元四元数可以更有效。
  2. 从非单元四元数转换为矩阵仍然很快。只需补偿四元数的平方。
  3. 转换矩阵到非单位quat更快。
  4. 因此不需要仅使用单位四元数,这只是常见的做法。对于每个用例,您可以决定使用或不进行规范化。我个人更喜欢使用非单位四元数。

    警告:通常,使用单位四元数时,我们会忘记数字错误。例如,从/向矩阵四元数转换并认为它仍然单位使得大数值不稳定,矩阵被缩放,提取的四元数是无效的。你可以轻松地进行这样的实验。