24

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

但是有什么理由不自动规范化四元数吗?如果有,哪些四元数运算会导致非归一化四元数?

  • 将两个四元数相乘?
  • 点积?

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

4

6 回答 6

40

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

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

如果您经常标准化,则不需要平方根。一阶近似效果很好。这是我将四元数用作 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 的值,1+qmagsq损失的精度比3-qmagsq. 另一个是与泰勒展开式相比,Padé 近似值将误差减少了三倍。对于qmagsq0 到 2 之间的值,此近似值的误差小于(1-qmagsq)^2 / 8. 幻数 2.107342e-08 表示此错误超过 IEEE 双倍 ULP 的一半。如果您采取合理的小步骤,则四元数大小的平方将始终在该限制内。你永远不会打电话sqrt

如果您使用李群积分技术来传播四元数,则这种“始终标准化”范式的一个例外可能是。如果您不知道这意味着什么,您可能正在使用等价物q(t+Δt) = q(t) + dq(t)/dt*Δt来传播四元数。即使您使用不是李群积分器的高阶积分技术,您仍在某处使用该欧拉步骤。

于 2012-10-17T12:52:07.417 回答
11

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

出于性能原因,我建议不要使用标准例程自动执行规范化。任何称职的程序员都应该意识到精度问题,并能够在必要时对数量进行规范化——并不总是需要有一个单位长度的四元数。

向量运算也是如此。

于 2012-07-26T11:09:27.390 回答
6

有趣的是,构建旋转矩阵是一种不需要归一化四元数的操作,为您节省了一个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)

(在 MATLAB-ish 表示法中)用于 quaternion w+x*i+y*j+z*k

此外,如果您使用齐次坐标和 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.

当然,仍然建议至少偶尔标准化四元数(其他操作也可能需要它)。

于 2012-07-31T19:58:08.967 回答
2

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

q表示 4 x 1 列的四元数矩阵,dq表示其时间导数。然后将dq+0.5(1-qq)q/tau发送到积分器以代替dq并使用合适的时间常数tau将连续归一化qqq表示内积。

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

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

四元数通常通过数值积分获得。如果它们没有在积分器内部归一化,那么幅度和相位误差将会累积。一个归一化的四元数沿着一个单位球体移动,它的一阶导数与该球体相切。如果四元数偏离单位球面,它将开始累积在积分器外部进行归一化无法校正的相位误差。因此,四元数必须在数值积分器内连续归一化,以最小化相位误差。

于 2013-03-10T16:59:41.430 回答
0

你的问题是模棱两可的,但如果你需要标准化一个四元数很简单

q_normalized = q /square(norm(q))

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

如果要向我解释你的问题

于 2016-07-09T02:26:55.900 回答
-1

使用 NONunit 四元数可能是有效的。

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

一些技巧:

  1. 创建和转换为非单位四元数会更有效。
  2. 从非单位四元数转换为矩阵仍然很快。只需补偿四元数平方的比例。
  3. 将矩阵转换为非单位 quat 的速度更快。

所以不需要只使用单位四元数,这只是常见的做法。对于每个用例,您都可以决定是否使用规范化。我个人更喜欢使用非单位四元数。

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

于 2014-03-17T12:01:15.877 回答