]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGAircraft.cpp
Initial revision
[flightgear.git] / src / FDM / 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 04/03/99   JSB   Changed Aero() method to correct body axis force calculation
38                  from wind vector. Fix provided by Tony Peden.
39 05/03/99   JSB   Changed (for the better?) the way configurations are read in.
40
41 ********************************************************************************
42 COMMENTS, REFERENCES,  and NOTES
43 ********************************************************************************
44 [1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
45       Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420  Naval Postgraduate
46       School, January 1994
47 [2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
48       JSC 12960, July 1977
49 [3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
50       NASA-Ames", NASA CR-2497, January 1975
51 [4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
52       Wiley & Sons, 1979 ISBN 0-471-03032-5
53 [5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
54       1982 ISBN 0-471-08936-2
55
56 The aerodynamic coefficients used in this model are:
57
58 Longitudinal
59   CL0 - Reference lift at zero alpha
60   CD0 - Reference drag at zero alpha
61   CDM - Drag due to Mach
62   CLa - Lift curve slope (w.r.t. alpha)
63   CDa - Drag curve slope (w.r.t. alpha)
64   CLq - Lift due to pitch rate
65   CLM - Lift due to Mach
66   CLadt - Lift due to alpha rate
67
68   Cmadt - Pitching Moment due to alpha rate
69   Cm0 - Reference Pitching moment at zero alpha
70   Cma - Pitching moment slope (w.r.t. alpha)
71   Cmq - Pitch damping (pitch moment due to pitch rate)
72   CmM - Pitch Moment due to Mach
73
74 Lateral
75   Cyb - Side force due to sideslip
76   Cyr - Side force due to yaw rate
77
78   Clb - Dihedral effect (roll moment due to sideslip)
79   Clp - Roll damping (roll moment due to roll rate)
80   Clr - Roll moment due to yaw rate
81   Cnb - Weathercocking stability (yaw moment due to sideslip)
82   Cnp - Rudder adverse yaw (yaw moment due to roll rate)
83   Cnr - Yaw damping (yaw moment due to yaw rate)
84
85 Control
86   CLDe - Lift due to elevator
87   CDDe - Drag due to elevator
88   CyDr - Side force due to rudder
89   CyDa - Side force due to aileron
90
91   CmDe - Pitch moment due to elevator
92   ClDa - Roll moment due to aileron
93   ClDr - Roll moment due to rudder
94   CnDr - Yaw moment due to rudder
95   CnDa - Yaw moment due to aileron
96
97 This class expects to be run in a directory which contains the subdirectory
98 structure shown below (where example aircraft X-15 is shown):
99
100 aircraft/
101          X-15/
102               X-15.dat reset00 reset01 reset02 ...
103               CDRAG/
104                  a0 a M De
105               CSIDE/
106                  b r Dr Da
107               CLIFT/
108                  a0 a M adt De
109               CROLL/
110                  b p r Da Dr
111               CPITCH/
112                  a0 a adt q M De
113               CYAW/
114                  b p r Dr Da
115          F-16/
116               F-16.dat reset00 reset01 ...
117               CDRAG/
118                  a0 a M De
119               ...
120
121 The General Idea
122
123 The file structure is arranged so that various modeled aircraft are stored in
124 their own subdirectory. Each aircraft subdirectory is named after the aircraft.
125 There should be a file present in the specific aircraft subdirectory (e.g.
126 aircraft/X-15) with the same name as the directory with a .dat appended. This
127 file contains mass properties information, name of aircraft, etc. for the
128 aircraft. In that same directory are reset files numbered starting from 0 (two
129 digit numbers), e.g. reset03. Within each reset file are values for important
130 state variables for specific flight conditions (altitude, airspeed, etc.). Also
131 within this directory are the directories containing lookup tables for the
132 stability derivatives for the aircraft.
133
134 ********************************************************************************
135 INCLUDES
136 *******************************************************************************/
137
138 #include <sys/stat.h>
139 #include <sys/types.h>
140
141 #ifdef FGFS
142 # ifndef __BORLANDC__
143 #  include <Include/compiler.h>
144 # endif
145 #  ifdef FG_HAVE_STD_INCLUDES
146 #    include <cmath>
147 #  else
148 #    include <math.h>
149 #  endif
150 #else
151 #  include <cmath>
152 #endif
153
154 #include "FGAircraft.h"
155 #include "FGTranslation.h"
156 #include "FGRotation.h"
157 #include "FGAtmosphere.h"
158 #include "FGState.h"
159 #include "FGFDMExec.h"
160 #include "FGFCS.h"
161 #include "FGPosition.h"
162 #include "FGAuxiliary.h"
163 #include "FGOutput.h"
164
165 /*******************************************************************************
166 ************************************ CODE **************************************
167 *******************************************************************************/
168
169 FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
170 {
171   int i;
172
173   Name = "FGAircraft";
174
175   for (i=0;i<6;i++) coeff_ctr[i] = 0;
176 }
177
178
179 FGAircraft::~FGAircraft(void)
180 {
181 }
182
183 bool FGAircraft::LoadAircraftEx(string aircraft_path, string engine_path, string fname)
184 {
185   string path;
186   string fullpath;
187   string filename;
188   string aircraftDef;
189   string tag;
190   string holding_string;
191   char scratch[128];
192   ifstream coeffInFile;
193
194   aircraftDef = aircraft_path + "/" + fname + "/" + fname + ".cfg";
195   ifstream aircraftfile(aircraftDef.c_str());
196   cout << "Reading Aircraft Configuration File: " << aircraftDef << endl;
197
198   numTanks = numEngines = 0;
199   numSelectedOxiTanks = numSelectedFuelTanks = 0;
200
201   while (!aircraftfile.fail()) {
202         holding_string.erase();
203     aircraftfile >> holding_string;
204     // if (holding_string.compare("//",0,2) != 0) {
205     if ( !(holding_string.substr(0, 2) == "//") ) {
206
207       if (holding_string == "AIRCRAFT") {
208         cout << "Reading in Aircraft parameters ..." << endl;
209       } else if (holding_string == "AERODYNAMICS") {
210         cout << "Reading in Aerodynamic parameters ..." << endl;
211                         } else if (holding_string == "AC_NAME") {
212                     aircraftfile >> AircraftName;   // String with no embedded spaces
213                     cout << "Aircraft Name: " << AircraftName << endl;
214                         } else if (holding_string == "AC_WINGAREA") {
215                                 aircraftfile >> WingArea;
216                                 cout << "Aircraft Wing Area: " << WingArea << endl;
217                         } else if (holding_string == "AC_WINGSPAN") {
218                                 aircraftfile >> WingSpan;
219                                 cout << "Aircraft WingSpan: " << WingSpan << endl;
220                         } else if (holding_string == "AC_CHORD") {
221                                 aircraftfile >> cbar;
222                                 cout << "Aircraft Chord: " << cbar << endl;
223                         } else if (holding_string == "AC_IXX") {
224                                 aircraftfile >> Ixx;
225                                 cout << "Aircraft Ixx: " << Ixx << endl;
226                         } else if (holding_string == "AC_IYY") {
227                                 aircraftfile >> Iyy;
228                                 cout << "Aircraft Iyy: " << Iyy << endl;
229                         } else if (holding_string == "AC_IZZ") {
230                                 aircraftfile >> Izz;
231                                 cout << "Aircraft Izz: " << Izz << endl;
232                         } else if (holding_string == "AC_IXZ") {
233                                 aircraftfile >> Ixz;
234                                 cout << "Aircraft Ixz: " << Ixz << endl;
235                         } else if (holding_string == "AC_EMPTYWT") {
236                                 aircraftfile >> EmptyWeight;
237                                 EmptyMass = EmptyWeight / GRAVITY;
238                                 cout << "Aircraft Empty Weight: " << EmptyWeight << endl;
239                         } else if (holding_string == "AC_CGLOC") {
240                                 aircraftfile >> Xcg >> Ycg >> Zcg;
241                                 cout << "Aircraft C.G.: " << Xcg << " " << Ycg << " " << Zcg << endl;
242                         } else if (holding_string == "AC_EYEPTLOC") {
243                                 aircraftfile >> Xep >> Yep >> Zep;
244                                 cout << "Pilot Eyepoint: " << Xep << " " << Yep << " " << Zep << endl;
245                         } else if (holding_string == "AC_TANK") {
246         Tank[numTanks] = new FGTank(aircraftfile);
247         switch(Tank[numTanks]->GetType()) {
248         case FGTank::ttFUEL:
249           numSelectedFuelTanks++;
250                                         cout << "Reading in Fuel Tank #" << numSelectedFuelTanks << " parameters ..." << endl;
251           break;
252         case FGTank::ttOXIDIZER:
253           numSelectedOxiTanks++;
254                                         cout << "Reading in Oxidizer Tank #" << numSelectedOxiTanks << " parameters ..." << endl;
255           break;
256         }
257         numTanks++;
258
259                         } else if (holding_string == "AC_ENGINE") {
260
261         aircraftfile >> tag;
262                                 cout << "Reading in " << tag << " Engine parameters ..." << endl;
263         Engine[numEngines] = new FGEngine(FDMExec, engine_path, tag, numEngines);
264         numEngines++;
265
266                         } else if (holding_string == "}") {
267
268                         } else if (holding_string == "{") {
269
270                         } else if (holding_string == "LIFT") {
271
272                                 cout << "   Lift Coefficients ..." << endl;
273         aircraftfile >> tag;
274         streampos gpos = aircraftfile.tellg();
275                                 aircraftfile >> tag;
276                                 if ( !(tag == "}") ) {
277                                         aircraftfile.seekg(gpos);
278                 Coeff[LiftCoeff][coeff_ctr[LiftCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
279               coeff_ctr[LiftCoeff]++;
280             } else {
281                 cout << "      None found ..." << endl;
282             }
283
284                         } else if (holding_string == "DRAG") {
285
286                                 cout << "   Drag Coefficients ..." << endl;
287         aircraftfile >> tag;
288         streampos gpos = aircraftfile.tellg();
289                                 aircraftfile >> tag;
290                                 if ( !(tag == "}") ) {
291                                         aircraftfile.seekg(gpos);
292                 Coeff[DragCoeff][coeff_ctr[DragCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
293               coeff_ctr[DragCoeff]++;
294             } else {
295                 cout << "      None found ..." << endl;
296             }
297
298                         } else if (holding_string == "SIDE") {
299
300                                 cout << "   Side Coefficients ..." << endl;
301         aircraftfile >> tag;
302         streampos gpos = aircraftfile.tellg();
303                                 aircraftfile >> tag;
304                                 if ( !(tag == "}") ) {
305                                         aircraftfile.seekg(gpos);
306                 Coeff[SideCoeff][coeff_ctr[SideCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
307               coeff_ctr[SideCoeff]++;
308             } else {
309                 cout << "      None found ..." << endl;
310             }
311
312                         } else if (holding_string == "ROLL") {
313
314                                 cout << "   Roll Coefficients ..." << endl;
315         aircraftfile >> tag;
316         streampos gpos = aircraftfile.tellg();
317                                 aircraftfile >> tag;
318                                 if ( !(tag == "}") ) {
319                                         aircraftfile.seekg(gpos);
320                 Coeff[RollCoeff][coeff_ctr[RollCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
321               coeff_ctr[RollCoeff]++;
322             } else {
323                 cout << "      None found ..." << endl;
324             }
325
326                         } else if (holding_string == "PITCH") {
327
328                                 cout << "   Pitch Coefficients ..." << endl;
329         aircraftfile >> tag;
330         streampos gpos = aircraftfile.tellg();
331                                 aircraftfile >> tag;
332                                 if ( !(tag == "}") ) {
333                                         aircraftfile.seekg(gpos);
334                 Coeff[PitchCoeff][coeff_ctr[PitchCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
335               coeff_ctr[PitchCoeff]++;
336             } else {
337                 cout << "      None found ..." << endl;
338             }
339
340                         } else if (holding_string == "YAW") {
341
342                                 cout << "   Yaw Coefficients ..." << endl;
343         aircraftfile >> tag;
344         streampos gpos = aircraftfile.tellg();
345                                 aircraftfile >> tag;
346                                 if ( !(tag == "}") ) {
347                                         aircraftfile.seekg(gpos);
348                 Coeff[YawCoeff][coeff_ctr[YawCoeff]] = new FGCoefficient(FDMExec, aircraftfile);
349               coeff_ctr[YawCoeff]++;
350             } else {
351                 cout << "      None found ..." << endl;
352             }
353
354                         } else {
355                         }
356
357     } else {
358         aircraftfile.getline(scratch, 127);
359     }
360   }
361         cout << "End of Configuration File Parsing." << endl;
362         return true;
363 }
364
365
366 bool FGAircraft::Run(void)
367 {
368   if (!FGModel::Run()) {                 // if false then execute this Run()
369     GetState();
370
371     for (int i = 0; i < 3; i++)  Forces[i] = Moments[i] = 0.0;
372
373     MassChange();
374
375     FProp(); FAero(); FGear(); FMass();
376     MProp(); MAero(); MGear(); MMass();
377
378     PutState();
379   } else {                               // skip Run() execution this time
380   }
381   return false;
382 }
383
384
385 void FGAircraft::MassChange()
386 {
387   // UPDATE TANK CONTENTS
388   //
389   // For each engine, cycle through the tanks and draw an equal amount of
390   // fuel (or oxidizer) from each active tank. The needed amount of fuel is
391   // determined by the engine in the FGEngine class. If more fuel is needed
392   // than is available in the tank, then that amount is considered a shortage,
393   // and will be drawn from the next tank. If the engine cannot be fed what it
394   // needs, it will be considered to be starved, and will shut down.
395
396   float Oshortage, Fshortage;
397
398   for (int e=0; e<numEngines; e++) {
399     Fshortage = Oshortage = 0.0;
400     for (int t=0; t<numTanks; t++) {
401       switch(Engine[e]->GetType()) {
402       case FGEngine::etRocket:
403
404         switch(Tank[t]->GetType()) {
405         case FGTank::ttFUEL:
406           if (Tank[t]->GetSelected()) {
407             Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
408                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
409           }
410           break;
411         case FGTank::ttOXIDIZER:
412           if (Tank[t]->GetSelected()) {
413             Oshortage = Tank[t]->Reduce((Engine[e]->CalcOxidizerNeed()/
414                                     numSelectedOxiTanks)*(dt*rate) + Oshortage);
415           }
416           break;
417         }
418         break;
419
420       case FGEngine::etPiston:
421       case FGEngine::etTurboJet:
422       case FGEngine::etTurboProp:
423
424         if (Tank[t]->GetSelected()) {
425           Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
426                                    numSelectedFuelTanks)*(dt*rate) + Fshortage);
427         }
428         break;
429       }
430     }
431     if ((Fshortage <= 0.0) || (Oshortage <= 0.0)) Engine[e]->SetStarved();
432     else Engine[e]->SetStarved(false);
433   }
434
435   Weight = EmptyWeight;
436   for (int t=0; t<numTanks; t++)
437     Weight += Tank[t]->GetContents();
438
439   Mass = Weight / GRAVITY;
440 }
441
442
443 void FGAircraft::FAero(void)
444 {
445   float F[3];
446
447   F[0] = F[1] = F[2] = 0.0;
448
449   for (int axis_ctr = 0; axis_ctr < 3; axis_ctr++)
450     for (int ctr=0; ctr < coeff_ctr[axis_ctr]; ctr++)
451       F[axis_ctr] += Coeff[axis_ctr][ctr]->TotalValue();
452
453   Forces[0] +=  F[DragCoeff]*cos(alpha)*cos(beta) - F[SideCoeff]*cos(alpha)*sin(beta) - F[LiftCoeff]*sin(alpha);
454   Forces[1] +=  F[DragCoeff]*sin(beta)            + F[SideCoeff]*cos(beta);
455   Forces[2] +=  F[DragCoeff]*sin(alpha)*cos(beta) - F[SideCoeff]*sin(alpha)*sin(beta) + F[LiftCoeff]*cos(alpha);
456 }
457
458
459 void FGAircraft::FGear(void)
460 {
461   if (GearUp) {
462   } else {
463   }
464 }
465
466
467 void FGAircraft::FMass(void)
468 {
469   Forces[0] += -GRAVITY*sin(tht) * Mass;
470   Forces[1] +=  GRAVITY*sin(phi)*cos(tht) * Mass;
471   Forces[2] +=  GRAVITY*cos(phi)*cos(tht) * Mass;
472 }
473
474
475 void FGAircraft::FProp(void)
476 {
477   for (int i=0;i<numEngines;i++) {
478     Forces[0] += Engine[i]->CalcThrust();
479   }
480 }
481
482
483 void FGAircraft::MAero(void)
484 {
485         int axis_ctr, ctr;
486         
487   for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
488     for (ctr = 0; ctr < coeff_ctr[axis_ctr+3]; ctr++) {
489       Moments[axis_ctr] += Coeff[axis_ctr+3][ctr]->TotalValue();
490     }
491   }
492 }
493
494
495 void FGAircraft::MGear(void)
496 {
497   if (GearUp) {
498   } else {
499   }
500 }
501
502
503 void FGAircraft::MMass(void)
504 {
505 }
506
507
508 void FGAircraft::MProp(void)
509 {
510 }
511
512
513 void FGAircraft::GetState(void)
514 {
515   dt = State->Getdt();
516
517   alpha = Translation->Getalpha();
518   beta = Translation->Getbeta();
519   phi = Rotation->Getphi();
520   tht = Rotation->Gettht();
521   psi = Rotation->Getpsi();
522 }
523
524
525 void FGAircraft::PutState(void)
526 {
527 }
528