Re: quaternians

New Message Reply Date view Thread view Subject view Author view

Don Hatch (hatch++at++hell)
Mon, 4 Mar 1996 15:23:00 -0800


On Mar 4, 5:50pm, Angus Henderson wrote:
> Subject: quaternians
> I've got a nice quaternian based flight dynamics model - but I want the euler
> angles for my instruments. What can I do about the nasty effects I am getting
> when roll angle tends to zero and my acos gets very inaccurate - I see a lot
> of "noise" on roll angle.
>

If you are using pfMatrix::makeQuat() followed by pfMatrix::getOrthoCoord,
to get the Euler angles, note that the implementation of
pfMatrix::getOrthoCoord() in Performer 2.0 is more unstable than necessary
when pitch is near +-90 degrees,
and it's just plain wrong when pitch is exactly +-90 degrees
(i.e. it gives Euler angles which represent a completely different matrix).

You could try compiling in the corrected version (included below)
which will be in future versions of Performer...
it's also more stable and tolerant of small
fluctuations in the matrix,
and it guarantees that roll=0
in the ambiguous case that pitch is +-90 degrees.

However, I am doubtful that this will improve your situation
except when the pitch is near +-90 degrees (in which case
the roll and heading are still going to be extremely
sensitive to very minor changes in the quaternion
no matter what algorithm is used)...
Even with the existing algorithm, you shouldn't be seeing discontinuities
in the roll except in the case of extreme pitch.
If you are, would you try dumping a trace of the quaternions
and Euler angles and catch it when the roll "jumps" unexpectedly?
That should make it easy to tell whether it's a bug in your program
or in one of the Performer functions.

Thanks,
Don

#include <Performer/pr/pfLinMath.h>
//
// Convert coordinate matrix to heading, pitch, roll.
//
void
pfMatrix::getOrthoCoord(pfCoord *coord)
{
    float sh, ch, sp, cp, sr, cr;

    coord->xyz[0] = mat[3][0];
    coord->xyz[1] = mat[3][1];
    coord->xyz[2] = mat[3][2];

    if (mat[0][2] == 0) // (roll == 0 or 180) or (pitch == +-90)
    {
        if (mat[2][2] >= 0)
        {
            coord->hpr[2] = 0; // cr == 1, sr == 0
            ch = mat[0][0];
            sh = mat[0][1];
            cp = mat[2][2];
        }
        else
        {
            coord->hpr[2] = 180; // cr == -1, sr = 0
            ch = -mat[0][0];
            sh = -mat[0][1];
            cp = -mat[2][2];
        }
    }
    else
    {
        //
        // The following actually works fine
        // in all cases, but special-casing mat[0][2] == 0 above
        // often saves two trig functions and some arithmetic...
        //
        coord->hpr[2] = pfArcTan2(-mat[0][2], mat[2][2]); // returns 0 if both 0
        pfSinCos(coord->hpr[2], &sr, &cr);
        ch = cr*mat[0][0] + sr*mat[2][0];
        sh = cr*mat[0][1] + sr*mat[2][1];
        cp = cr*mat[2][2] - sr*mat[0][2]; // >= 0 so pitch is in [-90..90]
    }
    sp = mat[1][2];
    coord->hpr[0] = pfArcTan2(sh, ch);
    coord->hpr[1] = pfArcTan2(sp, cp);
}

-- 
Don Hatch  hatch++at++sgi.com  (415) 933-5150  Silicon Graphics, Inc.

New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:52:31 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.