3、四元数基础:数学定义、旋转与基本运算

各位同学,欢迎来到第三讲。今天咱们聊聊四元数。

说实话,我第一次接触四元数的时候,头都是大的。什么虚部实部,什么i、j、k,感觉像在学天书。但后来在飞控项目里被欧拉角狠狠坑过一次——万向锁导致无人机直接翻了个跟头——从那以后,我就老老实实把四元数啃下来了。

你想想看,一个能在三维空间里自由旋转、还没有死角的数学工具,它不香吗?

3.1 四元数的数学定义

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

q = w + xi + yj + zk

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

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

嗯,这里要注意,i、j、k之间不满足交换律。也就是说:

i × j = k
j × i = -k

这个特性很重要,后面讲旋转的时候会用到。

我们通常把四元数写成向量形式:

q = [w, x, y, z]ᵀ

或者更规范一点:

q = [w, v]  其中 v = (x, y, z)

核心要点:四元数本质上是一个四维向量,但它能优雅地表示三维空间中的旋转。

3.2 四元数与旋转

为什么四元数能表示旋转?我当年也困惑了很久。

其实道理很简单:任何一个三维旋转,都可以用一个单位四元数来表示。假设我们要绕单位向量 n = (nx, ny, nz) 旋转 θ 角度,那么对应的四元数是:

q = cos(θ/2) + sin(θ/2) · (nx·i + ny·j + nz·k)

写成向量形式:

q = [cos(θ/2), sin(θ/2)·nx, sin(θ/2)·ny, sin(θ/2)·nz]

举个例子,绕Z轴旋转90度:

θ = 90°, n = (0, 0, 1)
q = [cos45°, 0, 0, sin45°] = [0.707, 0, 0, 0.707]

个人经验:我在做IMU姿态解算时,经常用这个公式把角度转换成四元数。记住,角度一定要用半角,这是初学者最容易犯错的地方。

3.3 四元数的基本运算

好了,理论讲完了,咱们来点实在的。四元数的运算其实不复杂,我给大家梳理一下。

3.3.1 加法

两个四元数相加,就是对应分量相加:

q₁ = [w₁, x₁, y₁, z₁]
q₂ = [w₂, x₂, y₂, z₂]
q₁ + q₂ = [w₁+w₂, x₁+x₂, y₁+y₂, z₁+z₂]

这个很简单,没什么好说的。

3.3.2 乘法

四元数乘法就有点意思了。它不满足交换律,所以顺序很重要。

假设:

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₂]

展开成标量形式:

w = w₁w₂ - x₁x₂ - y₁y₂ - z₁z₂
x = w₁x₂ + x₁w₂ + y₁z₂ - z₁y₂
y = w₁y₂ - x₁z₂ + y₁w₂ + z₁x₂
z = w₁z₂ + x₁y₂ - y₁x₂ + z₁w₂

我曾经踩过的坑:在C语言里实现四元数乘法时,一定要注意不能原地更新。比如 q1 = q1 * q2,如果你先更新了w分量,后面计算x、y、z时用的w就已经变了。正确的做法是用临时变量。

3.3.3 共轭

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

q = [w, x, y, z]
q* = [w, -x, -y, -z]

共轭有什么用?它和逆四元数关系密切。对于单位四元数,它的逆就等于共轭:

q⁻¹ = q*  (当 ||q|| = 1时)

这个性质在姿态解算中太常用了。比如我们要把一个向量从机体坐标系转到世界坐标系,就是用共轭四元数去乘。

3.3.4 模长

四元数的模长,就是它的范数:

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

单位四元数的模长为1。为什么叫单位四元数?因为它模长是1,就像单位向量一样。

重要提醒:在飞控代码里,每次更新完四元数后,我建议都做一次归一化。因为数值计算会引入误差,导致模长偏离1。不归一化的话,旋转会变形,姿态会漂移。

3.4 实战:用四元数旋转一个向量

说了这么多,咱们来点实际的。怎么用四元数旋转一个三维向量?

假设有一个向量 p = (px, py, pz),我们把它写成纯四元数形式:

p_quat = [0, px, py, pz]

然后用旋转四元数 q 去旋转它:

p_rotated = q × p_quat × q*

注意顺序:先左乘q,再右乘q的共轭。结果p_rotated的虚部就是旋转后的向量。

举个例子:

// 绕Z轴旋转90度
q = [0.707, 0, 0, 0.707]
p = [0, 1, 0, 0]  // 指向X轴正方向

// 计算 p_rotated = q * p * q*
// 结果应该是 [0, 0, 1, 0],指向Y轴正方向

我的习惯:在代码里,我会把四元数旋转封装成一个函数。输入是四元数和三维向量,输出是旋转后的三维向量。这样调用起来特别清爽,不容易出错。

3.5 本章小结

来,咱们捋一捋今天的内容:

  • 四元数定义:一个实部加三个虚部,q = w + xi + yj + zk
  • 旋转表示:绕轴n转θ,对应q = [cos(θ/2), sin(θ/2)·n]
  • 基本运算:加法对应分量相加,乘法注意顺序,共轭虚部取反,模长是平方和开根
  • 向量旋转:p_rotated = q × p_quat × q*

下一讲,咱们会深入四元数在姿态解算中的具体应用。到时候我会分享一些实际项目中的代码和调试经验,敬请期待。

记住,四元数这东西,刚开始觉得绕,用多了就顺了。我在项目里已经离不开它了,希望你也是。