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