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