四元数的使用
四元数可以理解成一个四维空间的量(其由四个变量组成),常用在三维旋转坐标下求取一个向量的坐标。四元数可以抽象地理解成对一种三维旋转方式的代表,这个旋转方式由两部分组成:一部分是旋转轴,这个可以用一个三维向量表示 v = ( v x , v y , v z ) v = (v_x,v_y,v_z) v=(vx,vy,vz),另一部分则是坐标系顺该旋转轴旋转角度,逆时针为正,例如 θ \theta θ。
再已知这两部分的前提下,旋转操作是唯一的,我们用四元数来表示这种旋转操作,记为:
q
=
(
c
o
s
θ
2
,
v
x
s
i
n
θ
2
,
v
y
s
i
n
θ
2
,
v
z
s
i
n
θ
2
)
q = (cos\frac{\theta}{2},v_xsin\frac{\theta}{2},v_ysin\frac{\theta}{2},v_zsin\frac{\theta}{2})
q=(cos2θ,vxsin2θ,vysin2θ,vzsin2θ)
现在假如我们已知一个三维向量
h
=
(
x
,
y
,
z
)
h=(x,y,z)
h=(x,y,z),我们想知道在
q
q
q这种旋转操作下在新坐标系
h
′
h'
h′的坐标,该怎么办?
下面解决方法我们不谈为什么,只讲怎么解决。
引入纯四元数这个概念,什么叫纯四元数,就是四元数有一个分量为0,然后将 h h h扩充为纯四元数 h 4 = ( 0 , x , y , z ) h_4=(0,x,y,z) h4=(0,x,y,z)也就是三维量变四维量,但事实上这个纯四元数也只是四维空间的一个三维超平面而已。
那么经过
q
q
q旋转后在新坐标系下
h
′
h'
h′的坐标可以用如下四元数表示:
h
′
=
q
−
1
v
q
h'=q^{-1}vq
h′=q−1vq
上面这个式子用到了四元数的乘法,下面引出四元数乘法的公式:(
q
1
=
(
w
1
,
x
1
,
y
1
,
z
1
)
,
q
2
=
(
w
2
,
x
2
,
y
2
,
z
2
)
q_1=(w_1,x_1,y_1,z_1),q_2=(w_2,x_2,y_2,z_2)
q1=(w1,x1,y1,z1),q2=(w2,x2,y2,z2))
q
1
∗
q
2
=
(
w
1
w
2
−
x
1
x
2
−
y
1
y
2
−
z
1
z
2
,
w
1
x
2
+
x
1
w
2
+
y
1
z
2
−
z
1
y
2
,
w
1
y
2
−
x
1
z
2
+
y
1
w
2
+
z
1
x
2
,
w
1
z
2
+
x
1
y
2
−
y
1
x
2
+
z
1
w
2
)
q_1*q_2=(w_1w_2-x_ 1x_2-y_1y_2-z_1z_2,w_1x_2+x_1w_2+\\y_1z_2-z_1y_2,w_1y_2-x_1z_2+y_1w_2+z_1x_2,w_1z_2+x_1y_2\\-y_1x_2+z_1w_2)
q1∗q2=(w1w2−x1x2−y1y2−z1z2,w1x2+x1w2+y1z2−z1y2,w1y2−x1z2+y1w2+z1x2,w1z2+x1y2−y1x2+z1w2)
同样,一个四元数的共轭(逆运算)定义为:
q
−
1
=
(
w
,
−
x
,
−
y
,
−
z
)
q^{-1}=(w,-x,-y,-z)
q−1=(w,−x,−y,−z)
最后旋转后向量的坐标为
h
′
h'
h′的后三个分量。
下面先给出乘法和逆运算的MATLAB函数:
function result = quaternionMultiplication(q1,q2)
result(1) = q1(1)*q2(1) - q1(2)*q2(2) - q1(3)*q2(3) - q1(4)*q2(4);
result(2) = q1(1)*q2(2) + q1(2)*q2(1) + q1(3)*q2(4) - q1(4)*q2(3);
result(3) = q1(1)*q2(3) - q1(2)*q2(4) + q1(3)*q2(1) + q1(4)*q2(2);
result(4) = q1(1)*q2(4) + q1(2)*q2(3) - q1(3)*q2(2) + q1(4)*q2(1);
end
function result = quaternionInv(q1)
result(1) = q1(1);
result(2) = -q1(2);
result(3) = -q1(3);
result(4) = -q1(4);
end
四元数 q − 1 v q q^{-1}vq q−1vq和 q v q − 1 qvq^{-1} qvq−1区别
区别在于旋转方向发生改变:
psai = pi/4; phi = pi/6; theta = pi/3;
q1 = [cos(psai/2),0,0,sin(psai/2)];
v1 = [0,1,1,0]; sqrt(sum(v1.^2))
% temp1 = quaternionMultiplication(q1,v1);
% temp2 = quaternionInv(q1);
% vRotation1 = quaternionMultiplication(temp1,temp2);
% vRotation1 = vRotation1(2:4)
% sqrt(sum(vRotation1.^2))
temp1 = quaternionMultiplication(quaternionInv(q1),v1);
vRotation1 = quaternionMultiplication(temp1,q1);
vRotation1 = vRotation1(2:4)
sqrt(sum(vRotation1.^2))
figure();
v2 = [1,1,0];
plot3([0,vRotation1(1)],[0,vRotation1(2)],[0,vRotation1(3)],"r","LineWidth",3);
hold on;
plot3([0,v2(1)],[0,v2(2)],[0,v2(3)],"b","LineWidth",3);
grid on;
注释和非注释部分演示了两种计算方式,并绘图。
这是
q
−
1
v
q
q^{-1}vq
q−1vq:
蓝色为旋转前矢量,红色为旋转后矢量,可以看到这个旋转操作是以z轴为旋转轴逆时针旋转45°。
这是
q
v
q
−
1
qvq^{-1}
qvq−1:
对比得知,旋转方向相反!
欧拉角的劣势
欧拉角通过
θ
ϕ
ψ
\theta \phi \psi
θϕψ确定一个旋转后坐标系,当然,有一个明显缺点就是必须给定旋转顺序,先转
θ
\theta
θ再转
ψ
\psi
ψ和先转
ψ
\psi
ψ再转
θ
\theta
θ是不一样的,一般规定顺序为
ψ
θ
ϕ
\psi \theta \phi
ψθϕ。对应角度如下:
而四元数是可以区分先后顺序的,例如:
v
′
=
q
3
−
1
q
2
−
1
q
1
−
1
v
q
1
q
2
q
3
v'=q_3^{-1}q_2^{-1}q_1^{-1}vq_1q_2q_3
v′=q3−1q2−1q1−1vq1q2q3
顺序是先
q
1
q_1
q1再
q
2
q_2
q2再
q
3
q_3
q3。
MATLAB验证欧拉角和四元数一一对应性
我们定义三个旋转操作,
q
1
q_1
q1为绕z轴45°,
q
2
q_2
q2为绕x轴30°,
q
3
q_3
q3为绕y轴60°。验证利用四元数计算结果和欧拉角旋转矩阵计算结果的一致性。
考虑到欧拉角旋转矩阵与旋转顺序有关,定义顺序为
ψ
θ
ϕ
\psi \theta \phi
ψθϕ
待旋转的向量:
v
=
(
1
,
2
,
3
)
v=(1,2,3)
v=(1,2,3)
%-------------------四元数----------------------------%
psai = pi/4; phi = pi/6; theta = pi/3;
q1 = [cos(psai/2),0,0,sin(psai/2)];
q2 = [cos(theta/2),0,sin(theta/2),0];
q3 = [cos(phi/2),sin(phi/2),0,0];
v1 = [0,1,2,3]; sqrt(sum(v1.^2))
temp1 = quaternionMultiplication(q1,q2);
temp2 = quaternionMultiplication(temp1,q3);
temp3 = quaternionInv(temp2);
temp4 = quaternionMultiplication(temp3,v1);
vRotation1 = quaternionMultiplication(temp4,temp2);
vRotation1 = vRotation1(2:4)
sqrt(sum(vRotation1.^2))
v2 = [1,2,3];
Cbn = [cos(psai)*cos(theta),cos(psai)*sin(theta)*sin(phi)-sin(psai)*cos(phi),...
sin(theta)*cos(phi)*cos(psai)+sin(phi)*sin(psai);...
sin(psai)*cos(theta),cos(phi)*cos(psai)+sin(phi)*sin(theta)*sin(psai),...
sin(theta)*cos(phi)*sin(psai)-sin(phi)*cos(psai);...
-sin(theta),cos(theta)*sin(phi),cos(theta)*cos(phi)
]';
vRotation2 = Cbn * v2'
sqrt(sum(vRotation2.^2))
figure();
plot3([0,vRotation1(1)],[0,vRotation1(2)],[0,vRotation1(3)],"r","LineWidth",3);
hold on;
plot3([0,vRotation2(1)],[0,vRotation2(2)],[0,vRotation2(3)],"g","LineWidth",3);
plot3([0,v2(1)],[0,v2(2)],[0,v2(3)],"b","LineWidth",3);
grid on;
红色和绿色向量重合,蓝色为原始向量,可以看出结果一致。
值得一提的是,这两种运算都有保范性,模不变。