PAYATHON 2026

为什么 SciPy 的方向余弦矩阵转换会得到共轭四元数?

数据小陈

结论

你使用的向量部公式与 scipy.spatial.transform.Rotation.as_matrix() 的符号约定相反,因此恢复出的四元数表示原旋转的逆旋转。对于单位四元数,这就是它的共轭。

SciPy 的 from_quat 接受标量在末位的 [x, y, z, w]。对于 rotation.as_matrix() 返回的矩阵,若令 w = q_c,从矩阵恢复四元数时,向量部应按以下差值计算:

x = (C_32 - C_23) / (4 * q_c)
y = (C_13 - C_31) / (4 * q_c)
z = (C_21 - C_12) / (4 * q_c)

你当前代码中的三个差值顺序都写反了。

原因

Rotation.as_matrix() 返回表示该旋转的矩阵。在常见的右手系主动旋转约定下,矩阵的反对称部分与四元数向量部的关系是:

C_32 - C_23 = 4 * x * w
C_13 - C_31 = 4 * y * w
C_21 - C_12 = 4 * z * w

你的代码使用了 C_23 - C_32 等差值,相当于将向量部整体取反,得到 [-x, -y, -z, w]。对于单位四元数 [x, y, z, w],其共轭正是 [-x, -y, -z, w],表示原旋转的逆旋转。

修正代码

import numpy as np


def convert_dcm_to_quaternion(dcm):
    C_11, C_12, C_13 = dcm[0, 0], dcm[0, 1], dcm[0, 2]
    C_21, C_22, C_23 = dcm[1, 0], dcm[1, 1], dcm[1, 2]
    C_31, C_32, C_33 = dcm[2, 0], dcm[2, 1], dcm[2, 2]

    q_c = 0.5 * np.sqrt(C_11 + C_22 + C_33 + 1)
    q_vec = np.array([
        C_32 - C_23,
        C_13 - C_31,
        C_21 - C_12,
    ]) / (4 * q_c)

    return np.array([q_vec[0], q_vec[1], q_vec[2], q_c])

这段代码沿用你原来的假设:q_c 不为零。也可以直接用 SciPy 转换:

q = Rotation.from_matrix(dcm).as_quat()

关于不同公式的符号

公式的正负号取决于矩阵和四元数各自采用的约定。如果 DCM 表示相反方向的坐标变换,矩阵可能是主动旋转矩阵的转置,符号关系也会随之改变。比较公式时,要先确认矩阵表示的是向量主动旋转还是坐标系之间的被动变换,并确保变换方向一致。

四元数 q 和 -q 表示同一个旋转。因此,比较结果时,整体符号相反并不代表旋转不同。共轭通常表示逆旋转,只有在特殊情况下才与原旋转相同。当 q_c 接近零时,基于迹的计算也会变得不稳定。此时可以使用 SciPy 的矩阵转换,或采用能处理不同矩阵分量情况的稳健算法。

备注:内容仅供参考。