59
static const char *IdSrc = "$Id$";
60
static const char *IdSrc = "$Id: FGQuaternion.cpp,v 1.19 2010/12/07 12:57:14 jberndt Exp $";
60
61
static const char *IdHdr = ID_QUATERNION;
62
63
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
65
// Initialize from q
65
FGQuaternion::FGQuaternion(const FGQuaternion& q)
66
: mCacheValid(q.mCacheValid) {
66
FGQuaternion::FGQuaternion(const FGQuaternion& q) : mCacheValid(q.mCacheValid)
80
81
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82
83
// Initialize with the three euler angles
83
FGQuaternion::FGQuaternion(double phi, double tht, double psi)
84
: mCacheValid(false) {
84
FGQuaternion::FGQuaternion(double phi, double tht, double psi): mCacheValid(false)
86
InitializeFromEulerAngles(phi, tht, psi);
89
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91
FGQuaternion::FGQuaternion(FGColumnVector3 vOrient): mCacheValid(false)
93
double phi = vOrient(ePhi);
94
double tht = vOrient(eTht);
95
double psi = vOrient(ePsi);
97
InitializeFromEulerAngles(phi, tht, psi);
100
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102
// This function computes the quaternion that describes the relationship of the
103
// body frame with respect to another frame, such as the ECI or ECEF frames. The
104
// Euler angles used represent a 3-2-1 (psi, theta, phi) rotation sequence from
105
// the reference frame to the body frame. See "Quaternions and Rotation
106
// Sequences", Jack B. Kuipers, sections 9.2 and 7.6.
108
void FGQuaternion::InitializeFromEulerAngles(double phi, double tht, double psi)
110
mEulerAngles(ePhi) = phi;
111
mEulerAngles(eTht) = tht;
112
mEulerAngles(ePsi) = psi;
85
114
double thtd2 = 0.5*tht;
86
115
double psid2 = 0.5*psi;
87
116
double phid2 = 0.5*phi;
99
128
double Sphid2Sthtd2 = Sphid2*Sthtd2;
100
129
double Sphid2Cthtd2 = Sphid2*Cthtd2;
102
Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
103
Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
104
Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
105
Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
131
data[0] = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
132
data[1] = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
133
data[2] = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
134
data[3] = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
138
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139
// Initialize with a direction cosine (rotation) matrix
141
FGQuaternion::FGQuaternion(const FGMatrix33& m) : mCacheValid(false)
143
data[0] = 0.50*sqrt(1.0 + m(1,1) + m(2,2) + m(3,3));
144
double t = 0.25/data[0];
145
data[1] = t*(m(2,3) - m(3,2));
146
data[2] = t*(m(3,1) - m(1,3));
147
data[3] = t*(m(1,2) - m(2,1));
108
152
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
155
angular velocities PQR.
112
156
See Stevens and Lewis, "Aircraft Control and Simulation", Second Edition,
158
Also see Jack Kuipers, "Quaternions and Rotation Sequences", Equation 11.12.
115
FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
116
double norm = Magnitude();
118
return FGQuaternion::zero();
119
double rnorm = 1.0/norm;
122
QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
123
QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
124
QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
125
QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
160
FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR)
163
-0.5*( data[1]*PQR(eP) + data[2]*PQR(eQ) + data[3]*PQR(eR)),
164
0.5*( data[0]*PQR(eP) - data[3]*PQR(eQ) + data[2]*PQR(eR)),
165
0.5*( data[3]*PQR(eP) + data[0]*PQR(eQ) - data[1]*PQR(eR)),
166
0.5*(-data[2]*PQR(eP) + data[1]*PQR(eQ) + data[0]*PQR(eR))
129
170
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131
172
void FGQuaternion::Normalize()
133
// Note: this does not touch the cache
134
// since it does not change the orientation ...
174
// Note: this does not touch the cache since it does not change the orientation
136
175
double norm = Magnitude();
176
if (norm == 0.0 || fabs(norm - 1.000) < 1e-10) return;
140
178
double rnorm = 1.0/norm;
147
186
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150
189
void FGQuaternion::ComputeDerivedUnconditional(void) const
152
191
mCacheValid = true;
154
// First normalize the 4-vector
155
double norm = Magnitude();
159
double rnorm = 1.0/norm;
160
double q1 = rnorm*Entry(1);
161
double q2 = rnorm*Entry(2);
162
double q3 = rnorm*Entry(3);
163
double q4 = rnorm*Entry(4);
193
double q0 = data[0]; // use some aliases/shorthand for the quat elements.
165
198
// Now compute the transformation matrix.
166
200
double q1q1 = q1*q1;
167
201
double q2q2 = q2*q2;
168
202
double q3q3 = q3*q3;
170
206
double q1q2 = q1*q2;
171
207
double q1q3 = q1*q3;
173
208
double q2q3 = q2*q3;
177
mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
178
mT(1,2) = 2.0*(q2q3 + q1q4);
179
mT(1,3) = 2.0*(q2q4 - q1q3);
180
mT(2,1) = 2.0*(q2q3 - q1q4);
181
mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
182
mT(2,3) = 2.0*(q3q4 + q1q2);
183
mT(3,1) = 2.0*(q2q4 + q1q3);
184
mT(3,2) = 2.0*(q3q4 - q1q2);
185
mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
186
// Since this is an orthogonal matrix, the inverse is simply
210
mT(1,1) = q0q0 + q1q1 - q2q2 - q3q3; // This is found from Eqn. 1.3-32 in
211
mT(1,2) = 2.0*(q1q2 + q0q3); // Stevens and Lewis
212
mT(1,3) = 2.0*(q1q3 - q0q2);
213
mT(2,1) = 2.0*(q1q2 - q0q3);
214
mT(2,2) = q0q0 - q1q1 + q2q2 - q3q3;
215
mT(2,3) = 2.0*(q2q3 + q0q1);
216
mT(3,1) = 2.0*(q1q3 + q0q2);
217
mT(3,2) = 2.0*(q2q3 - q0q1);
218
mT(3,3) = q0q0 - q1q1 - q2q2 + q3q3;
220
// Since this is an orthogonal matrix, the inverse is simply the transpose.
191
225
// Compute the Euler-angles
226
// Also see Jack Kuipers, "Quaternions and Rotation Sequences", section 7.8..
192
228
if (mT(3,3) == 0.0)
193
229
mEulerAngles(ePhi) = 0.5*M_PI;
220
256
mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
259
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261
std::ostream& operator<<(std::ostream& os, const FGQuaternion& q)
263
os << q(1) << " , " << q(2) << " , " << q(3) << " , " << q(4);
223
267
} // namespace JSBSim