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
FGAccelerations.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGAccelerations.cpp
4 Author: Jon S. Berndt
5 Date started: 07/12/11
6 Purpose: Calculates derivatives of rotational and translational rates, and
7 of the attitude quaternion.
8 Called by: FGFDMExec
9
10 ------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
11
12 This program is free software; you can redistribute it and/or modify it under
13 the terms of the GNU Lesser General Public License as published by the Free
14 Software Foundation; either version 2 of the License, or (at your option) any
15 later version.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 details.
21
22 You should have received a copy of the GNU Lesser General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc., 59
24 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 Further information about the GNU Lesser General Public License can also be
27 found on the world wide web at http://www.gnu.org.
28
29FUNCTIONAL DESCRIPTION
30--------------------------------------------------------------------------------
31This class encapsulates the calculation of the derivatives of the state vectors
32UVW and PQR - the translational and rotational rates relative to the planet
33fixed frame. The derivatives relative to the inertial frame are also calculated
34as a side effect. Also, the derivative of the attitude quaterion is also
35calculated.
36
37HISTORY
38--------------------------------------------------------------------------------
3907/12/11 JSB Created
40
41%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42COMMENTS, REFERENCES, and NOTES
43%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44[1] Stevens and Lewis, "Aircraft Control and Simulation", Second edition (2004)
45 Wiley
46[2] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
47 NASA-Ames", NASA CR-2497, January 1975
48[3] Erin Catto, "Iterative Dynamics with Temporal Coherence", February 22, 2005
49[4] Mark Harris and Robert Lyle, "Spacecraft Gravitational Torques",
50 NASA SP-8024, May 1969
51
52%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53INCLUDES
54%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55
56#include "FGAccelerations.h"
57#include "FGFDMExec.h"
58#include "input_output/FGLog.h"
59
60using namespace std;
61
62namespace JSBSim {
63
64/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65CLASS IMPLEMENTATION
66%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
67
69 : FGModel(fdmex)
70{
71 Debug(0);
72 Name = "FGAccelerations";
73 gravTorque = false;
74
75 vPQRidot.InitMatrix();
76 vUVWidot.InitMatrix();
77 vUVWdot.InitMatrix();
78 vBodyAccel.InitMatrix();
79
80 bind();
81 Debug(0);
82}
83
84//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85
87{
88 Debug(1);
89}
90
91//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92
94{
95 if (!FGModel::InitModel()) return false;
96
97 vPQRidot.InitMatrix();
98 vUVWidot.InitMatrix();
99 vUVWdot.InitMatrix();
100 vBodyAccel.InitMatrix();
101
102 return true;
103}
104
105//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106/*
107Purpose: Called on a schedule to calculate derivatives.
108*/
109
110bool FGAccelerations::Run(bool Holding)
111{
112 if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
113 if (Holding) return false;
114
115 CalculatePQRdot(); // Angular rate derivative
116 CalculateUVWdot(); // Translational rate derivative
117
118 if (!FDMExec->GetHoldDown())
119 CalculateFrictionForces(in.DeltaT * rate); // Update rate derivatives with friction forces
120
121 Debug(2);
122 return false;
123}
124
125//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126// Compute body frame rotational accelerations based on the current body moments
127//
128// vPQRdot is the derivative of the absolute angular velocity of the vehicle
129// (body rate with respect to the ECEF frame), expressed in the body frame,
130// where the derivative is taken in the body frame.
131// J is the inertia matrix
132// Jinv is the inverse inertia matrix
133// vMoments is the moment vector in the body frame
134// in.vPQRi is the total inertial angular velocity of the vehicle
135// expressed in the body frame.
136// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
137// Second edition (2004), eqn 1.5-16e (page 50)
138
139void FGAccelerations::CalculatePQRdot(void)
140{
141 if (gravTorque) {
142 // Compute the gravitational torque
143 // Reference: See Harris and Lyle "Spacecraft Gravitational Torques",
144 // NASA SP-8024 (1969) eqn (2) (page 7)
146 double invRadius = 1.0 / R.Magnitude();
147 R *= invRadius;
148 in.Moment += (3.0 * in.vGravAccel.Magnitude() * invRadius) * (R * (in.J * R));
149 }
150
151 // Compute body frame rotational accelerations based on the current body
152 // moments and the total inertial angular velocity expressed in the body
153 // frame.
154// if (HoldDown && !FDMExec->GetTrimStatus()) {
155 if (FDMExec->GetHoldDown()) {
156 // The rotational acceleration in ECI is calculated so that the rotational
157 // acceleration is zero in the body frame.
158 vPQRdot.InitMatrix();
159 vPQRidot = vPQRdot - in.vPQRi * (in.Ti2b * in.vOmegaPlanet);
160 }
161 else {
162 vPQRidot = in.Jinv * (in.Moment - in.vPQRi * (in.J * in.vPQRi));
163 vPQRdot = vPQRidot + in.vPQRi * (in.Ti2b * in.vOmegaPlanet);
164 }
165}
166
167//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168// This set of calculations results in the body and inertial frame accelerations
169// being computed.
170// Compute body and inertial frames accelerations based on the current body
171// forces including centripetal and Coriolis accelerations for the former.
172// in.vOmegaPlanet is the Earth angular rate - expressed in the inertial frame -
173// so it has to be transformed to the body frame. More completely,
174// in.vOmegaPlanet is the rate of the ECEF frame relative to the Inertial
175// frame (ECI), expressed in the Inertial frame.
176// in.Force is the total force on the vehicle in the body frame.
177// in.vPQR is the vehicle body rate relative to the ECEF frame, expressed
178// in the body frame.
179// in.vUVW is the vehicle velocity relative to the ECEF frame, expressed
180// in the body frame.
181// Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
182// Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
183
184void FGAccelerations::CalculateUVWdot(void)
185{
186 if (FDMExec->GetHoldDown() && !FDMExec->GetTrimStatus())
187 vBodyAccel.InitMatrix();
188 else
189 vBodyAccel = in.Force / in.Mass;
190
191 vUVWdot = vBodyAccel - (in.vPQR + 2.0 * (in.Ti2b * in.vOmegaPlanet)) * in.vUVW;
192
193 // Include Centripetal acceleration.
194 vUVWdot -= in.Ti2b * (in.vOmegaPlanet * (in.vOmegaPlanet * in.vInertialPosition));
195
196 if (FDMExec->GetHoldDown()) {
197 // The acceleration in ECI is calculated so that the acceleration is zero
198 // in the body frame.
199 vUVWidot = in.vOmegaPlanet * (in.vOmegaPlanet * in.vInertialPosition);
200 vUVWdot.InitMatrix();
201 }
202 else {
203 vUVWdot += in.Tec2b * in.vGravAccel;
204 vUVWidot = in.Tb2i * vBodyAccel + in.Tec2i * in.vGravAccel;
205 }
206}
207
208//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209
211{
212 if (hd) {
213 vUVWidot = in.vOmegaPlanet * (in.vOmegaPlanet * in.vInertialPosition);
214 vUVWdot.InitMatrix();
215 vPQRdot.InitMatrix();
216 vPQRidot = vPQRdot - in.vPQRi * (in.Ti2b * in.vOmegaPlanet);
217 }
218}
219
220//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221// Computes the contact forces just before integrating the EOM.
222// This routine is using Lagrange multipliers and the projected Gauss-Seidel
223// (PGS) method.
224// Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence",
225// February 22, 2005
226// In JSBSim there is only one rigid body (the aircraft) and there can be
227// multiple points of contact between the aircraft and the ground. As a
228// consequence our matrix Jac*M^-1*Jac^T is not sparse and the algorithm
229// described in Catto's paper has been adapted accordingly.
230// The friction forces are resolved in the body frame relative to the origin
231// (Earth center).
232
233void FGAccelerations::CalculateFrictionForces(double dt)
234{
235 vector<LagrangeMultiplier*>& multipliers = *in.MultipliersList;
236 size_t n = multipliers.size();
237
238 vFrictionForces.InitMatrix();
239 vFrictionMoments.InitMatrix();
240
241 // If no gears are in contact with the ground then return
242 if (!n) return;
243
244 vector<double> a(n*n); // Will contain Jac*M^-1*Jac^T
245 vector<double> rhs(n);
246
247 // Assemble the linear system of equations
248 for (unsigned int i=0; i < n; i++) {
249 FGColumnVector3 U = multipliers[i]->ForceJacobian;
250 FGColumnVector3 r = multipliers[i]->LeverArm;
251 FGColumnVector3 v1 = U / in.Mass;
252 FGColumnVector3 v2 = in.Jinv * (r*U); // Should be J^-T but J is symmetric and so is J^-1
253
254 for (unsigned int j=0; j < i; j++)
255 a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of Jac^T*M^-1*Jac
256
257 for (unsigned int j=i; j < n; j++) {
258 U = multipliers[j]->ForceJacobian;
259 r = multipliers[j]->LeverArm;
260 a[i*n+j] = DotProduct(U, v1 + v2*r);
261 }
262 }
263
264 // Assemble the RHS member
265
266 // Translation
267 FGColumnVector3 vdot = vUVWdot;
268 if (dt > 0.) // Zeroes out the relative movement between the aircraft and the ground
269 vdot += (in.vUVW - in.Tec2b * in.TerrainVelocity) / dt;
270
271 // Rotation
272 FGColumnVector3 wdot = vPQRdot;
273 if (dt > 0.) // Zeroes out the relative movement between the aircraft and the ground
274 wdot += (in.vPQR - in.Tec2b * in.TerrainAngularVel) / dt;
275
276 // Prepare the linear system for the Gauss-Seidel algorithm :
277 // 1. Compute the right hand side member 'rhs'
278 // 2. Divide every line of 'a' and 'rhs' by a[i,i]. This is in order to save
279 // a division computation at each iteration of Gauss-Seidel.
280 for (unsigned int i=0; i < n; i++) {
281 double d = a[i*n+i];
282 FGColumnVector3 U = multipliers[i]->ForceJacobian;
283 FGColumnVector3 r = multipliers[i]->LeverArm;
284
285 rhs[i] = -DotProduct(U, vdot + wdot*r)/d;
286
287 for (unsigned int j=0; j < n; j++)
288 a[i*n+j] /= d;
289 }
290
291 // Resolve the Lagrange multipliers with the projected Gauss-Seidel method
292 for (int iter=0; iter < 50; iter++) {
293 double norm = 0.;
294
295 for (unsigned int i=0; i < n; i++) {
296 double lambda0 = multipliers[i]->value;
297 double dlambda = rhs[i];
298
299 for (unsigned int j=0; j < n; j++)
300 dlambda -= a[i*n+j]*multipliers[j]->value;
301
302 multipliers[i]->value = Constrain(multipliers[i]->Min, lambda0+dlambda, multipliers[i]->Max);
303 dlambda = multipliers[i]->value - lambda0;
304
305 norm += fabs(dlambda);
306 }
307
308 if (norm < 1E-5) break;
309 }
310
311 // Calculate the total friction forces and moments
312
313 for (unsigned int i=0; i< n; i++) {
314 double lambda = multipliers[i]->value;
315 FGColumnVector3 U = multipliers[i]->ForceJacobian;
316 FGColumnVector3 r = multipliers[i]->LeverArm;
317
318 FGColumnVector3 F = lambda * U;
319 vFrictionForces += F;
320 vFrictionMoments += r * F;
321 }
322
323 FGColumnVector3 accel = vFrictionForces / in.Mass;
324 FGColumnVector3 omegadot = in.Jinv * vFrictionMoments;
325
326 vBodyAccel += accel;
327 vUVWdot += accel;
328 vUVWidot += in.Tb2i * accel;
329 vPQRdot += omegadot;
330 vPQRidot += omegadot;
331}
332
333//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334
336{
337 // Make an initial run and set past values
338 CalculatePQRdot(); // Angular rate derivative
339 CalculateUVWdot(); // Translational rate derivative
340 CalculateFrictionForces(0.); // Update rate derivatives with friction forces
341}
342
343//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
345void FGAccelerations::bind(void)
346{
347 PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, &FGAccelerations::GetPQRdot);
348 PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, &FGAccelerations::GetPQRdot);
349 PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, &FGAccelerations::GetPQRdot);
350
351 PropertyManager->Tie("accelerations/pidot-rad_sec2", this, eP, &FGAccelerations::GetPQRidot);
352 PropertyManager->Tie("accelerations/qidot-rad_sec2", this, eQ, &FGAccelerations::GetPQRidot);
353 PropertyManager->Tie("accelerations/ridot-rad_sec2", this, eR, &FGAccelerations::GetPQRidot);
354
355 PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, &FGAccelerations::GetUVWdot);
356 PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, &FGAccelerations::GetUVWdot);
357 PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, &FGAccelerations::GetUVWdot);
358
359 PropertyManager->Tie("accelerations/uidot-ft_sec2", this, eU, &FGAccelerations::GetUVWidot);
360 PropertyManager->Tie("accelerations/vidot-ft_sec2", this, eV, &FGAccelerations::GetUVWidot);
361 PropertyManager->Tie("accelerations/widot-ft_sec2", this, eW, &FGAccelerations::GetUVWidot);
362
363 PropertyManager->Tie("accelerations/gravity-ft_sec2", this, &FGAccelerations::GetGravAccelMagnitude);
364 PropertyManager->Tie("simulation/gravitational-torque", &gravTorque);
365 PropertyManager->Tie("forces/fbx-weight-lbs", this, eX, &FGAccelerations::GetWeight);
366 PropertyManager->Tie("forces/fby-weight-lbs", this, eY, &FGAccelerations::GetWeight);
367 PropertyManager->Tie("forces/fbz-weight-lbs", this, eZ, &FGAccelerations::GetWeight);
368
369 PropertyManager->Tie("forces/fbx-total-lbs", this, eX, &FGAccelerations::GetForces);
370 PropertyManager->Tie("forces/fby-total-lbs", this, eY, &FGAccelerations::GetForces);
371 PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, &FGAccelerations::GetForces);
372 PropertyManager->Tie("moments/l-total-lbsft", this, eL, &FGAccelerations::GetMoments);
373 PropertyManager->Tie("moments/m-total-lbsft", this, eM, &FGAccelerations::GetMoments);
374 PropertyManager->Tie("moments/n-total-lbsft", this, eN, &FGAccelerations::GetMoments);
375
376 PropertyManager->Tie("moments/l-gear-lbsft", this, eL, &FGAccelerations::GetGroundMoments);
377 PropertyManager->Tie("moments/m-gear-lbsft", this, eM, &FGAccelerations::GetGroundMoments);
378 PropertyManager->Tie("moments/n-gear-lbsft", this, eN, &FGAccelerations::GetGroundMoments);
379 PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, &FGAccelerations::GetGroundForces);
380 PropertyManager->Tie("forces/fby-gear-lbs", this, eY, &FGAccelerations::GetGroundForces);
381 PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, &FGAccelerations::GetGroundForces);
382}
383
384//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385// The bitmasked value choices are as follows:
386// unset: In this case (the default) JSBSim would only print
387// out the normally expected messages, essentially echoing
388// the config files as they are read. If the environment
389// variable is not set, debug_lvl is set to 1 internally
390// 0: This requests JSBSim not to output any messages
391// whatsoever.
392// 1: This value explicity requests the normal JSBSim
393// startup messages
394// 2: This value asks for a message to be printed out when
395// a class is instantiated
396// 4: When this value is set, a message is displayed when a
397// FGModel object executes its Run() method
398// 8: When this value is set, various runtime state variables
399// are printed out periodically
400// 16: When set various parameters are sanity checked and
401// a message is printed out when they go out of bounds
402
403void FGAccelerations::Debug(int from)
404{
405 if (debug_lvl <= 0) return;
406
407 if (debug_lvl & 1) { // Standard console startup message output
408 if (from == 0) { // Constructor
409
410 }
411 }
412 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
413 FGLogging log(LogLevel::DEBUG);
414 if (from == 0) log << "Instantiated: FGAccelerations\n";
415 if (from == 1) log << "Destroyed: FGAccelerations\n";
416 }
417 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
418 }
419 if (debug_lvl & 8 && from == 2) { // Runtime state variables
420 }
421 if (debug_lvl & 16) { // Sanity checking
422 }
423 if (debug_lvl & 64) {
424 if (from == 0) { // Constructor
425 }
426 }
427}
428}
void InitializeDerivatives(void)
Initializes the FGAccelerations class prior to a new execution.
const FGColumnVector3 & GetUVWidot(void) const
Retrieves the body axis acceleration in the ECI frame.
const FGColumnVector3 & GetUVWdot(void) const
Retrieves the body axis acceleration.
FGAccelerations(FGFDMExec *Executive)
Constructor.
bool Run(bool Holding) override
Runs the state propagation model; called by the Executive Can pass in a value indicating if the execu...
bool InitModel(void) override
Initializes the FGAccelerations class after instantiation and prior to first execution.
const FGColumnVector3 & GetPQRdot(void) const
Retrieves the body axis angular acceleration vector.
const FGColumnVector3 & GetPQRidot(void) const
Retrieves the axis angular acceleration vector in the ECI frame.
void SetHoldDown(bool hd)
Sets the property forces/hold-down.
This class implements a 3 element column vector.
double Magnitude(void) const
Length of the vector.
Encapsulates the JSBSim simulation executive.
Definition FGFDMExec.h:185
bool GetHoldDown(void) const
Gets the value of the property forces/hold-down.
Definition FGFDMExec.h:617
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
Definition FGJSBBase.h:289
Base class for all scheduled JSBSim models.
Definition FGModel.h:70
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
Definition FGModel.cpp:90
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71
double DotProduct(const FGColumnVector3 &v1, const FGColumnVector3 &v2)
Dot product of two vectors Compute and return the euclidean dot (or scalar) product of two vectors v1...
FGColumnVector3 TerrainVelocity
Terrain velocities with respect to the local frame (expressed in the ECEF frame).
FGColumnVector3 vUVW
Velocities of the body with respect to the local frame (expressed in the body frame).
FGMatrix33 Tb2i
Transformation matrix from the Body to the ECI frame.
FGMatrix33 J
The body inertia matrix expressed in the body frame.
FGColumnVector3 vPQRi
Angular velocities of the body with respect to the ECI frame (expressed in the body frame).
FGColumnVector3 Moment
Total moments applied to the body except friction and gravity (expressed in the body frame)
FGMatrix33 Jinv
The inverse of the inertia matrix J.
FGColumnVector3 vOmegaPlanet
Earth rotating vector (expressed in the ECI frame).
FGColumnVector3 vInertialPosition
Body position (X,Y,Z) measured in the ECI frame.
FGColumnVector3 vPQR
Angular velocities of the body with respect to the local frame (expressed in the body frame).
FGColumnVector3 vGravAccel
Gravity intensity vector (expressed in the ECEF frame).
FGMatrix33 Tec2i
Transformation matrix from the ECEF to the ECI frame.
std::vector< LagrangeMultiplier * > * MultipliersList
List of Lagrange multipliers set by FGLGear for friction forces calculations.
FGMatrix33 Tec2b
Transformation matrix from the ECEF to the Body frame.
FGColumnVector3 TerrainAngularVel
Terrain angular velocities with respect to the local frame (expressed in the ECEF frame).
FGColumnVector3 Force
Total forces applied to the body except friction and gravity (expressed in the body frame)
FGMatrix33 Ti2b
Transformation matrix from the ECI to the Body frame.