四元数 Quaternions 又称 汉密尔顿数 Hamiltonians 这玩意就很抽象,看了半天愣是没看懂。 它本质上是一个数系,隶属于抽象代数,和我们了解过的实数,有理数,p进数,复数… 并列存在 欸,说白了,他就是 $w+xi+yj+zk$ ,一个四维的复数空间

四元数用一个四维数学结构来表示旋转,可以看作是一个旋转轴+一个旋转角度的封装。

我们之前了解过$e^{i\pi}=-1$,这实际上是一个复平面的上圆,我们也了解过对一个虚数(我们把它理解为复平面上的向量)$a+bi$乘一个$i$实际上是对其逆时针旋转90°,我们不妨把这个拓展到三维上来…

四元数之所以会在现在被广泛采纳,就是因为它在计算上比其他方法要更加高效,而且还能避免许多数值误差,即便它的可读性非常差。相比于欧拉数,它也没有万向节死锁,避免了类似的奇异,且插值是平滑的 (球面线性插值 Slerp)。

当然,最终为了可读性,我们还是要将四元数转化为欧拉角的,所以我才会把这两个东西放在同一个文件夹里。

归根结底,四元数可以表示一种三维旋转过程,也可以表示一种状态,这取决于你如何去使用它。 这之前我们先进一步了解一些前置知识吧

空间球体降维

作为一个三维生物,我们不太能理解高维的世界是怎么样的,但是实际上可以将高维的几何体通过某种方式映射到低维,虽然这个几何体在高维可能并没有体积,也就是说,它在高维只是个薄片。但是我们仍然可以通过这个方法来一窥高维的几何世界。

二维单位圆映射到一维

我们这里所说的是一个单位圆,也就是说,它实际上没有面积。另外,不用考虑高斯绝妙定理之类的事情,这是非刚性的变化。你要做的就是把一个圆环展开一个一维数轴上。

不妨将单位圆的圆心$O$与数轴原点重合,记远点为 $P$,连接 $P$ 与圆上的每一个点,交直线于点 $A_n$,这样就可以把圆上的每一个点映射到数轴上了,不过疏密程度会不同。 按照这个方法,很容易得知上半圆落在 $[-1,1]$ 的区间里,下半圆落在 $[-\infty,-1],[1,\infty]$ 区间里,$P$点在数轴上对应的位置就是 $\infty$

(忘了提了,现在我们把复平面的x和y轴换了一下,横着的是虚数轴了,铅锤的为实数轴)

现在,数轴上 $0$ 的位置就对应实数单位 $1$,$-1$ 对应 $-i$,$1$ 对应 $i$,而 $\frac{\sqrt{2}}{2}+\frac{\sqrt{2}}{2}i$ 落在$[0,1]$之间,$-1$则在$\infty$的位置上 再次提醒,此时数轴所能表示的只是二维复平面中一个单位圆上的点,其他点是看不到的

为什么不直接线性的映射到 $[-\frac{\pi}{2},\frac{\pi}{2}]$ 区间上呢?

这是为了保证运算的统一性。我们主要是研究空间的旋转和拉伸的运算,当然,这里我们只研究旋转,为了让二维的旋转操作能够在一维上有所体现,我们需要一个连续且封闭的”空间”,即加减法和数乘所得到的值仍然属于这个”空间”

假如线性映射,按照二维复平面的旋转规则,我们对其中任意一个数进行旋转操作,即右乘一个”旋转函数”$z$,数轴理应得到一个和原来差不多样子的映射,但是这种线性映射就无法达到这种效果。

相反,如果是上面这种映射方法,在乘以一个 $z$ ,比方说 $i$ 之后,原来的 $i$ 会到 $-1$ 的位置去,原来的 $-1$ 从 $\infty$ 来到了数轴的 $-1$ 上,也就是代表 $-i$ 的点

三维单位球映射到二维

继续将铅锤的作为实数轴 现在有三个轴了,也就是 $a+bi+cj$,但是三维数其实没有良好的乘法规则,即 $ij\neq{ji}$,但是你又不知道他们等于什么。当然,这确实是导致它无法定义旋转的原因之一,因为乘法太难算了。这里我们只是拿三元数来类比。

同样的,我们这里所说的是一个没有体积的单位球 不妨将单位球的球心$O$与平面坐标系的原点重合,记远点为$P$,连接$P$于球上的每一个点,交平面于点$A_n$。按照这个方法,很容易得知上半球落在 $[(x,y)||x|\leq1,|y|\leq1]$ 的区间里,下半球落在其他延伸到无穷的区间内。

四维单位球映射到三维

