JSBSim Flight Dynamics Model 1.3.0 (09 Apr 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGQuaternion.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGQuaternion.cpp
4 Author: Jon Berndt, Mathias Froehlich
5 Date started: 12/02/98
6
7 ------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) ------------------
8 ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Further information about the GNU Lesser General Public License can also be found on
25 the world wide web at http://www.gnu.org.
26
27HISTORY
28-------------------------------------------------------------------------------
2912/02/98 JSB Created
3015/01/04 Mathias Froehlich implemented a quaternion class from many places
31 in JSBSim.
32
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34SENTRY
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
36
37/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40
41#include <string>
42#include <iostream>
43#include <sstream>
44#include <iomanip>
45#include <cmath>
46
47#include "FGMatrix33.h"
48#include "FGColumnVector3.h"
49
50#include "FGQuaternion.h"
51
52/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 DEFINITIONS
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55
56namespace JSBSim {
57
58//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59
60// Initialize from q
61FGQuaternion::FGQuaternion(const FGQuaternion& q) : mCacheValid(q.mCacheValid)
62{
63 data[0] = q(1);
64 data[1] = q(2);
65 data[2] = q(3);
66 data[3] = q(4);
67 if (mCacheValid) {
68 mT = q.mT;
69 mTInv = q.mTInv;
70 mEulerAngles = q.mEulerAngles;
71 mEulerSines = q.mEulerSines;
72 mEulerCosines = q.mEulerCosines;
73 }
74}
75
76//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77
78// Initialize with the three euler angles
79FGQuaternion::FGQuaternion(double phi, double tht, double psi): mCacheValid(false)
80{
81 InitializeFromEulerAngles(phi, tht, psi);
82}
83
84//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85
86FGQuaternion::FGQuaternion(FGColumnVector3 vOrient): mCacheValid(false)
87{
88 double phi = vOrient(ePhi);
89 double tht = vOrient(eTht);
90 double psi = vOrient(ePsi);
91
92 InitializeFromEulerAngles(phi, tht, psi);
93}
94
95//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96//
97// This function computes the quaternion that describes the relationship of the
98// body frame with respect to another frame, such as the ECI or ECEF frames. The
99// Euler angles used represent a 3-2-1 (psi, theta, phi) rotation sequence from
100// the reference frame to the body frame. See "Quaternions and Rotation
101// Sequences", Jack B. Kuipers, sections 9.2 and 7.6.
102
103void FGQuaternion::InitializeFromEulerAngles(double phi, double tht, double psi)
104{
105 mEulerAngles(ePhi) = phi;
106 mEulerAngles(eTht) = tht;
107 mEulerAngles(ePsi) = psi;
108
109 double thtd2 = 0.5*tht;
110 double psid2 = 0.5*psi;
111 double phid2 = 0.5*phi;
112
113 double Sthtd2 = sin(thtd2);
114 double Spsid2 = sin(psid2);
115 double Sphid2 = sin(phid2);
116
117 double Cthtd2 = cos(thtd2);
118 double Cpsid2 = cos(psid2);
119 double Cphid2 = cos(phid2);
120
121 double Cphid2Cthtd2 = Cphid2*Cthtd2;
122 double Cphid2Sthtd2 = Cphid2*Sthtd2;
123 double Sphid2Sthtd2 = Sphid2*Sthtd2;
124 double Sphid2Cthtd2 = Sphid2*Cthtd2;
125
126 data[0] = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
127 data[1] = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
128 data[2] = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
129 data[3] = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
130
131 Normalize();
132}
133//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134// Initialize with a direction cosine (rotation) matrix
135
136FGQuaternion::FGQuaternion(const FGMatrix33& m) : mCacheValid(false)
137{
138 data[0] = 0.50*sqrt(1.0 + m(1,1) + m(2,2) + m(3,3));
139 double t = 0.25/data[0];
140 data[1] = t*(m(2,3) - m(3,2));
141 data[2] = t*(m(3,1) - m(1,3));
142 data[3] = t*(m(1,2) - m(2,1));
143
144 Normalize();
145}
146
147//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148
156{
157 return FGQuaternion(
158 -0.5*( data[1]*PQR(eP) + data[2]*PQR(eQ) + data[3]*PQR(eR)),
159 0.5*( data[0]*PQR(eP) - data[3]*PQR(eQ) + data[2]*PQR(eR)),
160 0.5*( data[3]*PQR(eP) + data[0]*PQR(eQ) - data[1]*PQR(eR)),
161 0.5*(-data[2]*PQR(eP) + data[1]*PQR(eQ) + data[0]*PQR(eR))
162 );
163}
164
165//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166
168{
169 // Note: this does not touch the cache since it does not change the orientation
170 double norm = Magnitude();
171 if (norm == 0.0 || fabs(norm - 1.000) < 1e-10) return;
172
173 double rnorm = 1.0/norm;
174
175 data[0] *= rnorm;
176 data[1] *= rnorm;
177 data[2] *= rnorm;
178 data[3] *= rnorm;
179}
180
181//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182
183// Compute the derived values if required ...
184void FGQuaternion::ComputeDerivedUnconditional(void) const
185{
186 mCacheValid = true;
187
188 double q0 = data[0]; // use some aliases/shorthand for the quat elements.
189 double q1 = data[1];
190 double q2 = data[2];
191 double q3 = data[3];
192
193 // Now compute the transformation matrix.
194 double q0q0 = q0*q0;
195 double q1q1 = q1*q1;
196 double q2q2 = q2*q2;
197 double q3q3 = q3*q3;
198 double q0q1 = q0*q1;
199 double q0q2 = q0*q2;
200 double q0q3 = q0*q3;
201 double q1q2 = q1*q2;
202 double q1q3 = q1*q3;
203 double q2q3 = q2*q3;
204
205 mT(1,1) = q0q0 + q1q1 - q2q2 - q3q3; // This is found from Eqn. 1.3-32 in
206 mT(1,2) = 2.0*(q1q2 + q0q3); // Stevens and Lewis
207 mT(1,3) = 2.0*(q1q3 - q0q2);
208 mT(2,1) = 2.0*(q1q2 - q0q3);
209 mT(2,2) = q0q0 - q1q1 + q2q2 - q3q3;
210 mT(2,3) = 2.0*(q2q3 + q0q1);
211 mT(3,1) = 2.0*(q1q3 + q0q2);
212 mT(3,2) = 2.0*(q2q3 - q0q1);
213 mT(3,3) = q0q0 - q1q1 - q2q2 + q3q3;
214
215 // Since this is an orthogonal matrix, the inverse is simply the transpose.
216
217 mTInv = mT;
218 mTInv.T();
219
220 // Compute the Euler-angles
221
222 mEulerAngles = mT.GetEuler();
223
224 // FIXME: may be one can compute those values easier ???
225 mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
226 // mEulerSines(eTht) = sin(mEulerAngles(eTht));
227 mEulerSines(eTht) = -mT(1,3);
228 mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
229 mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
230 mEulerCosines(eTht) = cos(mEulerAngles(eTht));
231 mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
232}
233
234//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235
236std::string FGQuaternion::Dump(const std::string& delimiter) const
237{
238 std::ostringstream buffer;
239 buffer << std::setprecision(16) << data[0] << delimiter;
240 buffer << std::setprecision(16) << data[1] << delimiter;
241 buffer << std::setprecision(16) << data[2] << delimiter;
242 buffer << std::setprecision(16) << data[3];
243 return buffer.str();
244}
245
246//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247
248std::ostream& operator<<(std::ostream& os, const FGQuaternion& q)
249{
250 os << q(1) << " , " << q(2) << " , " << q(3) << " , " << q(4);
251 return os;
252}
253
254} // namespace JSBSim
This class implements a 3 element column vector.
Handles matrix math operations.
Definition FGMatrix33.h:70
void T(void)
Transposes this matrix.
FGColumnVector3 GetEuler() const
Returns the Euler angle column vector associated with this matrix.
Models the Quaternion representation of rotations.
void Normalize(void)
Normalize.
double Magnitude(void) const
Length of the vector.
FGQuaternion GetQDot(const FGColumnVector3 &PQR) const
Quaternion derivative for given angular rates.
FGQuaternion()
Default initializer.
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71
ostream & operator<<(ostream &os, const FGColumnVector3 &col)
Write vector to a stream.