]> git.mxchange.org Git - flightgear.git/blob - JSBsim/FGAircraft.cpp
Latest changes from Jon, plus ...
[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, string fname)
187 {
188   string path;
189   string fullpath;
190   string filename;
191   string aircraftDef;
192   string tag;
193   DIR* dir;
194   DIR* coeffdir;
195   struct dirent* dirEntry;
196   struct dirent* coeffdirEntry;
197   struct stat st;
198   struct stat st2;
199   ifstream coeffInFile;
200
201   aircraftDef = aircraft_path + "/" + fname + "/" + fname + ".dat";
202   ifstream aircraftfile(aircraftDef.c_str());
203
204   if (aircraftfile) {
205     aircraftfile >> AircraftName;   // String with no embedded spaces
206     aircraftfile >> WingArea;       // square feet
207     aircraftfile >> WingSpan;       // feet
208     aircraftfile >> cbar;           // feet
209     aircraftfile >> Ixx;            // slug ft^2
210     aircraftfile >> Iyy;            // "
211     aircraftfile >> Izz;            // "
212     aircraftfile >> Ixz;            // "
213     aircraftfile >> EmptyWeight;    // pounds
214     EmptyMass = EmptyWeight / GRAVITY;
215     aircraftfile >> tag;
216
217     numTanks = numEngines = 0;
218     numSelectedOxiTanks = numSelectedFuelTanks = 0;
219
220     while ( !(tag == "EOF") ) {
221       if (tag == "CGLOC") {
222         aircraftfile >> Xcg;        // inches
223         aircraftfile >> Ycg;        // inches
224         aircraftfile >> Zcg;        // inches
225       } else if (tag == "EYEPOINTLOC") {
226         aircraftfile >> Xep;        // inches
227         aircraftfile >> Yep;        // inches
228         aircraftfile >> Zep;        // inches
229       } else if (tag == "TANK") {
230         Tank[numTanks] = new FGTank(aircraftfile);
231         switch(Tank[numTanks]->GetType()) {
232         case FGTank::ttFUEL:
233           numSelectedFuelTanks++;
234           break;
235         case FGTank::ttOXIDIZER:
236           numSelectedOxiTanks++;
237           break;
238         }
239         numTanks++;
240       } else if (tag == "ENGINE") {
241         aircraftfile >> tag;
242         Engine[numEngines] = new FGEngine(FDMExec, engine_path, tag, numEngines);
243         numEngines++;
244       }
245       aircraftfile >> tag;
246     }
247     aircraftfile.close();
248     PutState();
249
250     // Read subdirectory for this aircraft for stability derivative lookup tables:
251     //
252     // Build up the path name to the aircraft file by appending the aircraft
253     // name to the "aircraft/" initial path. Initialize the directory entry
254     // structure dirEntry in preparation for reading through the directory.
255     // Build up a path to each file in the directory sequentially and "stat" it
256     // to see if the entry is a directory or a file. If the entry is a file, then
257     // compare it to each string in the Axis[] array to see which axis the
258     // directory represents: Lift, Drag, Side, Roll, Pitch, Yaw. When the match
259     // is found, go into that directory and search for any coefficient files.
260     // Build a new coefficient by passing the full pathname to the coefficient
261     // file to the FGCoefficient constructor.
262     //
263     // Note: axis_ctr=0 for the Lift "axis", 1 for Drag, 2 for Side force, 3 for
264     //       Roll, 4 for Pitch, and 5 for Yaw. The term coeff_ctr merely keeps
265     //       track of the number of coefficients registered for each of the
266     //       previously mentioned axis.
267
268     path = aircraft_path + "/" + AircraftName + "/";
269     if (dir = opendir(path.c_str())) {
270
271       while (dirEntry = readdir(dir)) {
272         fullpath = path + dirEntry->d_name;
273         stat(fullpath.c_str(),&st);
274         if ((st.st_mode & S_IFMT) == S_IFDIR) {
275           for (int axis_ctr=0; axis_ctr < 6; axis_ctr++) {
276             if (dirEntry->d_name == Axis[axis_ctr]) {
277               if (coeffdir = opendir(fullpath.c_str())) {
278                 while (coeffdirEntry = readdir(coeffdir)) {
279                   if (coeffdirEntry->d_name[0] != '.') {
280                     filename = path + Axis[axis_ctr] + "/" + coeffdirEntry->d_name;
281                     stat(filename.c_str(),&st2);
282                     if (st2.st_size > 6) {
283                       Coeff[axis_ctr][coeff_ctr[axis_ctr]] = new FGCoefficient(FDMExec, filename);
284                       coeff_ctr[axis_ctr]++;
285                     }
286                   }
287                 }
288               }
289             }
290           }
291         }
292       }
293     } else {
294       cerr << "Could not open directory " << path << " for reading" << endl;
295     }
296     return true;
297
298   } else {
299     cerr << "Unable to open aircraft definition file " << fname << endl;
300     return false;
301   }
302
303 }
304
305
306 bool FGAircraft::Run(void)
307 {
308   if (!FGModel::Run()) {                 // if false then execute this Run()
309     GetState();
310
311     for (int i = 0; i < 3; i++)  Forces[i] = Moments[i] = 0.0;
312
313     MassChange();
314
315     FProp(); FAero(); FGear(); FMass();
316     MProp(); MAero(); MGear(); MMass();
317
318     PutState();
319   } else {                               // skip Run() execution this time
320   }
321   return false;
322 }
323
324
325 void FGAircraft::MassChange()
326 {
327   // UPDATE TANK CONTENTS
328   //
329   // For each engine, cycle through the tanks and draw an equal amount of
330   // fuel (or oxidizer) from each active tank. The needed amount of fuel is
331   // determined by the engine in the FGEngine class. If more fuel is needed
332   // than is available in the tank, then that amount is considered a shortage,
333   // and will be drawn from the next tank. If the engine cannot be fed what it
334   // needs, it will be considered to be starved, and will shut down.
335
336   float Oshortage, Fshortage;
337
338   for (int e=0; e<numEngines; e++) {
339     Fshortage = Oshortage = 0.0;
340     for (int t=0; t<numTanks; t++) {
341       switch(Engine[e]->GetType()) {
342       case FGEngine::etRocket:
343
344         switch(Tank[t]->GetType()) {
345         case FGTank::ttFUEL:
346           if (Tank[t]->GetSelected()) {
347             Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
348                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
349           }
350           break;
351         case FGTank::ttOXIDIZER:
352           if (Tank[t]->GetSelected()) {
353             Oshortage = Tank[t]->Reduce((Engine[e]->CalcOxidizerNeed()/
354                                     numSelectedOxiTanks)*(dt*rate) + Oshortage);
355           }
356           break;
357         }
358         break;
359
360       case FGEngine::etPiston:
361       case FGEngine::etTurboJet:
362       case FGEngine::etTurboProp:
363
364         if (Tank[t]->GetSelected()) {
365           Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
366                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
367         }
368         break;
369       }
370     }
371     if ((Fshortage <= 0.0) || (Oshortage <= 0.0)) Engine[e]->SetStarved();
372     else Engine[e]->SetStarved(false);
373   }
374
375   Weight = EmptyWeight;
376   for (int t=0; t<numTanks; t++)
377     Weight += Tank[t]->GetContents();
378
379   Mass = Weight / GRAVITY;
380 }
381
382
383 void FGAircraft::FAero(void)
384 {
385   float F[3];
386
387   F[0] = F[1] = F[2] = 0.0;
388
389   for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++)
390     for (int ctr=0; ctr < coeff_ctr[axis_ctr]; ctr++)
391       F[axis_ctr] += Coeff[axis_ctr][ctr]->Value();
392
393   Forces[0] +=  F[LiftCoeff]*sin(alpha) - F[DragCoeff]*cos(alpha) - F[SideCoeff]*sin(beta);
394   Forces[1] +=  F[SideCoeff]*cos(beta);
395   Forces[2] += -F[LiftCoeff]*cos(alpha) - F[DragCoeff]*sin(alpha);
396 }
397
398
399 void FGAircraft::FGear(void)
400 {
401   if (GearUp) {
402   } else {
403   }
404 }
405
406
407 void FGAircraft::FMass(void)
408 {
409   Forces[0] += -GRAVITY*sin(tht) * Mass;
410   Forces[1] +=  GRAVITY*sin(phi)*cos(tht) * Mass;
411   Forces[2] +=  GRAVITY*cos(phi)*cos(tht) * Mass;
412 }
413
414
415 void FGAircraft::FProp(void)
416 {
417   for (int i=0;i<numEngines;i++) {
418     Forces[0] += Engine[i]->CalcThrust();
419   }
420 }
421
422
423 void FGAircraft::MAero(void)
424 {
425   for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++)
426     for (int ctr = 0; ctr < coeff_ctr[axis_ctr+3]; ctr++)
427       Moments[axis_ctr] += Coeff[axis_ctr+3][ctr]->Value();
428 }
429
430
431 void FGAircraft::MGear(void)
432 {
433   if (GearUp) {
434   } else {
435   }
436 }
437
438
439 void FGAircraft::MMass(void)
440 {
441 }
442
443
444 void FGAircraft::MProp(void)
445 {
446 }
447
448
449 void FGAircraft::GetState(void)
450 {
451   dt = State->Getdt();
452
453   alpha = Translation->Getalpha();
454   beta = Translation->Getbeta();
455   phi = Rotation->Getphi();
456   tht = Rotation->Gettht();
457   psi = Rotation->Getpsi();
458 }
459
460
461 void FGAircraft::PutState(void)
462 {
463 }
464