第1章:四元数基本运算
各位同学,今天咱们来聊聊四元数的基本运算。说实话,我刚接触四元数那会儿,也觉得这东西挺抽象的。但后来在项目里用多了,发现它其实就是一套很优雅的数学工具。
1.1 四元数的定义与表示
四元数,说白了就是一个四维的超复数。它由一个实部和三个虚部组成:
q = w + xi + yj + zk
其中 w 是实部,x、y、z 是虚部。i、j、k 是三个虚数单位,它们满足一个很有意思的关系:
i² = j² = k² = ijk = -1
嗯,这里要注意,i、j、k 之间是相互正交的,而且乘法不满足交换律。也就是说,i×j ≠ j×i。我在做惯性导航时,就因为这个特性吃过亏,后面会详细说。
在实际编程中,我们通常用四维向量来表示四元数:
q = [w, x, y, z]
或者用结构体:
typedef struct {
float w;
float x;
float y;
float z;
} quaternion_t;
1.2 四元数乘法
四元数乘法是姿态更新的核心运算。它不像普通乘法那么简单,因为涉及到虚数单位之间的交互。
假设有两个四元数:
q₁ = w₁ + x₁i + y₁j + z₁k
q₂ = w₂ + x₂i + y₂j + z₂k
它们的乘积 q = q₁ × q₂ 的计算公式如下:
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 代码实现
void quaternion_multiply(quaternion_t *q1, quaternion_t *q2, quaternion_t *result) {
result->w = q1->w * q2->w - q1->x * q2->x - q1->y * q2->y - q1->z * q2->z;
result->x = q1->w * q2->x + q1->x * q2->w + q1->y * q2->z - q1->z * q2->y;
result->y = q1->w * q2->y - q1->x * q2->z + q1->y * q2->w + q1->z * q2->x;
result->z = q1->w * q2->z + q1->x * q2->y - q1->y * q2->x + q1->z * q2->w;
}
注意:四元数乘法不满足交换律!q₁ × q₂ ≠ q₂ × q₁。我在项目中遇到过,有人把乘法顺序搞反了,结果姿态解算出来的角度完全不对,查了两天才找到问题。
1.3 四元数的共轭
四元数的共轭,其实就是把虚部取反。这个操作在求逆四元数时非常有用。
q = w + xi + yj + zk
q* = w - xi - yj - zk
代码实现很简单:
void quaternion_conjugate(quaternion_t *q, quaternion_t *result) {
result->w = q->w;
result->x = -q->x;
result->y = -q->y;
result->z = -q->z;
}
共轭有一个重要性质:用四元数旋转向量时,旋转后的向量可以通过 q × v × q* 得到。这个公式在姿态更新中会反复用到。
1.4 四元数的范数
范数,说白了就是四元数的"长度"。它的定义和向量范数一样:
||q|| = √(w² + x² + y² + z²)
代码实现:
float quaternion_norm(quaternion_t *q) {
return sqrtf(q->w * q->w + q->x * q->x + q->y * q->y + q->z * q->z);
}
为什么要关心范数?因为单位四元数的范数等于1,而只有单位四元数才能表示旋转。如果范数偏离1,姿态就会产生畸变。
小技巧:我建议每次做完四元数乘法后,都检查一下范数。如果偏离1超过某个阈值(比如0.001),就做一次归一化。这样可以有效防止数值误差累积。
1.5 四元数的归一化
归一化就是把四元数变成单位四元数。操作很简单,每个分量除以范数:
void quaternion_normalize(quaternion_t *q) {
float norm = quaternion_norm(q);
if (norm < 1e-6f) {
// 防止除零
q->w = 1.0f;
q->x = 0.0f;
q->y = 0.0f;
q->z = 0.0f;
return;
}
q->w /= norm;
q->x /= norm;
q->y /= norm;
q->z /= norm;
}
我曾经在无人机项目里,因为忘记做归一化,导致姿态漂移越来越严重。后来在代码里加了个定时器,每10ms强制归一化一次,问题就解决了。
1.6 知识体系总览
下面这张图,是我自己总结的四元数基本运算之间的关系:
从图中可以看出,四个基本运算环环相扣。乘法用于组合旋转,共轭用于求逆,范数用于检查精度,归一化用于保证单位性。我在实际项目中,通常把这四个函数封装成一个工具库,每次调用都很方便。
1.7 运算性质总结
为了方便查阅,我把四元数基本运算的性质整理成了表格:
| 运算 | 公式 | 关键性质 | 工程用途 |
|---|---|---|---|
| 乘法 | q = q₁ × q₂ | 不满足交换律 | 组合旋转、姿态更新 |
| 共轭 | q* = w - xi - yj - zk | (q₁ × q₂)* = q₂* × q₁* | 求逆、向量旋转 |
| 范数 | ||q|| = √(w²+x²+y²+z²) | ||q₁ × q₂|| = ||q₁|| × ||q₂|| | 数值误差检测 |
| 归一化 | q' = q / ||q|| | ||q'|| = 1 | 保证旋转精度 |
核心要点:四元数的四个基本运算,是姿态解算的基石。乘法负责"动",共轭负责"反",范数负责"查",归一化负责"稳"。把这四个运算吃透了,后面的互补滤波和姿态更新就水到渠成了。
好了,这一章的内容就到这里。四元数虽然看起来有点绕,但只要你动手写几遍代码,就会发现它其实很直观。下一章我们聊聊四元数如何表示旋转,那才是真正好玩的地方。
公众号:蓝海资料掘金营,微信deep3321