1 /*******************************************************************************
6 Purpose: Encapsulates an aircraft
9 ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
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
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
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.
25 Further information about the GNU General Public License can also be found on
26 the world wide web at http://www.gnu.org.
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 Models the aircraft reactions and forces.
33 --------------------------------------------------------------------------------
37 --------------------------------------------------------------------------------
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
46 [2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
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
55 The aerodynamic coefficients used in this model are:
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
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
74 Cyb - Side force due to sideslip
75 Cyr - Side force due to yaw rate
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)
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
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
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):
101 X-15.dat reset00 reset01 reset02 ...
115 F-16.dat reset00 reset01 ...
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.
133 ********************************************************************************
135 *******************************************************************************/
136 #include "FGAircraft.h"
140 #include <sys/stat.h>
141 #include <sys/types.h>
144 /*******************************************************************************
145 ************************************ CODE **************************************
146 *******************************************************************************/
149 FGAircraft::FGAircraft(void) : FGModel()
153 strcpy(Name,"FGAircraft");
155 for (i=0;i<6;i++) Axis[i] = (char*)malloc(7);
156 for (i=0;i<6;i++) coeff_ctr[i] = 0;
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");
167 FGAircraft::~FGAircraft(void)
172 bool FGAircraft::LoadAircraft(char* fname)
177 char aircraftDef[2100];
181 struct dirent* dirEntry = 0L;
182 struct dirent* coeffdirEntry = 0L;
185 ifstream coeffInFile;
189 sprintf(aircraftDef, "/h/curt/projects/FlightGear/Simulator/FDM/JSBsim/aircraft/%s/%s.dat", fname, fname);
190 ifstream aircraftfile(aircraftDef);
193 aircraftfile >> AircraftName;
194 aircraftfile >> WingArea;
195 aircraftfile >> WingSpan;
196 aircraftfile >> cbar;
201 aircraftfile >> Weight;
205 numTanks = numEngines = 0;
206 numSelectedOxiTanks = numSelectedFuelTanks = 0;
208 while (strstr(tag,"EOF") == 0) {
209 if (strstr(tag,"CGLOC")) {
213 } else if (strstr(tag,"EYEPOINTLOC")) {
217 } else if (strstr(tag,"TANK")) {
218 Tank[numTanks] = new FGTank(aircraftfile);
219 switch(Tank[numTanks]->GetType()) {
221 numSelectedOxiTanks++;
224 numSelectedFuelTanks++;
228 } else if (strstr(tag,"ENGINE")) {
230 Engine[numEngines] = new FGEngine(tag);
235 aircraftfile.close();
238 // Read subdirectory for this aircraft for stability derivative lookup tables:
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.
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.
256 sprintf(path,"/h/curt/projects/FlightGear/Simulator/FDM/JSBsim/aircraft/%s/",AircraftName);
257 if ( dir = opendir(path) ) {
259 while (dirEntry = readdir(dir)) {
260 sprintf(fullpath,"%s%s",path,dirEntry->d_name);
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);
270 if (st2.st_size > 6) {
271 Coeff[axis_ctr][coeff_ctr[axis_ctr]] = new FGCoefficient(filename);
272 coeff_ctr[axis_ctr]++;
282 cerr << "Could not open directory " << path << " for reading" << endl;
287 cerr << "Unable to open aircraft definition file " << fname << endl;
294 bool FGAircraft::Run(void)
296 if (!FGModel::Run()) { // if false then execute this Run()
299 for (int i = 0; i < 3; i++) Forces[i] = Moments[i] = 0.0;
301 FProp(); FAero(); FGear(); FMass();
302 MProp(); MAero(); MGear(); MMass();
305 } else { // skip Run() execution this time
311 void FGAircraft::FAero(void)
315 F[0] = F[1] = F[2] = 0.0;
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();
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);
327 void FGAircraft::FGear(void)
335 void FGAircraft::FMass(void)
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;
343 void FGAircraft::FProp(void)
345 float Oshortage, Fshortage;
347 for (int i=0;i<numEngines;i++) {
348 Forces[0] += Engine[i]->CalcThrust();
352 // UPDATE TANK CONTENTS
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.
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()) {
366 switch(Tank[t]->GetType()) {
368 if (Tank[t]->GetSelected()) {
369 Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/numSelectedFuelTanks)*(dt*rate) + Fshortage);
373 if (Tank[t]->GetSelected()) {
374 Oshortage = Tank[t]->Reduce((Engine[e]->CalcOxidizerNeed()/numSelectedOxiTanks)*(dt*rate) + Oshortage);
379 default: // piston, turbojet, turbofan, etc.
380 if (Tank[t]->GetSelected()) {
381 Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/numSelectedFuelTanks)*(dt*rate) + Fshortage);
386 if ((Fshortage < 0.0) || (Oshortage < 0.0)) Engine[e]->SetStarved();
387 else Engine[e]->SetStarved(false);
393 void FGAircraft::MAero(void)
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();
401 void FGAircraft::MGear(void)
409 void FGAircraft::MMass(void)
414 void FGAircraft::MProp(void)
419 void FGAircraft::GetState(void)
421 Ixx = State->GetIxx();
422 Iyy = State->GetIyy();
423 Izz = State->GetIzz();
424 Ixz = State->GetIxz();
425 alpha = State->Getalpha();
426 beta = State->Getbeta();
428 phi = State->Getphi();
429 tht = State->Gettht();
430 psi = State->Getpsi();
436 void FGAircraft::PutState(void)
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]);