我们给到了这么一个四维向量 $w+xi+yj+zk$,具体理解可以去看3b1b的视频,这里只讲我的理解。 继续将铅锤的作为实数轴,那么剩下三个轴 $i,j,k$ 则会以某种四维的方式在一个三维空间中互相垂直。我们把上半超球记为$w>0$的部分,那么显然,按照规律,它会被映射到三维的一个单位球内,$w=0$的部分则正好是三维的一个单位球,$w<0$的部分则从球开始延伸到无穷外。

更方便的来理解,$i,j,k$ 实际上表示为了三维中的方向,而$w$则反应为”长度”

注意!此长度非彼长度!此方向非彼方向!

我们说了现在三维应该被一个四维单位超球映射,所以四个数恒满足\(w^2+x^2+y^2+z^2=1\)

也就是说,$w\in(-1,1)$,我们说的$w$的$(0,1)$被映射在了三维的单位球内部,$(-1,0)$则从球面开始映射到无穷

相应的,$i,j,k$表示方向的方法是通过$x^2+y^2+z^2=1-w^2$来设置权重的,也就是说,$i,j,k$表示方向的方法是通过相互之间的比值,而不是绝对长度,不然你没法保证上面的的等式成立

高维复空间旋转

对于一个复数$z=a+bi$和一个单位复数$e^{i\theta}=\cos{\theta}+i\sin{\theta}$

$z\cdot e^{i\theta}$代表将$z$绕原点逆时针旋转$90°$,它通过一个二维数优雅的封装了二维旋转 或者,你可以将$z$看作一个旋转函数,他做的实际上是将原本的单位向量$+i$拉伸到$z$的位置,也就等同于旋转拉伸的操作了 我们不妨这样来理解

\[z_1\cdot z_2=\left(\frac{z_1}{||z_1||}\right)||z_1||\cdot z_2\]

前面的$\left(\frac{z_1}{||z_1||}\right)$代表旋转操作,$||z_1||$代表拉伸操作 稍加思考,你就知道了一个单位向量 unit vector作为操作时就代表纯旋转

很自然的,我们能够想到,如果将空间拓展到三维,那么该如何表示封装旋转呢? 哈密顿提出需要四个数才能实现信息不丢失的旋转运算,即 $w+xi+yj+zk$,他们同时满足

\[\displaylines { i^2=j^2=k^2=ijk=-1\\ ij=k,ji=-k\\jk=i,kj=-1\\ ki=j,ik=-j }\]

我只能说这真的非常丑,这也是使得它的乘法变得非常繁琐,这里就不列公式了

关于为什么二维空间封装只需要两个数,而三维需要四个

二维空间的旋转操作构成 $U(1)$ 群,所以它只需要二维数就可以封装旋转了,复杂度不高

但是三维空间的旋转操作构成 $SO(3)$ 群,因为虽然只加了一个轴,但是实际上多了两个面,即$C\left(\displaylines{3 \ 2}\right)=3$,所以复杂度并不是线性增加的

和二维复平面类似类似四维也可以用类似的公式来表示四维的旋转和拉伸操作

\[q_1\cdot q_2=\left(\frac{q_1}{||q_1||}\right)||q_1||\cdot q_2\]

这里我们也只讨论单位四元数$q_1$作为纯旋转操作的情况 当然,这时候就不满足交换律了,左乘和右乘需要区分,这就好像魔方一样,旋转的顺序不同,结果也是不同的。

四维旋转的理解

你可以将一个四维旋转理解为两个独立的二维旋转,而这两个二维旋转面相互垂直。 我们不妨设这两个旋转面分别以$w,i$和$j,k$为轴,而注意,我们现在能看到的是$i,j,k$轴,$w$轴是垂直于这三个轴的第四维,我们是看不见的。

  • $j,k$的圆很好表示,你只需要在$jOk$平面上画一个单位圆就行了。
  • $w,i$平面中的$w$是无法在三维空间中显示的,所以这么一个单位圆就可以像之前二维变一维的一样映射到$i$轴上
  • 这时,$j,k$轴上圆的旋转会同时带动映射到$i$轴上的圆的旋转

当然,这里只是给了两个参考圆在分别在$j,k$和$w,i$上,实际上哪哪都是圆。 这时候四维的旋转就其作用了,还记得我们上面定义的三个虚数的乘法规则吗,那实际上就代表了一个旋转操作和一个点的移动过程。 就像我们在一维里描述的一样,被映射到指定轴上的圆发生旋转,表示在三维中就是这个轴上的映射发生移动。而垂直于这个”圆”的圆在三维看来是在一个二维平面中正常旋转的,则遵循右手螺旋定则的,按照手指的方向旋转。

右手螺旋定则

你的大拇指指向操作单位向量的方向,也就是其中一个圆映射到的轴的方向 手指卷起来,手指的方向就是与被映射的圆垂直的圆的旋转方向

另外,事实上,你可以把所有东西都考虑成一个函数,比如$×0.5$代表放缩$0.5$倍,$×-1$代表旋转$180°$


