4. 四元数数学基础:定义、乘法、共轭与模,以及旋转的关系

各位同学,欢迎来到第四讲。

说实话,很多做姿态解算的工程师,一听到「四元数」三个字就头大。我当年刚入行时也一样,觉得这东西太抽象了,不如欧拉角直观。但后来在项目里被万向锁坑过一次之后,我才老老实实把四元数啃了下来。嗯,今天我就带你把它彻底搞明白。

4.1 四元数的定义

四元数,说白了就是一个超复数。它由一个实部和三个虚部组成:

q = w + xi + yj + zk

其中 w、x、y、z 都是实数。i、j、k 是三个虚数单位,它们满足一个很关键的关系:

i² = j² = k² = ijk = -1

这个关系式,就是四元数的灵魂。你想想看,它跟普通复数的 i² = -1 是不是很像?只不过这里扩展到了三个维度。

在实际代码里,我们通常把四元数存成一个四维向量:

q = [w, x, y, z]

我个人习惯把 w 放在第一位,这样跟很多数学库的接口保持一致。

核心理解: 四元数可以看作是一个标量 w 加上一个三维向量 (x, y, z)。这个视角在后面理解旋转时会非常有用。

4.2 四元数的乘法

四元数乘法,是姿态解算中最频繁的操作。我建议你把它当成一个固定的公式来记,不要每次都去推导。

假设有两个四元数:

q1 = w1 + x1i + y1j + z1k
q2 = w2 + x2i + y2j + z2k

它们的乘积 q = q1 × q2 为:

w = w1*w2 - x1*x2 - y1*y2 - z1*z2
x = w1*x2 + x1*w2 + y1*z2 - z1*y2
y = w1*y2 - x1*z2 + y1*w2 + z1*x2
z = w1*z2 + x1*y2 - y1*x2 + z1*w2

注意,四元数乘法是不满足交换律的。也就是说,q1 × q2 不等于 q2 × q1。我在项目中曾经因为搞反了乘法的顺序,导致整个姿态解算结果完全反了,排查了整整一个下午。嗯,这个坑你一定要注意。

我的小技巧: 写代码时,把乘法封装成一个函数,每次调用前先确认一下顺序。我习惯用 q_result = q_multiply(q1, q2) 这种命名,一目了然。

4.3 共轭与模

四元数的共轭,就是把虚部取反:

q* = w - xi - yj - zk

共轭有什么用?在姿态解算中,我们经常用共轭来「反向旋转」。比如你有一个旋转四元数 q,那么 q* 就代表相反方向的旋转。

四元数的模(也叫范数)定义为:

||q|| = sqrt(w² + x² + y² + z²)

在姿态解算中,我们通常使用单位四元数,也就是模等于 1 的四元数。为什么?因为只有单位四元数才能表示纯旋转,不包含缩放。

我曾经踩过的坑: 在长时间运行姿态解算算法后,由于数值误差累积,四元数会慢慢偏离单位模长。如果不做归一化,旋转结果会越来越离谱。所以,我建议你在每次更新四元数后,都做一次归一化:

norm = sqrt(w*w + x*x + y*y + z*z)
w /= norm
x /= norm
y /= norm
z /= norm

4.4 四元数与旋转的关系

这是本章最核心的部分。四元数到底怎么表示旋转?

一个绕单位轴 u = (ux, uy, uz) 旋转 θ 角度的操作,可以用四元数表示为:

q = cos(θ/2) + sin(θ/2) * (ux*i + uy*j + uz*k)

注意这里用的是半角。为什么会这样?因为四元数旋转实际上是通过「两次共轭」来实现的。具体来说,对一个三维向量 v,旋转后的结果 v' 为:

v' = q * v * q*

其中 v 被表示成纯四元数 (0, vx, vy, vz)。这个公式,就是四元数旋转的核心公式。你想想看,一次乘法加一次共轭乘法,就完成了一次三维旋转,是不是很优雅?

对比欧拉角: 欧拉角需要三次旋转,而且有万向锁问题。四元数只需要一次旋转,没有奇点。我在做无人机飞控时,就是因为这个原因,果断放弃了欧拉角,全面转向四元数。

4.5 知识体系结构图

下面这张图,帮你把四元数的知识脉络理清楚:

四元数数学基础 定义 q = w + xi + yj + zk 乘法 不满足交换律 共轭与模 单位四元数 旋转关系 v' = q * v * q* 姿态解算中的应用 互补滤波 · 归一化 · 插值

4.6 实战中的注意事项

最后,我总结几个实战中容易出问题的地方:

  • 四元数顺序: 不同数学库对四元数的存储顺序可能不同(wxyz 或 xyzw)。我建议你在项目一开始就统一约定,并在代码注释里写清楚。
  • 乘法顺序: 记住,四元数乘法对应旋转的复合。q1 × q2 表示先做 q2 旋转,再做 q1 旋转。这个顺序搞反了,姿态就全错了。
  • 归一化: 每次更新后都要归一化。我习惯在互补滤波的每一步更新后都做一次,虽然多花一点计算量,但换来的是稳定性。
  • 半角问题: 从角速度积分得到四元数时,一定要记得用半角。很多初学者在这里翻车。

我的建议: 如果你刚开始接触四元数,先不要急着看复杂的推导。把定义、乘法公式、旋转公式这三个东西背下来,然后直接上手写代码。在实践中理解,比死磕数学要快得多。

好了,四元数的数学基础就讲到这里。这些东西看起来有点枯燥,但它们是整个姿态解算算法的基石。你把这些搞明白了,后面的互补滤波实现就是一马平川。


专注资料整理