"如果你认为自己理解了四元数,那你还没有真正理解它们。"
—— 这句流传的话,我们今天要把它打破。
引子:拧开一个瓶盖
想象你正拧开一个汽水瓶盖。
你的手指做了一个动作:捏住瓶盖,旋转,然后——砰,打开了。
这个动作看起来简单极了,但如果我要你用数学精确描述这个旋转,事情突然变得诡异起来。
你说:"就是转了一圈啊,360度。"
但如果我问你:"往哪个方向转?"你会伸出大拇指,比划一个方向。这是旋转轴。
如果我问:"转多快?"你会说匀速,或者先慢后快——这是角速度。
现在问题来了:我们如何用三个数字(x, y, z)来同时表示这三个信息?
更糟糕的是,如果瓶盖拧到一半,我想知道它"现在"的姿态,该怎么办?
这就是四元数要解决的问题。但在我们抵达那里之前,让我们先回到一个更简单的地方。
第一章:复数——旋转的第一次启示
1.1 负数开平方?疯了吧
很久以前,数学家们发现一个尴尬的事实:有些方程没有解。
比如:\(x^2 + 1 = 0\)
"什么数的平方等于 -1?"没有实数满足这个条件。于是数学家们做了一个大胆的决定:发明一个数。
他们称之为 \(i\),并规定:
这就是虚数单位。当时的数学家们觉得这简直是作弊——"你解决不了问题,就发明一个新数?"
但等等,让我们看看这个"作弊"带来了什么。
1.2 复平面上的旋转
复数看起来像这样:\(z = a + bi\)
- \(a\) 是实部(水平方向)
- \(b\) 是虚部(垂直方向)
我们可以把复数画在平面上——这就是复平面。
现在,神奇的事情发生了。
乘以 \(i\) 等于逆时针旋转 90 度。
让我再重复一遍:乘以 \(i\) 等于旋转 90 度。
验证一下:
- \(1 \times i = i\)(从 (1,0) 转到 (0,1),确实是 90 度)
- \(i \times i = -1\)(从 (0,1) 转到 (-1,0),再转 90 度)
- \(-1 \times i = -i\)(再转 90 度)
- \(-i \times i = 1\)(回到起点,总共 360 度)
这不仅仅是巧合。这揭示了一个深刻的真理:乘法可以是旋转。
1.3 欧拉公式的震撼
让我们更进一步。考虑这个复数:
这个复数在复平面上位于单位圆上,与实轴夹角为 \(\theta\)。
现在,欧拉(对,就是那个欧拉)发现了这个惊人的等式:
这意味着:指数的虚幂描述旋转。
如果你把一个复数 \(z\) 乘以 \(e^{i\theta}\),你实际上是把 \(z\) 旋转了角度 \(\theta\)。
这就是二维旋转的完整描述。优美、简洁、强大。
1.4 但三维呢?
现在问题来了。
复数完美地描述了二维平面上的旋转。但我们生活在三维空间。
瓶盖可以绕 x 轴转、绕 y 轴转、绕 z 轴转。如何用一种统一的数学语言描述这些旋转?
19 世纪中叶,一位爱尔兰数学家为此苦苦思索。他的名字叫威廉·罗恩·哈密顿(William Rowan Hamilton)。
第二章:哈密顿的十年求索
2.1 从复数到三元数?
哈密顿的想法很直接:如果复数 \(a + bi\) 能描述二维旋转,那么三元数 \(a + bi + cj\) 应该能描述三维旋转吧?
这里 \(i\) 和 \(j\) 是两个不同的虚数单位,满足:
哈密顿花了十年时间试图让这种三元数工作。他需要定义乘法规则:\(i \times j\) 应该等于什么?
他尝试了各种可能性,但每次都遇到矛盾。要么乘法不满足结合律,要么无法保持向量的长度(这在旋转中很重要)。
2.2 那个顿悟的早晨
1843 年 10 月 16 日,哈密顿和妻子沿着都柏林的皇家运河散步。
他的脑海里一直在转悠着那个问题:如何让三维旋转的代数工作?
突然,灵光一闪。
他意识到:他需要四个维度,而不是三个。
他掏出小刀,在布鲁姆桥(Brougham Bridge)的石栏上刻下了这个公式:
这就是四元数的诞生时刻。
2.3 为什么需要第四个维度?
这是一个深刻的问题。为什么三维旋转需要四维的数学对象来描述?
答案与旋转的不可交换性有关。
想象一本书:
- 先绕 x 轴转 90 度,再绕 y 轴转 90 度
- 先绕 y 轴转 90 度,再绕 x 轴转 90 度
结果一样吗?不一样。旋转的顺序很重要。
数学家说:三维旋转构成一个非阿贝尔群。这意味着乘法顺序不可随意交换。
复数的乘法是可交换的(阿贝尔的)。为了描述非交换的旋转,我们需要更丰富的代数结构——这就是四元数。
第三章:四元数的基本结构
3.1 四元数长什么样
一个四元数写成这样:
或者更常见的向量形式:
其中:
- \(w\) 是标量部分(实部)
- \(\mathbf{v} = (x, y, z)\) 是向量部分
- \(i, j, k\) 是三个虚数单位
3.2 哈密顿关系
哈密顿刻下的那个公式,展开后给出以下乘法规则:
注意那个负号!乘法顺序很重要:\(ij \neq ji\)。
这是一个非交换代数。正是因为这个非交换性,四元数才能描述三维旋转。
3.3 记忆的窍门
记住这些乘法规则有个简单的办法:
想象 \(i, j, k\) 按顺时针排成一个圆圈:
i
/ \
k - j
顺时针相乘得到正的下一个:\(ij = k\),\(jk = i\),\(ki = j\)
逆时针相乘得到负的下一个:\(ji = -k\),\(kj = -i\),\(ik = -j\)
这就像钟表的指针,或者就像……一个旋转本身。
第四章:四元数的运算
4.1 加法与减法
四元数的加法和减法很简单,就像向量一样:
没什么特别的,分量逐个相加就行。
4.2 乘法——核心操作
四元数乘法才是精髓。让我们来计算:
我们需要逐项相乘,然后使用哈密顿关系化简。这有点繁琐,但结果是:
看起来一团糟?让我们用向量形式重写:
等等! 看到了吗?
- 标量部分包含点积 \(\mathbf{v}_1 \cdot \mathbf{v}_2\)
- 向量部分包含叉积 \(\mathbf{v}_1 \times \mathbf{v}_2\)
四元数乘法统一了点积和叉积。这不是巧合——这是几何的深层结构。
4.3 共轭与模
共轭(就像复数的共轭):
模(长度):
4.4 逆元
有了共轭,我们可以定义逆元:
验证:\(q q^{-1} = \frac{qq^*}{|q|^2} = \frac{|q|^2}{|q|^2} = 1\) ✓
注意:四元数的逆总是存在的(除了 \(q=0\)),这让我们可以做除法。
第五章:用四元数表示旋转
5.1 旋转四元数
现在到了最精彩的部分:如何用四元数表示三维旋转。
给定一个旋转:
- 旋转轴:单位向量 \(\mathbf{u} = (u_x, u_y, u_z)\)
- 旋转角:\(\theta\)
对应的旋转四元数是:
或者简写:
注意那个 \(\frac{\theta}{2}\)!这是四元数旋转的标志性特征。旋转角度被"平分"了。
5.2 为什么是半角?
这个问题困扰了我很久。为什么公式里是 \(\theta/2\) 而不是 \(\theta\)?
答案是:四元数旋转使用"双侧乘法"。
为了旋转一个向量 \(\mathbf{v}\),我们这样做:
这里 \(\mathbf{v}\) 被表示为纯虚四元数:\(0 + v_x i + v_y j + v_z k\)。
因为我们要乘以 \(q\) 两次(左乘和右乘),所以每个 \(q\) 只需要包含一半的角度。\(q\) 里的 \(\theta/2\) 乘以 2,得到完整的 \(\theta\)。
这就像两个人抬重物:每人只需要出一半的力。
5.3 旋转公式的工作原理
让我们验证这个公式确实产生旋转。
考虑简单情况:绕 z 轴旋转角度 \(\theta\)。
旋转轴是 \(\mathbf{u} = (0, 0, 1)\),所以:
现在把向量 \(\mathbf{v} = (x, y, 0)\)(xy 平面上的点)写成四元数:\(v = xi + yj\)
计算 \(qvq^{-1}\):
继续计算 \((qv)q^{-1}\)……经过一番代数运算(相信我省略的代数,或者自己算一遍),你会得到:
这正是二维旋转矩阵的作用!
它真的工作了!
5.4 单位四元数
在旋转应用中,我们通常使用单位四元数,即模为 1 的四元数:
对于单位四元数,逆元就是共轭:
旋转公式简化为:
单位四元数构成一个三维球面(在四维空间中),称为 \(S^3\)。所有三维旋转对应于 \(S^3\) 上的点(以及对径点,因为 \(q\) 和 \(-q\) 表示同一个旋转——这就是为什么我们说旋转对应于 \(S^3\) "模去" 对径映射)。
第六章:四元数 vs 欧拉角 vs 旋转矩阵
6.1 三种表示方法
在三维图形学和机器人学中,有三种主要的旋转表示方法:
1. 欧拉角(俯仰、偏航、翻滚)
用三个角度 \((\alpha, \beta, \gamma)\) 描述旋转。
优点:直观,容易理解 缺点:万向节锁(Gimbal Lock)
2. 旋转矩阵
用 3×3 矩阵描述旋转:
优点:直接作用于向量 缺点:9 个数但只有 3 个自由度,有冗余;插值困难
3. 四元数
用 4 个数 \((w, x, y, z)\) 描述旋转,满足 \(w^2 + x^2 + y^2 + z^2 = 1\)
优点:紧凑、无万向节锁、插值平滑 缺点:不直观、需要理解抽象代数
6.2 万向节锁的悲剧
万向节锁是什么?想象一个陀螺仪:
当两个旋转轴对齐时,你突然失去了一个自由度。你只能绕着两个轴旋转,而不是三个。
用数学语言:当俯仰角为 ±90 度时,偏航和翻滚变成同一个旋转。
这不仅仅是理论问题。在航天史上,万向节锁真的造成过事故。阿波罗 11 号就曾经历过万向节锁的警报。
四元数没有这个问题。因为四元数直接描述最终旋转状态,而不是通过一系列中间旋转。
6.3 插值:SLERP 的魔法
假设你有两个旋转,想在它们之间平滑过渡。
用欧拉角?你会经过奇怪的路径。 用旋转矩阵?线性插值矩阵会得到非正交矩阵(不是合法旋转)。 用四元数?欢迎来到**球面线性插值(SLERP)**的美妙世界。
给定两个单位四元数 \(q_1\) 和 \(q_2\),SLERP 公式是:
其中 \(\Omega\) 是两个四元数之间的夹角:\(\cos\Omega = q_1 \cdot q_2\)
这个结果沿着最短路径(大圆)在四维球面上移动,对应于三维空间中的恒定角速度旋转。
这就是为什么游戏引擎和动画软件都用四元数。角色动画中那种流畅自然的旋转过渡?那就是 SLERP 的功劳。
第七章:从四元数到几何代数
7.1 回顾我们的旅程
让我们回顾我们已经走了多远:
- 复数:二维旋转 \(e^{i\theta}\)
- 四元数:三维旋转 \(q = \cos\frac{\theta}{2} + \mathbf{u}\sin\frac{\theta}{2}\)
自然会问:四维旋转呢?五维呢?有没有一个统一的框架?
有的。它叫做几何代数(Geometric Algebra)。
7.2 几何代数的基本思想
几何代数的基本对象是多向量(multivector),它可以包含:
- 标量(0维)
- 向量(1维)
- 双向量(2维,表示面积)
- 三向量(3维,表示体积)
- ……
几何积是核心操作。对于两个向量 \(\mathbf{a}\) 和 \(\mathbf{b}\):
- \(\mathbf{a} \cdot \mathbf{b}\) 是标量(内积)
- \(\mathbf{a} \wedge \mathbf{b}\) 是双向量(外积)
这看起来很像四元数乘法,不是吗?
7.3 四元数是几何代数的子集
事实上,四元数就是三维空间几何代数中的偶子代数。
具体来说:
- \(i, j, k\) 对应于三个坐标平面上的双向量(有向面积)
- \(i = e_2 \wedge e_3\)(yz 平面)
- \(j = e_3 \wedge e_1\)(zx 平面)
- \(k = e_1 \wedge e_2\)(xy 平面)
四元数的乘法规则,就是双向量在几何代数中的乘法规则。
7.4 旋子:旋转的一般形式
在几何代数中,旋转由一个称为旋子(rotor)的对象描述:
其中 \(B\) 是一个双向量,表示旋转平面和大小。
对于三维空间中的绕轴旋转,\(B = \theta \hat{B}\),其中 \(\hat{B}\) 是垂直于旋转轴的平面的单位双向量。
展开指数:
如果你把 \(\hat{B}\) 识别为 \(u_x i + u_y j + u_z k\),你就得到了四元数旋转公式。
四元数就是三维空间中的旋子。
7.5 更高维度的推广
现在美妙的事情发生了。
在几何代数中,旋子公式 \(R = e^{-B/2}\) 适用于任意维度。
- 二维:旋子是单位复数 \(e^{i\theta}\)
- 三维:旋子是单位四元数
- 四维:旋子是"双四元数"(有两个分量,8个数)
- n维:旋子有 \(2^{n-1}\) 个分量
更高维度的旋转可以同时在多个平面上进行,因为高维空间可以有不只一个"垂直于给定轴的平面"。
第八章:实践中的四元数
8.1 代码实现
以下是 Python 中一个简单的四元数类:
import numpy as np
class Quaternion:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.z = z
self.v = np.array([x, y, z])
def __mul__(self, other):
"""四元数乘法"""
w = self.w * other.w - np.dot(self.v, other.v)
v = (self.w * other.v + other.w * self.v +
np.cross(self.v, other.v))
return Quaternion(w, v[0], v[1], v[2])
def conjugate(self):
return Quaternion(self.w, -self.x, -self.y, -self.z)
def norm(self):
return np.sqrt(self.w**2 + self.x**2 + self.y**2 + self.z**2)
def normalize(self):
n = self.norm()
return Quaternion(self.w/n, self.x/n, self.y/n, self.z/n)
def inverse(self):
"""单位四元数的逆就是共轭"""
return self.conjugate()
def rotate_vector(self, vec):
"""用四元数旋转向量"""
# 将向量表示为纯虚四元数
v_quat = Quaternion(0, vec[0], vec[1], vec[2])
# 应用旋转: q * v * q^-1
result = self * v_quat * self.inverse()
return np.array([result.x, result.y, result.z])
@staticmethod
def from_axis_angle(axis, angle):
"""从旋转轴和角度创建四元数"""
axis = np.array(axis) / np.linalg.norm(axis)
half_angle = angle / 2
w = np.cos(half_angle)
v = axis * np.sin(half_angle)
return Quaternion(w, v[0], v[1], v[2])
def to_axis_angle(self):
"""转换为轴-角表示"""
if abs(self.w) > 1:
self = self.normalize()
angle = 2 * np.arccos(self.w)
s = np.sqrt(1 - self.w**2)
if s < 1e-8: # 接近零旋转
axis = np.array([1, 0, 0])
else:
axis = self.v / s
return axis, angle
def __repr__(self):
return f"Quaternion({self.w:.4f}, {self.x:.4f}, {self.y:.4f}, {self.z:.4f})"
# 示例:绕 z 轴旋转 90 度
q = Quaternion.from_axis_angle([0, 0, 1], np.pi/2)
vec = np.array([1, 0, 0])
rotated = q.rotate_vector(vec)
print(f"Original: {vec}")
print(f"Rotated: {rotated}") # 应该接近 [0, 1, 0]
8.2 SLERP 实现
def slerp(q1, q2, t):
"""球面线性插值"""
# 确保输入是单位四元数
q1 = q1.normalize()
q2 = q2.normalize()
# 计算夹角
dot = q1.w*q2.w + q1.x*q2.x + q1.y*q2.y + q1.z*q2.z
# 如果点积为负,反转一个四元数以走最短路径
if dot < 0:
q2 = Quaternion(-q2.w, -q2.x, -q2.y, -q2.z)
dot = -dot
# 如果四元数非常接近,使用线性插值
DOT_THRESHOLD = 0.9995
if dot > DOT_THRESHOLD:
# 线性插值并归一化
result = Quaternion(
q1.w + t*(q2.w - q1.w),
q1.x + t*(q2.x - q1.x),
q1.y + t*(q2.y - q1.y),
q1.z + t*(q2.z - q1.z)
)
return result.normalize()
# 计算插值角度
theta_0 = np.arccos(dot) # 原始夹角
theta = theta_0 * t # 当前角度
sin_theta = np.sin(theta)
sin_theta_0 = np.sin(theta_0)
s0 = np.cos(theta) - dot * sin_theta / sin_theta_0
s1 = sin_theta / sin_theta_0
return Quaternion(
s0*q1.w + s1*q2.w,
s0*q1.x + s1*q2.x,
s0*q1.y + s1*q2.y,
s0*q1.z + s1*q2.z
)
8.3 常见应用
游戏开发:
- Unity 使用四元数表示所有旋转
- Unreal Engine 也使用四元数
- 角色动画中的骨骼旋转
航空航天:
- 航天器姿态控制
- 无人机飞行控制
- 惯性导航系统
计算机视觉:
- 相机姿态估计
- 三维重建
- SLAM(同步定位与地图构建)
机器人学:
- 机械臂运动学
- 路径规划
- 抓取姿态
结语:旋转的本质
让我们回到开头的那个汽水瓶盖。
你拧开瓶盖的动作,本质上是一个旋转——绕某个轴转动某个角度。
这个看似简单的动作,却需要四维的数学才能精确描述。这不是因为我们生活在四维空间,而是因为三维旋转本身具有非交换的、拓扑的结构。
四元数的美妙之处在于:
- 它是紧凑的:4 个数描述 3 个自由度(比旋转矩阵的 9 个数高效)
- 它是无歧义的:没有万向节锁
- 它是可插值的:SLERP 提供自然的旋转过渡
- 它是普适的:是几何代数中旋子的三维特例
但更重要的是,四元数教会我们一件事:数学对象的价值不在于它的直观性,而在于它的力量。
复数曾经被认为是"虚构"的,直到它们被证明是描述电磁波的完美工具。四元数曾经被嘲笑为非交换的怪物,直到它们成为计算机图形学的标准。
所以,下次当你在游戏中看到流畅的角色动画,或者使用手机的 AR 功能时,记住:在那背后,有四个数在跳舞。
它们不直观,但它们真实。它们不显然,但它们强大。
这就是四元数——旋转的诗篇。
延伸阅读
历史与直觉:
- 《Quaternions and Rotation Sequences》(Kuipers) - 四元数经典教材
- 3Blue1Brown 的 YouTube 系列《四元数的可视化》
技术深度:
- 《Geometric Algebra for Physicists》(Doran & Lasenby)
- 《Geometric Algebra for Computer Science》(Dorst et al.)
现代应用:
- GATr 和 Versor 论文(几何代数在深度学习中的应用)
#记忆 #四元数 #几何代数 #数学 #教程 #费曼风格 #小凯
讨论回复
0 条回复还没有人回复,快来发表你的看法吧!
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。