目前为止,我们还不知道四元数怎么描述三维旋转,我们只是知道了怎么在三维空间里表示四元数的单位超球。接下来,我们只关注$w=0$的单位四元数,这在上一节我们说了,这个四维超球的 $w=0$ 的部分在三维上也映射为一个单位圆。

还记得一开始我们说四元数的功能吗?它可以表示一种状态,但更多时候表示一种旋转操作。也就是说,设三维向量为$p$,表示旋转操作的四元数为$q$,则有$q\cdot p$来表示对三维向量的旋转操作。

但是,一个四维的怎么能降维对三维向量进行旋转呢?

四元数单位化简写

我们表示一个三维旋转需要一个旋转轴旋转角度,以及一个伸缩比例,这恰好符合四元数对四个参数的需求——两个变量决定轴的方向,一个变量决定旋转角度,一个变量决定伸缩比例。 我们已知:

  • 旋转角度:$θ$.
  • 旋转轴:\(\vec u=(u_x,u_y,u_z)\) ,满足 \(u\) 长度为 1
  • 四元数通常写成:$q=w+xi+yj+zk$,其中 $w$ 是实部,$(x,y,z)$ 是虚部向量,你也可以写成 $w+\vec{u}$,也就是一个标量和一个三维向量。也就可以理解为绕轴v旋转θ度.

则有:

\[q\left(\frac{\theta}{2}, \vec{u}\right) = \cos\left(\frac{\theta}{2}\right) + \sin\left(\frac{\theta}{2}\right)(u_x i + u_y j + u_z k)\]

也就是:

\[q = \cos\frac{\theta}{2} + \left(\sin\frac{\theta}{2}\cdot u_x\right)i + \left(\sin\frac{\theta}{2}\cdot u_y\right)j + \left(\sin\frac{\theta}{2}\cdot u_z\right)k\]

类比一下二维旋转$e^{i\theta}=\cos{\theta}+\sin{\theta}i$,会发现单位四元数的简化表示其实把$i$换成了$i\ j\ k$ 我们先不考虑为什么这里是$\frac{\theta}{2}$,下面会解释的

值得一提的是,需要单位化四元数的原因和需要单位化正交分解后的矩阵的原因是一样的,都是为了表示一个刚性的旋转操作,而不做拉伸。

四元数的旋转

四元数旋转三维向量时会先将三维向量 $p=\left(x,y,z\right)^T$ 升维成 $p=\left(\displaylines{0,x,y,z}\right)^T$

为啥要升维

我们之前替代了三元数乘法不存在良定义,除非你引进第三个量$k$,也就是升为到四维,这样乘法就可以算了,而这个乘法也就包括了数乘,点乘和叉乘

之后,我们进行四元数的乘法运算$q\cdot p$,得到一个新的四元数

\[p'=q(\frac{\theta}{2},\vec{u})pq^{-1}(\frac{\theta}{2},\vec{u})=(0,x`,y`,z`)\]

这式子非常奇怪,一个好端端的 $q\cdot p$ 哪来这么多东西? 正常来说,$q\cdot p$ 就够了,但是你知道这一个操作会把好好的一个三维向量拉进四维,但是你还是需要一个三维向量啊!浅显来说,我们还需要一个逆操作,就是在后面再乘一个$q^{-1}$来抵消前面的操作。

当然,这样做还有一个好处,就是抵消了位移和形变,使得其就是一个单纯的纯旋转操作。至于为什么,我们需要先知道点乘和叉乘

点乘和叉乘

其实相当好理解,这在我们高中学物理单位制的时候就出现了很多,因为你会发现有一些有时候两个向量出来之后还是一个向量,这和点乘的性质不符。当然,你得明确这个乘法是针对于两个向量来说的,下面我们令其为$\vec{A},\vec{B}$

四元数包含实数虚数部分,实数实数运算是点乘虚数矢量计算叉积利用叉积就能表示方向的变化,从而四元数的乘法可以表示为

\[q_1q_2=(w_1w_2,叉乘部分)\]

因此对原向量$\vec{v}$做四元数乘积,除了叉积完成了旋转的变化,还有点积产生了不应该的拉伸分量。 因此使用双乘法,$q\vec{p}q^{-1}$,通过乘以q逆反向抵消拉伸分量。

同时,因为乘了两遍$q$,所以要把其转的角度表示为$\frac{\theta}{2}$

四元数转欧拉角

这里不做具体的推演了,直接上公式。

\[\begin{cases}\theta=-\arcsin2(q_1q_2-q_0q_3)\\\psi=\arctan\frac{2(q_1q_2+q_0q_3)}{q_3^2+q_2^2-q_1^2+q_0^2}\\\gamma=\arctan\frac{2(q_1q_3+q_0q_1)}{q_3^2+q_2^2-q_1^2+q_0^2}\end{cases}\]