4、四元数运算:乘法、共轭、归一化与旋转表示
四元数这东西,刚接触时确实有点绕。我记得第一次在项目里用四元数做姿态解算,差点被它的乘法规则搞晕。但说白了,它就是三维旋转的「瑞士军刀」——比欧拉角优雅,比旋转矩阵轻量。
今天咱们就把四元数的几个核心运算掰开揉碎。你想想看,搞懂了乘法、共轭、归一化,旋转表示也就水到渠成了。
4.1 四元数的基本形态
一个四元数长这样:
q = w + xi + yj + zk
其中 w 是实部,x、y、z 是虚部。i、j、k 是三个虚数单位,它们的关系很有意思:
- i² = j² = k² = -1
- ij = k, jk = i, ki = j
- ji = -k, kj = -i, ik = -j
嗯,这里要注意:四元数乘法不满足交换律。也就是说,q₁ × q₂ 不等于 q₂ × q₁。我在项目中踩过这个坑,当时调试半天才发现是乘法顺序搞反了。
4.2 四元数乘法
两个四元数相乘,公式看起来有点吓人:
q₁ = w₁ + x₁i + y₁j + z₁k
q₂ = w₂ + x₂i + y₂j + z₂k
q₁ × q₂ = (w₁w₂ - x₁x₂ - y₁y₂ - z₁z₂) +
(w₁x₂ + x₁w₂ + y₁z₂ - z₁y₂)i +
(w₁y₂ - x₁z₂ + y₁w₂ + z₁x₂)j +
(w₁z₂ + x₁y₂ - y₁x₂ + z₁w₂)k
别急着背公式。我个人习惯用向量形式来理解:
q₁ = [w₁, v₁] 其中 v₁ = (x₁, y₁, z₁)
q₂ = [w₂, v₂] 其中 v₂ = (x₂, y₂, z₂)
q₁ × q₂ = [w₁w₂ - v₁·v₂, w₁v₂ + w₂v₁ + v₁ × v₂]
你看,点积和叉积都用上了。这样记起来是不是舒服多了?
核心要点:四元数乘法的几何意义是旋转的复合。q₁ × q₂ 表示先做 q₂ 的旋转,再做 q₁ 的旋转。
4.3 四元数的共轭
共轭很简单,就是把虚部取反:
q = w + xi + yj + zk
q* = w - xi - yj - zk
共轭有什么用?我告诉你,它在求逆的时候特别方便。对于单位四元数,共轭就是它的逆。
小技巧:q × q* = q* × q = w² + x² + y² + z²,这个结果就是四元数的模长的平方。
4.4 四元数的归一化
归一化就是把四元数变成单位四元数。为什么要归一化?因为只有单位四元数才能表示纯旋转,不引入缩放。
模长: ||q|| = sqrt(w² + x² + y² + z²)
归一化: q_norm = q / ||q||
我曾经在惯性导航项目里,因为忘记归一化,导致姿态越偏越大。嗯,从那以后我每次做四元数运算,都会检查一下模长是不是接近1。
注意:浮点数运算会有精度误差,多次乘法后模长会偏离1。建议每做几次运算就归一化一次。
4.5 用四元数表示旋转
这才是重头戏。用四元数旋转一个三维向量 v,步骤是这样的:
- 把向量 v 写成纯四元数:p = (0, v)
- 用单位四元数 q 做旋转:p' = q × p × q*
- p' 的虚部就是旋转后的向量
公式看起来简单,但要注意乘法顺序。我建议写成这样:
def rotate_vector(v, q):
# v: 三维向量 [x, y, z]
# q: 单位四元数 [w, x, y, z]
p = Quaternion(0, v[0], v[1], v[2])
q_conj = q.conjugate()
p_rotated = q * p * q_conj
return [p_rotated.x, p_rotated.y, p_rotated.z]
你想想看,为什么是 q × p × q* 而不是 q × p?因为 p 是纯四元数,q × p 的结果不一定是纯四元数。乘上 q* 之后,才能保证结果落在纯四元数空间里。
4.6 旋转的复合
假设你先做 q₁ 的旋转,再做 q₂ 的旋转,那么总的旋转就是:
q_total = q₂ × q₁
注意顺序!q₂ × q₁ 表示先 q₁ 后 q₂。这和矩阵乘法是一致的。
实战经验:在机器人控制中,我经常需要把多个关节的旋转复合起来。用四元数乘法比用欧拉角稳定得多,完全不用担心万向锁的问题。
4.7 知识体系总览
下面这张图帮你理清四元数运算的脉络:
4.8 避坑指南
最后分享几个我踩过的坑:
- 乘法顺序:q₁ × q₂ 和 q₂ × q₁ 完全不同,一定要搞清楚旋转的先后顺序
- 归一化:每次乘法后检查模长,偏离1就归一化
- 共轭 vs 逆:只有单位四元数,共轭才等于逆
- 旋转方向:四元数旋转默认是右手法则,和左手系不兼容
四元数运算说难不难,说简单也不简单。关键是多动手写代码,多在实际项目里用。我刚开始也是死记硬背公式,后来发现理解了几何意义,一切都顺了。