首页 > 解决方案 > 单元测试欧拉到四元数的实现失败

问题描述

我目前正在尝试实现一个四元数,其中我需要欧拉到四元数的转换。我当前的实现看起来像这样,我从这里删减了

void Quaternion::FromEuler(double x, double y, double z)
{
    z *= Math::DegToRad;
    y *= Math::DegToRad;
    x *= Math::DegToRad;

    double xCos = Math::Cos(x / 2);
    double xSin = Math::Sin(x / 2);
    double yCos = Math::Cos(y / 2);
    double ySin = Math::Sin(y / 2);
    double zCos = Math::Cos(z / 2);
    double zSin = Math::Sin(z / 2);

    W = zCos * yCos * xCos + zSin * ySin * xSin;
    X = zCos * yCos * xSin - zSin * ySin * xCos;
    Y = zSin * yCos * xSin + zCos * ySin * xCos;
    Z = zSin * yCos * xCos - zCos * ySin * xSin;
}

我正在使用以下单元测试来测试实现

TEST(Quaternions, FromEuler)
{
    Quaternion quaternion(45, 90, 180);


    ExpectNear(quaternion, 0.6532815, -0.2705981, 0.6532815, 0.270598);
}

以下方式失败。

  Expected | Actual     
X  0.6533   -0.6533
Y -0.2706    0.2706
Z  0.6533    0.6533
W  0.2706    0.2706

预期值是从各种网站获得的,它们产生相同的值,但符号不同,类似于我当前的输出与预期输出的差异。

我还尝试了几种不同的实现,产生了相同类型的失败。

这是由于轮换有几种表示,在这种情况下,我的单元测试失败实际上是假阴性吗?如果是这样,我该如何实施适当的单元测试?

标签: c++unit-testingquaternionseuler-angles

解决方案


通过简单的数学可以推断出您对结果的期望是错误的:z_deg == 180,即 z_rad == PI,将给出zCos0.0 的值:PI/2 的 cos 为 0.0。知道了这一点,您可以简化, , ,的计算W,忽略所有带有 的产品。XYZzCos

由于 x/2 和 y/2 也位于第一象限,所有xCosxSinyCosySin的值zSin都是正的。因此, 的结果X必须是负数(0.0 减去一些正数)。而且,结果Y必须是正数:一些正数乘积加上 0.0。

这仅来自您的代码和给定的参数。结论是,要么期望是错误的,要么您在算法中发现了错误。至少(正如预期的那样)实际结果是合理的:-)

所以,检查你的代码和期望,也许你有来自不同来源的混合实现和期望?或者,如果它们来自同一来源并且您没有犯任何复制错误,则原作者计算错误......


推荐阅读