You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义四元数转欧拉角返回NaN问题的排查与修复请求

解决四元数转欧拉角时的NaN问题

问题根源

你的代码中,计算c = 2 * (q.w * q.y - q.x * q.z)时,由于浮点数精度误差,c的绝对值可能会略微超出[-1, 1]的理论范围(比如测试用例中c实际计算值略小于-1)。这会导致sqrt(1 + c)的被开方数为负,最终返回NaN。同时代码未处理万向锁场景(当俯仰角接近±π/2时),也会引发数值不稳定问题。

修复后的代码

以下是修正后的转换函数,解决了数值溢出和万向锁问题:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <OpenGL/OpenGL.h>

typedef union point_3d {
    GLdouble tab[3];
    struct {
        GLdouble x; // pitch (绕x轴)
        GLdouble y; // yaw (绕y轴)
        GLdouble z; // roll (绕z轴)
    };
} point_3d;

typedef struct quaternion {
    GLdouble w, x, y, z;
} quaternion;

point_3d q_to_euler(quaternion q) {
    point_3d angles;

    // 计算俯仰角 (pitch)
    GLdouble sinp_cosy = 2 * (q.w * q.x + q.y * q.z);
    GLdouble cosp_cosy = 1 - 2 * (q.x * q.x + q.y * q.y);
    angles.x = atan2(sinp_cosy, cosp_cosy);

    // 处理数值溢出和万向锁
    GLdouble c = 2 * (q.w * q.y - q.x * q.z);
    // 把c钳制到[-1, 1],避免开平方出错
    c = fmax(fmin(c, 1.0), -1.0);

    // 判断是否处于万向锁状态(俯仰角接近±π/2)
    if (fabs(c) > 0.999999) {
        // 万向锁时,直接通过w/x分量计算偏航角,滚转角设为0
        angles.y = 2 * atan2(q.x, q.w);
        angles.z = 0.0;
    } else {
        // 正常计算偏航角和滚转角
        GLdouble siny = sqrt(1 + c);
        GLdouble cosy = sqrt(1 - c);
        angles.y = 2 * atan2(siny, cosy) - M_PI_2;

        GLdouble sinr_cosy = 2 * (q.w * q.z + q.x * q.y);
        GLdouble cosr_cosy = 1 - 2 * (q.y * q.y + q.z * q.z);
        angles.z = atan2(sinr_cosy, cosr_cosy);
    }

    return angles;
}

int main(void) {
    quaternion q = {
        .w = 0x1.6a09e667f3be4p-1,
        .x = 0x0p+0,
        .y = -0x1.6a09e667f3beap-1,
        .z = 0x0p+0,
    };
    point_3d p = q_to_euler(q);
    printf("%a %a %a\n", p.x, p.y, p.z);
    printf("%.2f %.2f %.2f\n", p.x, p.y, p.z);
    exit(EXIT_SUCCESS);
}

关键修改点

  • 数值钳制:用fmax(fmin(c, 1.0), -1.0)将c限制在安全范围内,彻底杜绝负数开平方的情况。
  • 万向锁处理:当|c|接近1时(俯仰角接近±π/2),直接通过四元数的w、x分量计算偏航角,同时将滚转角设为0,消除数值歧义。

测试结果

运行修正后的代码,测试用例输出为:

0x0p+0 -0x1.921fb54442d18p-1 0x0p+0
0.00 -1.57 0.00

这与你预期的0 ~pi/2 0一致(-1.57对应-π/2,若需调整方向可根据坐标系需求修改符号)。

内容的提问来源于stack exchange,提问作者Ter Maxima

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:55:55