]> git.mxchange.org Git - flightgear.git/blob - JSBsim/FGAircraft.cpp
Added initial support for native SGI compilers.
[flightgear.git] / JSBsim / FGAircraft.cpp
1 /*******************************************************************************
2
3  Module:       FGAircraft.cpp
4  Author:       Jon S. Berndt
5  Date started: 12/12/98                                   
6  Purpose:      Encapsulates an aircraft
7  Called by:    FGFDMExec
8
9  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  details.
20
21  You should have received a copy of the GNU General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 Models the aircraft reactions and forces. This class is instantiated by the
31 FGFDMExec class and scheduled as an FDM entry. LoadAircraft() is supplied with a
32 name of a valid, registered aircraft, and the data file is parsed.
33
34 HISTORY
35 --------------------------------------------------------------------------------
36 12/12/98   JSB   Created
37
38 ********************************************************************************
39 COMMENTS, REFERENCES,  and NOTES
40 ********************************************************************************
41 [1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
42       Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420  Naval Postgraduate
43       School, January 1994
44 [2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
45       JSC 12960, July 1977
46 [3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
47       NASA-Ames", NASA CR-2497, January 1975
48 [4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
49       Wiley & Sons, 1979 ISBN 0-471-03032-5
50 [5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
51       1982 ISBN 0-471-08936-2
52
53 The aerodynamic coefficients used in this model are:
54
55 Longitudinal
56   CL0 - Reference lift at zero alpha
57   CD0 - Reference drag at zero alpha
58   CDM - Drag due to Mach
59   CLa - Lift curve slope (w.r.t. alpha)
60   CDa - Drag curve slope (w.r.t. alpha)
61   CLq - Lift due to pitch rate
62   CLM - Lift due to Mach
63   CLadt - Lift due to alpha rate
64
65   Cmadt - Pitching Moment due to alpha rate
66   Cm0 - Reference Pitching moment at zero alpha
67   Cma - Pitching moment slope (w.r.t. alpha)
68   Cmq - Pitch damping (pitch moment due to pitch rate)
69   CmM - Pitch Moment due to Mach
70
71 Lateral
72   Cyb - Side force due to sideslip
73   Cyr - Side force due to yaw rate
74
75   Clb - Dihedral effect (roll moment due to sideslip)
76   Clp - Roll damping (roll moment due to roll rate)
77   Clr - Roll moment due to yaw rate
78   Cnb - Weathercocking stability (yaw moment due to sideslip)
79   Cnp - Rudder adverse yaw (yaw moment due to roll rate)
80   Cnr - Yaw damping (yaw moment due to yaw rate)
81
82 Control
83   CLDe - Lift due to elevator
84   CDDe - Drag due to elevator
85   CyDr - Side force due to rudder
86   CyDa - Side force due to aileron
87
88   CmDe - Pitch moment due to elevator
89   ClDa - Roll moment due to aileron
90   ClDr - Roll moment due to rudder
91   CnDr - Yaw moment due to rudder
92   CnDa - Yaw moment due to aileron
93
94 This class expects to be run in a directory which contains the subdirectory
95 structure shown below (where example aircraft X-15 is shown):
96
97 aircraft/
98          X-15/
99               X-15.dat reset00 reset01 reset02 ...
100               CDRAG/
101                  a0 a M De
102               CSIDE/
103                  b r Dr Da
104               CLIFT/
105                  a0 a M adt De
106               CROLL/
107                  b p r Da Dr
108               CPITCH/
109                  a0 a adt q M De
110               CYAW/
111                  b p r Dr Da
112          F-16/
113               F-16.dat reset00 reset01 ...
114               CDRAG/
115                  a0 a M De
116               ...
117
118 The General Idea
119
120 The file structure is arranged so that various modeled aircraft are stored in
121 their own subdirectory. Each aircraft subdirectory is named after the aircraft.
122 There should be a file present in the specific aircraft subdirectory (e.g.
123 aircraft/X-15) with the same name as the directory with a .dat appended. This
124 file contains mass properties information, name of aircraft, etc. for the
125 aircraft. In that same directory are reset files numbered starting from 0 (two
126 digit numbers), e.g. reset03. Within each reset file are values for important
127 state variables for specific flight conditions (altitude, airspeed, etc.). Also
128 within this directory are the directories containing lookup tables for the
129 stability derivatives for the aircraft.
130
131 ********************************************************************************
132 INCLUDES
133 *******************************************************************************/
134 #include <dirent.h>
135 #include <sys/stat.h>
136 #include <sys/types.h>
137
138 #ifdef FGFS
139 #  include <Include/compiler.h>
140 #  ifdef FG_HAVE_STD_INCLUDES
141 #    include <cmath>
142 #  else
143 #    include <math.h>
144 #  endif
145 #else
146 #  include <cmath>
147 #endif
148
149 #include "FGAircraft.h"
150 #include "FGTranslation.h"
151 #include "FGRotation.h"
152 #include "FGAtmosphere.h"
153 #include "FGState.h"
154 #include "FGFDMExec.h"
155 #include "FGFCS.h"
156 #include "FGPosition.h"
157 #include "FGAuxiliary.h"
158 #include "FGOutput.h"
159
160 /*******************************************************************************
161 ************************************ CODE **************************************
162 *******************************************************************************/
163
164 FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
165 {
166   int i;
167
168   Name = "FGAircraft";
169
170   for (i=0;i<6;i++) coeff_ctr[i] = 0;
171
172   Axis[LiftCoeff]  = "CLIFT";
173   Axis[DragCoeff]  = "CDRAG";
174   Axis[SideCoeff]  = "CSIDE";
175   Axis[RollCoeff]  = "CROLL";
176   Axis[PitchCoeff] = "CPITCH";
177   Axis[YawCoeff]   = "CYAW";
178 }
179
180
181 FGAircraft::~FGAircraft(void)
182 {
183 }
184
185
186 bool FGAircraft::LoadAircraft(string aircraft_path, string engine_path, 
187                               string fname)
188 {
189   string path;
190   string fullpath;
191   string filename;
192   string aircraftDef;
193   string tag;
194   DIR* dir;
195   DIR* coeffdir;
196   struct dirent* dirEntry;
197   struct dirent* coeffdirEntry;
198   struct stat st;
199   struct stat st2;
200   ifstream coeffInFile;
201
202   aircraftDef = aircraft_path + "/" + fname + "/" + fname + ".dat";
203   ifstream aircraftfile(aircraftDef.c_str());
204
205   if (aircraftfile) {
206     aircraftfile >> AircraftName;   // String with no embedded spaces
207     aircraftfile >> WingArea;       // square feet
208     aircraftfile >> WingSpan;       // feet
209     aircraftfile >> cbar;           // feet
210     aircraftfile >> Ixx;            // slug ft^2
211     aircraftfile >> Iyy;            // "
212     aircraftfile >> Izz;            // "
213     aircraftfile >> Ixz;            // "
214     aircraftfile >> EmptyWeight;    // pounds
215     EmptyMass = EmptyWeight / GRAVITY;
216     aircraftfile >> tag;
217
218     numTanks = numEngines = 0;
219     numSelectedOxiTanks = numSelectedFuelTanks = 0;
220
221     while ( !(tag == "EOF") ) {
222       if (tag == "CGLOC") {
223         aircraftfile >> Xcg;        // inches
224         aircraftfile >> Ycg;        // inches
225         aircraftfile >> Zcg;        // inches
226       } else if (tag == "EYEPOINTLOC") {
227         aircraftfile >> Xep;        // inches
228         aircraftfile >> Yep;        // inches
229         aircraftfile >> Zep;        // inches
230       } else if (tag == "TANK") {
231         Tank[numTanks] = new FGTank(aircraftfile);
232         switch(Tank[numTanks]->GetType()) {
233         case FGTank::ttFUEL:
234           numSelectedFuelTanks++;
235           break;
236         case FGTank::ttOXIDIZER:
237           numSelectedOxiTanks++;
238           break;
239         }
240         numTanks++;
241       } else if (tag == "ENGINE") {
242         aircraftfile >> tag;
243         Engine[numEngines] = new FGEngine(FDMExec, engine_path, tag, 
244                                           numEngines);
245         numEngines++;
246       }
247       aircraftfile >> tag;
248     }
249     aircraftfile.close();
250     PutState();
251
252     // Read subdirectory for this aircraft for stability derivative lookup tables:
253     //
254     // Build up the path name to the aircraft file by appending the aircraft
255     // name to the "aircraft/" initial path. Initialize the directory entry
256     // structure dirEntry in preparation for reading through the directory.
257     // Build up a path to each file in the directory sequentially and "stat" it
258     // to see if the entry is a directory or a file. If the entry is a file, then
259     // compare it to each string in the Axis[] array to see which axis the
260     // directory represents: Lift, Drag, Side, Roll, Pitch, Yaw. When the match
261     // is found, go into that directory and search for any coefficient files.
262     // Build a new coefficient by passing the full pathname to the coefficient
263     // file to the FGCoefficient constructor.
264     //
265     // Note: axis_ctr=0 for the Lift "axis", 1 for Drag, 2 for Side force, 3 for
266     //       Roll, 4 for Pitch, and 5 for Yaw. The term coeff_ctr merely keeps
267     //       track of the number of coefficients registered for each of the
268     //       previously mentioned axis.
269
270     path = aircraft_path + "/" + AircraftName + "/";
271     if (dir = opendir(path.c_str())) {
272
273       while (dirEntry = readdir(dir)) {
274         fullpath = path + dirEntry->d_name;
275         stat(fullpath.c_str(),&st);
276         if ((st.st_mode & S_IFMT) == S_IFDIR) {
277           for (int axis_ctr=0; axis_ctr < 6; axis_ctr++) {
278             if (dirEntry->d_name == Axis[axis_ctr]) {
279               if (coeffdir = opendir(fullpath.c_str())) {
280                 while (coeffdirEntry = readdir(coeffdir)) {
281                   if (coeffdirEntry->d_name[0] != '.') {
282                     filename = path + Axis[axis_ctr] + "/" + coeffdirEntry->d_name;
283                     stat(filename.c_str(),&st2);
284                     if (st2.st_size > 6) {
285                       Coeff[axis_ctr][coeff_ctr[axis_ctr]] = new FGCoefficient(FDMExec, filename);
286                       coeff_ctr[axis_ctr]++;
287                     }
288                   }
289                 }
290               }
291             }
292           }
293         }
294       }
295     } else {
296       cerr << "Could not open directory " << path << " for reading" << endl;
297     }
298     return true;
299
300   } else {
301     cerr << "Unable to open aircraft definition file " << fname << endl;
302     return false;
303   }
304
305 }
306
307
308 bool FGAircraft::Run(void)
309 {
310   if (!FGModel::Run()) {                 // if false then execute this Run()
311     GetState();
312
313     for (int i = 0; i < 3; i++)  Forces[i] = Moments[i] = 0.0;
314
315     MassChange();
316
317     FProp(); FAero(); FGear(); FMass();
318     MProp(); MAero(); MGear(); MMass();
319
320     PutState();
321   } else {                               // skip Run() execution this time
322   }
323   return false;
324 }
325
326
327 void FGAircraft::MassChange()
328 {
329   // UPDATE TANK CONTENTS
330   //
331   // For each engine, cycle through the tanks and draw an equal amount of
332   // fuel (or oxidizer) from each active tank. The needed amount of fuel is
333   // determined by the engine in the FGEngine class. If more fuel is needed
334   // than is available in the tank, then that amount is considered a shortage,
335   // and will be drawn from the next tank. If the engine cannot be fed what it
336   // needs, it will be considered to be starved, and will shut down.
337
338   float Oshortage, Fshortage;
339
340   for (int e=0; e<numEngines; e++) {
341     Fshortage = Oshortage = 0.0;
342     for (int t=0; t<numTanks; t++) {
343       switch(Engine[e]->GetType()) {
344       case FGEngine::etRocket:
345
346         switch(Tank[t]->GetType()) {
347         case FGTank::ttFUEL:
348           if (Tank[t]->GetSelected()) {
349             Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
350                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
351           }
352           break;
353         case FGTank::ttOXIDIZER:
354           if (Tank[t]->GetSelected()) {
355             Oshortage = Tank[t]->Reduce((Engine[e]->CalcOxidizerNeed()/
356                                     numSelectedOxiTanks)*(dt*rate) + Oshortage);
357           }
358           break;
359         }
360         break;
361
362       case FGEngine::etPiston:
363       case FGEngine::etTurboJet:
364       case FGEngine::etTurboProp:
365
366         if (Tank[t]->GetSelected()) {
367           Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
368                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
369         }
370         break;
371       }
372     }
373     if ((Fshortage <= 0.0) || (Oshortage <= 0.0)) Engine[e]->SetStarved();
374     else Engine[e]->SetStarved(false);
375   }
376
377   Weight = EmptyWeight;
378   for (int t=0; t<numTanks; t++)
379     Weight += Tank[t]->GetContents();
380
381   Mass = Weight / GRAVITY;
382 }
383
384
385 void FGAircraft::FAero(void)
386 {
387   float F[3];
388
389   F[0] = F[1] = F[2] = 0.0;
390
391   for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++)
392     for (int ctr=0; ctr < coeff_ctr[axis_ctr]; ctr++)
393       F[axis_ctr] += Coeff[axis_ctr][ctr]->Value();
394
395   Forces[0] +=  F[LiftCoeff]*sin(alpha) - F[DragCoeff]*cos(alpha) - F[SideCoeff]*sin(beta);
396   Forces[1] +=  F[SideCoeff]*cos(beta);
397   Forces[2] += -F[LiftCoeff]*cos(alpha) - F[DragCoeff]*sin(alpha);
398 }
399
400
401 void FGAircraft::FGear(void)
402 {
403   if (GearUp) {
404   } else {
405   }
406 }
407
408
409 void FGAircraft::FMass(void)
410 {
411   Forces[0] += -GRAVITY*sin(tht) * Mass;
412   Forces[1] +=  GRAVITY*sin(phi)*cos(tht) * Mass;
413   Forces[2] +=  GRAVITY*cos(phi)*cos(tht) * Mass;
414 }
415
416
417 void FGAircraft::FProp(void)
418 {
419   for (int i=0;i<numEngines;i++) {
420     Forces[0] += Engine[i]->CalcThrust();
421   }
422 }
423
424
425 void FGAircraft::MAero(void)
426 {
427   for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++)
428     for (int ctr = 0; ctr < coeff_ctr[axis_ctr+3]; ctr++)
429       Moments[axis_ctr] += Coeff[axis_ctr+3][ctr]->Value();
430 }
431
432
433 void FGAircraft::MGear(void)
434 {
435   if (GearUp) {
436   } else {
437   }
438 }
439
440
441 void FGAircraft::MMass(void)
442 {
443 }
444
445
446 void FGAircraft::MProp(void)
447 {
448 }
449
450
451 void FGAircraft::GetState(void)
452 {
453   dt = State->Getdt();
454
455   alpha = Translation->Getalpha();
456   beta = Translation->Getbeta();
457   phi = Rotation->Getphi();
458   tht = Rotation->Gettht();
459   psi = Rotation->Getpsi();
460 }
461
462
463 void FGAircraft::PutState(void)
464 {
465 }
466