Search code examples
c++unit-testingquaternionseuler-angles

Unit testing euler-to-quaternion implementation fails


I'm currently trying to implement a quaternion, in which I need euler-to-quaternion conversion. My current implementation looks like this, which I've nicked from here

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;
}

I'm testing the implementation using the following unit test

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


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

Which fails in the following way.

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

The expected value have been acquired from a variety of websites, which yields the same values, but with different signs, similar to how my current output differs from the expected output.

I've also tried several different implementation, yielding the same type of failure.

Is this due to rotations having several representations, in which case the failure of my unit test is actually a false negative? If so, how do I implement a proper unit test?


Solution

  • By simple math it can be deduced that your expection on the results is wrong: z_deg == 180, that is z_rad == PI, will give a zCos value of 0.0: cos of PI/2 is 0.0. Knowing this, you can simplify the computations of W,X,Y,Z, ignoring all products with zCos.

    Since also x/2 and y/2 are in the first quadrant, all values for xCos, xSin, yCos, ySin and zSin are positive. Therefore, the result for X must be negative (0.0 minus some positive product). And, the result for Y must be positive: some positive product plus 0.0.

    This just follows from your code and the arguments given. The conclusion is, that either the expectations are wrong, or you have found a bug in your algorithm. At least (as was to be expected) the actual results are plausible :-)

    So, check your code and the expectations, maybe you have mixed implementation and expectations from different sources? Or, if they came from the same source and you have not made any copying mistakes, the original author made some calculation error...