四元数和归一化

Posted

技术标签:

【中文标题】四元数和归一化【英文标题】:Quaternion and normalization 【发布时间】:2012-07-24 22:48:21 【问题描述】:

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

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

两个四元数相乘? 点积?

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

【问题讨论】:

从技术上讲,任何四元数都代表一个有效的旋转,如果你使用它正确的话,即q x v x q^-1而不是q x v x q*。还有一个隐式归一化会导致旋转矩阵。 【参考方案1】:

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

q_normalized = q /square(norm(q))

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

如果要向我解释你的问题

【讨论】:

【参考方案2】:

使用 NONunit 四元数会很有效。

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

一些提示:

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

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

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

【讨论】:

【参考方案3】:

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

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

向量运算也是如此。

【讨论】:

这只是过早的优化:让开发人员做额外的容易出错的工作,即使这并不重要。 如果您不介意,调整这类事情的典型策略是什么?您是要测试所有实现的速度和准确性,并相互结合,还是有一个策略?例如,我预计混合加法和乘法会产生更多的非规范化,并在那里优先考虑准确性。但我不知道什么时候可以摆脱它或应该尝试,我最终会制作一个从故障到滞后的滑块,但不知道如何避免两者。 @JohnP。做数学。如果您可以使用任何四元数是某个范数乘以单位四元数这一事实,请这样做。例如,如果您正在乘法、反转、共轭等,您可以将归一化保存到最后,或者直接忽略它。唯一真正需要归一化四元数的时候是将它用作转子。【参考方案4】:

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

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

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

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

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

【讨论】:

【参考方案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)

(以 MATLAB 风格的表示法)用于四元数 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.

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

【讨论】:

如果四元数未归一化,则该矩阵 M 不是正确的变换矩阵。使用的公式隐含地假设一个归一化的四元数。 @DavidHammen:如果您使用齐次坐标,它是一个适当的变换矩阵。在这种情况下,矩阵Ma*M 对于任何非零a 基本上是相同的——并且该矩阵正是从归一化四元数获得的矩阵,然后按w*w+x*x+y*y+z*z 缩放。 不,不是。计算行列式。它不是一个。计算 M*转置(M)。它不是单位矩阵。这正是我在编写“标准公式”时所要解决的问题。这是那些标准公式之一,它隐含地假设一个归一化的四元数。对于这种四元数的特殊应用,有一个简单、无平方根的解决方案:只需将每个元素除以 w*w+x*x+y*y+z*z,瞧,你就有了一个合适的变换矩阵。 @DavidHammen:(1)您似乎假设变换矩阵必须是正交的。即使在您的工作中确实如此,这也不是一般要求。你明白什么是“齐次坐标”,对吧? (2) 涉及除以w*w+x*x+y*y+z*z 的无 Sqrt 计算正是我第一个语句(在答案中)的意思。 4x4 矩阵本身是一个无除法修复。 @DavidHammen:我在答案中添加了一些方程式。如果您认为它可以使用更多细节,请发表评论。【参考方案6】:

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

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

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

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

【讨论】:

归一化是将四元数拖回单位 3 球体的杂项。四元数偏离流形的原因是因为欧拉步在某种意义上在数学上是无效的:单位四元数是一个群,而不是代数。不使用单位四元数也是无效的;现在您没有关于 so(3) 的图表。做对了(例如,李群积分技术),四元数几乎会留在流形上。您可能仍需要偶尔进行标准化。 就我的平方根近似而言:根据设计,它在其设计范围内精确到 ULP 的一半。它有时与1/std::sqrt(x) 的最低有效位不同,但这是因为std::sqrt(x) 也可以精确到半个ULP。当它们确实不同时,哪个答案是正确的?没有一个。正确答案介于两者之间。 对于此类问题,这些都是有效的考虑因素。但是,与您批评的答案不同,它们与“不自动归一化四元数的原因”的存在或不存在的原始问题无关(例如,使用未归一化的四元数,而不仅仅是试图在没有重整化的情况下保持它们的大小)。您的回答提供了一个反例,但它并不能证明存在对规范化有不同要求的其他问题。 @chtz - 关于 x=1 的 1/sqrt(x) 的一阶泰勒近似是 (3-x)/2,在误差方面,它比 2/(1+x) 对于 x 接近 1 差大约 3 倍。有时Padé 近似值非常神奇。这是魔法效果很好的情况之一。 你知道 IEEE 单精度 (float) 浮点数的幻数吗?

以上是关于四元数和归一化的主要内容,如果未能解决你的问题,请参考以下文章

3D数学基础四元数和欧拉角

Unity四元数和向量相乘作用及其运算规则

四元数运动学笔记旋转的雅克比矩阵

Unity四元数和旋转

欧拉角四元数和矩阵的对比(转)

怎么把向量转化为四元数或欧拉角