]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/FGAircraft.cpp
JSBSim updates, including external atmosphere fix
[flightgear.git] / src / FDM / JSBSim / FGAircraft.cpp
index b0639ec3cffbc790a8b6572bd27e9decf3bfac8d..5ee4979c07952e1642e4ab89ba3d2b043731f021 100644 (file)
@@ -1,11 +1,11 @@
-/*******************************************************************************
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  Module:       FGAircraft.cpp
  Author:       Jon S. Berndt
  Date started: 12/12/98                                   
  Purpose:      Encapsulates an aircraft
  Called by:    FGFDMExec
  
  Module:       FGAircraft.cpp
  Author:       Jon S. Berndt
  Date started: 12/12/98                                   
  Purpose:      Encapsulates an aircraft
  Called by:    FGFDMExec
+
  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
  
  This program is free software; you can redistribute it and/or modify it under
  ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------
  
  This program is free software; you can redistribute it and/or modify it under
@@ -28,8 +28,7 @@
 FUNCTIONAL DESCRIPTION
 --------------------------------------------------------------------------------
 Models the aircraft reactions and forces. This class is instantiated by the
 FUNCTIONAL DESCRIPTION
 --------------------------------------------------------------------------------
 Models the aircraft reactions and forces. This class is instantiated by the
-FGFDMExec class and scheduled as an FDM entry. LoadAircraft() is supplied with a
-name of a valid, registered aircraft, and the data file is parsed.
+FGFDMExec class and scheduled as an FDM entry. 
  
 HISTORY
 --------------------------------------------------------------------------------
  
 HISTORY
 --------------------------------------------------------------------------------
@@ -41,65 +40,13 @@ HISTORY
                  point to config file. Added calculations for moments due to 
                  difference in cg and aero reference point
  
                  point to config file. Added calculations for moments due to 
                  difference in cg and aero reference point
  
-********************************************************************************
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 COMMENTS, REFERENCES,  and NOTES
 COMMENTS, REFERENCES,  and NOTES
-********************************************************************************
-[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
-      Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420  Naval Postgraduate
-      School, January 1994
-[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
-      JSC 12960, July 1977
-[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
-      NASA-Ames", NASA CR-2497, January 1975
-[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
-      Wiley & Sons, 1979 ISBN 0-471-03032-5
-[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
-      1982 ISBN 0-471-08936-2
-The aerodynamic coefficients used in this model are:
-Longitudinal
-  CL0 - Reference lift at zero alpha
-  CD0 - Reference drag at zero alpha
-  CDM - Drag due to Mach
-  CLa - Lift curve slope (w.r.t. alpha)
-  CDa - Drag curve slope (w.r.t. alpha)
-  CLq - Lift due to pitch rate
-  CLM - Lift due to Mach
-  CLadt - Lift due to alpha rate
-  Cmadt - Pitching Moment due to alpha rate
-  Cm0 - Reference Pitching moment at zero alpha
-  Cma - Pitching moment slope (w.r.t. alpha)
-  Cmq - Pitch damping (pitch moment due to pitch rate)
-  CmM - Pitch Moment due to Mach
-Lateral
-  Cyb - Side force due to sideslip
-  Cyr - Side force due to yaw rate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  
-  Clb - Dihedral effect (roll moment due to sideslip)
-  Clp - Roll damping (roll moment due to roll rate)
-  Clr - Roll moment due to yaw rate
-  Cnb - Weathercocking stability (yaw moment due to sideslip)
-  Cnp - Rudder adverse yaw (yaw moment due to roll rate)
-  Cnr - Yaw damping (yaw moment due to yaw rate)
-Control
-  CLDe - Lift due to elevator
-  CDDe - Drag due to elevator
-  CyDr - Side force due to rudder
-  CyDa - Side force due to aileron
-  CmDe - Pitch moment due to elevator
-  ClDa - Roll moment due to aileron
-  ClDr - Roll moment due to rudder
-  CnDr - Yaw moment due to rudder
-  CnDa - Yaw moment due to aileron
-********************************************************************************
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 INCLUDES
 INCLUDES
-*******************************************************************************/
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 #include <sys/stat.h>
 #include <sys/types.h>
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -108,16 +55,24 @@ INCLUDES
 #  ifndef __BORLANDC__
 #    include <simgear/compiler.h>
 #  endif
 #  ifndef __BORLANDC__
 #    include <simgear/compiler.h>
 #  endif
-#  ifdef FG_HAVE_STD_INCLUDES
+#  ifdef SG_HAVE_STD_INCLUDES
 #    include <cmath>
 #  else
 #    include <math.h>
 #  endif
 #else
 #    include <cmath>
 #  else
 #    include <math.h>
 #  endif
 #else
-#  include <cmath>
+#  if defined (sgi) && !defined(__GNUC__)
+#    include <math.h>
+#  else
+#    include <cmath>
+#  endif
 #endif
 
 #include "FGAircraft.h"
 #endif
 
 #include "FGAircraft.h"
+#include "FGMassBalance.h"
+#include "FGInertial.h"
+#include "FGGroundReactions.h"
+#include "FGAerodynamics.h"
 #include "FGTranslation.h"
 #include "FGRotation.h"
 #include "FGAtmosphere.h"
 #include "FGTranslation.h"
 #include "FGRotation.h"
 #include "FGAtmosphere.h"
@@ -127,627 +82,300 @@ INCLUDES
 #include "FGPosition.h"
 #include "FGAuxiliary.h"
 #include "FGOutput.h"
 #include "FGPosition.h"
 #include "FGAuxiliary.h"
 #include "FGOutput.h"
+#include "FGPropertyManager.h"
 
 
-const char *IdSrc = "$Header$";
-const char *IdHdr = ID_AIRCRAFT;
-
-/*******************************************************************************
-************************************ CODE **************************************
-*******************************************************************************/
-
-FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex),
-    vMoments(3),
-    vForces(3),
-    vFs(3),
-    vXYZrp(3),
-    vbaseXYZcg(3),
-    vXYZcg(3),
-    vXYZep(3),
-    vEuler(3)
-    
-{
-  Name = "FGAircraft";
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 
-  AxisIdx["DRAG"]  = 0;
-  AxisIdx["SIDE"]  = 1;
-  AxisIdx["LIFT"]  = 2;
-  AxisIdx["ROLL"]  = 3;
-  AxisIdx["PITCH"] = 4;
-  AxisIdx["YAW"]   = 5;
-  
-  Coeff = new CoeffArray[6];
-
-  GearUp = false;
-  
-  alphaclmin = alphaclmax = 0;
-
-  numTanks = numEngines = numSelectedFuelTanks = numSelectedOxiTanks = 0;
-}
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+GLOBAL DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_AIRCRAFT;
 
 
-/******************************************************************************/
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 
+FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+  Name = "FGAircraft";
+  HTailArea = VTailArea = 0.0;
+  HTailArm  = VTailArm  = 0.0;
+  lbarh = lbarv = 0.0;
+  vbarh = vbarv = 0.0;
 
 
-FGAircraft::~FGAircraft(void) { 
-  unsigned int i,j;
+  bind();
 
 
-  if (Engine != NULL) {
-    for (i=0; i<numEngines; i++)
-      delete Engine[i];
-  }    
-  if (Tank != NULL) {
-    for (i=0; i<numTanks; i++)
-      delete Tank[i];
-  }    
-  for (i=0; i<6; i++) {
-    for (j=0; j<Coeff[i].size(); j++) {
-      delete Coeff[i][j];
-    }
-  }
-  delete[] Coeff;
+  Debug(0);
 }
 
 }
 
-/******************************************************************************/
-
-bool FGAircraft::LoadAircraft(string aircraft_path, string engine_path, string fname) {
-  string path;
-  string filename;
-  string aircraftCfgFileName;
-  string token;
-
-  AircraftPath = aircraft_path;
-  EnginePath = engine_path;
-
-# ifndef macintosh
-  aircraftCfgFileName = AircraftPath + "/" + fname + "/" + fname + ".xml";
-# else  
-  aircraftCfgFileName = AircraftPath + ";" + fname + ";" + fname + ".xml";
-# endif
-
-  FGConfigFile AC_cfg(aircraftCfgFileName);
-  if (!AC_cfg.IsOpen()) return false;
-
-  ReadPrologue(&AC_cfg);
-
-  while ((AC_cfg.GetNextConfigLine() != "EOF") &&
-         (token = AC_cfg.GetValue()) != "/FDM_CONFIG") {
-    if (token == "METRICS") {
-      cout << "  Reading Metrics" << endl;
-      ReadMetrics(&AC_cfg);
-    } else if (token == "AERODYNAMICS") {
-      cout << "  Reading Aerodynamics" << endl;
-      ReadAerodynamics(&AC_cfg);
-    } else if (token == "UNDERCARRIAGE") {
-      cout << "  Reading Landing Gear" << endl;
-      ReadUndercarriage(&AC_cfg);
-    } else if (token == "PROPULSION") {
-      cout << "  Reading Propulsion" << endl;
-      ReadPropulsion(&AC_cfg);
-    } else if (token == "FLIGHT_CONTROL") {
-      cout << "  Reading Flight Control" << endl;
-      ReadFlightControls(&AC_cfg);
-    } else if (token == "OUTPUT") {
-      ReadOutput(&AC_cfg);
-    }
-  }
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-  return true;
+FGAircraft::~FGAircraft()
+{
+  unbind();
+  Debug(1);
 }
 
 }
 
-/******************************************************************************/
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-bool FGAircraft::Run(void) {
+bool FGAircraft::Run(void)
+{
   if (!FGModel::Run()) {                 // if false then execute this Run()
   if (!FGModel::Run()) {                 // if false then execute this Run()
-    GetState();
-
-    for (int i = 1; i <= 3; i++)  vForces(i) = vMoments(i) = 0.0;
-
-    MassChange();
-    FMProp();
-    FMAero();
-    FMGear();
-    FMMass();
+    vForces.InitMatrix();
+    vForces += Aerodynamics->GetForces();
+    vForces += Inertial->GetForces();
+    vForces += Propulsion->GetForces();
+    vForces += GroundReactions->GetForces();
+
+    vMoments.InitMatrix();
+    vMoments += Aerodynamics->GetMoments();
+    vMoments += Propulsion->GetMoments();
+    vMoments += GroundReactions->GetMoments();
+    
+    vBodyAccel = vForces/MassBalance->GetMass();
+    
+    vNcg = vBodyAccel/Inertial->gravity();
 
 
-    nlf = 0;
-    if (fabs(Position->GetGamma()) < 1.57) {
-        nlf = vFs(eZ)/(Weight*cos(Position->GetGamma()));
-    }    
-        
+    vNwcg = State->GetTb2s() * vNcg;
+    vNwcg(3) = -1*vNwcg(3) + 1;
+    
+    return false;
   } else {                               // skip Run() execution this time
   } else {                               // skip Run() execution this time
+    return true;
   }
   }
-
-
-  return false;
-}
-
-/******************************************************************************/
-
-void FGAircraft::MassChange() {
-  static FGColumnVector vXYZtank(3);
-  float Tw;
-  float IXXt, IYYt, IZZt, IXZt;
-  unsigned int t;
-  unsigned int axis_ctr;
-
-  for (axis_ctr=1; axis_ctr<=3; axis_ctr++) vXYZtank(axis_ctr) = 0.0;
-
-  // UPDATE TANK CONTENTS
-  //
-  // For each engine, cycle through the tanks and draw an equal amount of
-  // fuel (or oxidizer) from each active tank. The needed amount of fuel is
-  // determined by the engine in the FGEngine class. If more fuel is needed
-  // than is available in the tank, then that amount is considered a shortage,
-  // and will be drawn from the next tank. If the engine cannot be fed what it
-  // needs, it will be considered to be starved, and will shut down.
-
-  float Oshortage, Fshortage;
-
-  for (unsigned int e=0; e<numEngines; e++) {
-    Fshortage = Oshortage = 0.0;
-    for (t=0; t<numTanks; t++) {
-      switch(Engine[e]->GetType()) {
-      case FGEngine::etRocket:
-
-        switch(Tank[t]->GetType()) {
-        case FGTank::ttFUEL:
-          if (Tank[t]->GetSelected()) {
-            Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
-                                         numSelectedFuelTanks)*(dt*rate) + Fshortage);
-          }
-          break;
-        case FGTank::ttOXIDIZER:
-          if (Tank[t]->GetSelected()) {
-            Oshortage = Tank[t]->Reduce((Engine[e]->CalcOxidizerNeed()/
-                                         numSelectedOxiTanks)*(dt*rate) + Oshortage);
-          }
-          break;
-        }
-        break;
-
-      case FGEngine::etPiston:
-      case FGEngine::etTurboJet:
-      case FGEngine::etTurboProp:
-
-        if (Tank[t]->GetSelected()) {
-          Fshortage = Tank[t]->Reduce((Engine[e]->CalcFuelNeed()/
-                                       numSelectedFuelTanks)*(dt*rate) + Fshortage);
-        }
-        break;
-      }
-    }
-    if ((Fshortage <= 0.0) || (Oshortage <= 0.0)) Engine[e]->SetStarved();
-    else Engine[e]->SetStarved(false);
-  }
-
-  Weight = EmptyWeight;
-  for (t=0; t<numTanks; t++)
-    Weight += Tank[t]->GetContents();
-
-  Mass = Weight / GRAVITY;
-  // Calculate new CG here.
-
-  Tw = 0;
-  for (t=0; t<numTanks; t++) {
-    vXYZtank(eX) += Tank[t]->GetX()*Tank[t]->GetContents();
-    vXYZtank(eY) += Tank[t]->GetY()*Tank[t]->GetContents();
-    vXYZtank(eZ) += Tank[t]->GetZ()*Tank[t]->GetContents();
-
-    Tw += Tank[t]->GetContents();
-  }
-
-  vXYZcg = (vXYZtank + EmptyWeight*vbaseXYZcg) / (Tw + EmptyWeight);
-
-  // Calculate new moments of inertia here
-
-  IXXt = IYYt = IZZt = IXZt = 0.0;
-  for (t=0; t<numTanks; t++) {
-    IXXt += ((Tank[t]->GetX()-vXYZcg(eX))/12.0)*((Tank[t]->GetX() - vXYZcg(eX))/12.0)*Tank[t]->GetContents()/GRAVITY;
-    IYYt += ((Tank[t]->GetY()-vXYZcg(eY))/12.0)*((Tank[t]->GetY() - vXYZcg(eY))/12.0)*Tank[t]->GetContents()/GRAVITY;
-    IZZt += ((Tank[t]->GetZ()-vXYZcg(eZ))/12.0)*((Tank[t]->GetZ() - vXYZcg(eZ))/12.0)*Tank[t]->GetContents()/GRAVITY;
-    IXZt += ((Tank[t]->GetX()-vXYZcg(eX))/12.0)*((Tank[t]->GetZ() - vXYZcg(eZ))/12.0)*Tank[t]->GetContents()/GRAVITY;
-  }
-
-  Ixx = baseIxx + IXXt;
-  Iyy = baseIyy + IYYt;
-  Izz = baseIzz + IZZt;
-  Ixz = baseIxz + IXZt;
-
-}
-
-/******************************************************************************/
-
-void FGAircraft::FMAero(void) {
-  static FGColumnVector vDXYZcg(3);
-  static FGColumnVector vAeroBodyForces(3);
-  unsigned int axis_ctr,ctr;
-
-  for (axis_ctr=1; axis_ctr<=3; axis_ctr++) vFs(axis_ctr) = 0.0;
-
-  for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
-    for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
-      vFs(axis_ctr+1) += Coeff[axis_ctr][ctr]->TotalValue();
-    }
-  }
-
-  vAeroBodyForces = State->GetTs2b(alpha, beta)*vFs;
-  vForces += vAeroBodyForces;
-
-  // The d*cg distances below, given in inches, are the distances FROM the c.g.
-  // TO the reference point. Since the c.g. and ref point are given in inches in
-  // the structural system (X positive rearwards) and the body coordinate system
-  // is given with X positive out the nose, the dxcg and dzcg values are
-  // *rotated* 180 degrees about the Y axis.
-
-  vDXYZcg(eX) = -(vXYZrp(eX) - vXYZcg(eX))/12.0;  //cg and rp values are in inches
-  vDXYZcg(eY) =  (vXYZrp(eY) - vXYZcg(eY))/12.0;
-  vDXYZcg(eZ) = -(vXYZrp(eZ) - vXYZcg(eZ))/12.0;
-
-  vMoments(eL) += vAeroBodyForces(eZ)*vDXYZcg(eY) - vAeroBodyForces(eY)*vDXYZcg(eZ); // rolling moment
-  vMoments(eM) += vAeroBodyForces(eX)*vDXYZcg(eZ) - vAeroBodyForces(eZ)*vDXYZcg(eX); // pitching moment
-  vMoments(eN) += vAeroBodyForces(eY)*vDXYZcg(eX) - vAeroBodyForces(eX)*vDXYZcg(eY); // yawing moment
-  
-  for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
-    for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
-      vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->TotalValue();
-    }
-  }
-}
-
-/******************************************************************************/
-
-void FGAircraft::FMGear(void) {
-
-  if ( !GearUp ) {
-    vector <FGLGear>::iterator iGear = lGear.begin();
-    while (iGear != lGear.end()) {
-      vForces  += iGear->Force();
-      vMoments += iGear->Moment();
-      iGear++;
-    }
-  } else {
-    // Crash Routine
-  }
-}
-
-/******************************************************************************/
-
-void FGAircraft::FMMass(void) {
-  vForces(eX) += -GRAVITY*sin(vEuler(eTht)) * Mass;
-  vForces(eY) +=  GRAVITY*sin(vEuler(ePhi))*cos(vEuler(eTht)) * Mass;
-  vForces(eZ) +=  GRAVITY*cos(vEuler(ePhi))*cos(vEuler(eTht)) * Mass;
-}
-
-/******************************************************************************/
-
-void FGAircraft::FMProp(void) {
-  for (unsigned int i=0;i<numEngines;i++) {
-
-    // Changes required here for new engine placement parameters (i.e. location and direction)
-
-    vForces(eX) += Engine[i]->CalcThrust();
-  }
-  
 }
 
 }
 
-/******************************************************************************/
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-void FGAircraft::GetState(void) {
-  dt = State->Getdt();
-
-  alpha = Translation->Getalpha();
-  beta = Translation->Getbeta();
-  vEuler = Rotation->GetEuler();
+float FGAircraft::GetNlf(void)
+{
+  return -1*Aerodynamics->GetvFs(3)/MassBalance->GetWeight();
 }
 
 }
 
-/******************************************************************************/
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-void FGAircraft::ReadMetrics(FGConfigFile* AC_cfg) {
+bool FGAircraft::Load(FGConfigFile* AC_cfg)
+{
   string token = "";
   string parameter;
   string token = "";
   string parameter;
+  double EW, bixx, biyy, bizz, bixy, bixz;
+  double pmWt, pmX, pmY, pmZ;
+  FGColumnVector3 vbaseXYZcg;
 
   AC_cfg->GetNextConfigLine();
 
 
   AC_cfg->GetNextConfigLine();
 
-  while ((token = AC_cfg->GetValue()) != "/METRICS") {
+  while ((token = AC_cfg->GetValue()) != string("/METRICS")) {
     *AC_cfg >> parameter;
     if (parameter == "AC_WINGAREA") {
     *AC_cfg >> parameter;
     if (parameter == "AC_WINGAREA") {
-        *AC_cfg >> WingArea;
-        cout << "    WingArea: " << WingArea  << endl; 
+      *AC_cfg >> WingArea;
+      if (debug_lvl > 0) cout << "    WingArea: " << WingArea  << endl;
     } else if (parameter == "AC_WINGSPAN") {
     } else if (parameter == "AC_WINGSPAN") {
-        *AC_cfg >> WingSpan;
-        cout << "    WingSpan: " << WingSpan  << endl;
+      *AC_cfg >> WingSpan;
+      if (debug_lvl > 0) cout << "    WingSpan: " << WingSpan  << endl;
+    } else if (parameter == "AC_WINGINCIDENCE") {
+      *AC_cfg >> WingIncidence;
+      if (debug_lvl > 0) cout << "    Chord: " << cbar << endl;
     } else if (parameter == "AC_CHORD") {
     } else if (parameter == "AC_CHORD") {
-        *AC_cfg >> cbar;
-        cout << "    Chord: " << cbar << endl;
+      *AC_cfg >> cbar;
+      if (debug_lvl > 0) cout << "    Chord: " << cbar << endl;
+    } else if (parameter == "AC_HTAILAREA") {
+      *AC_cfg >> HTailArea;
+      if (debug_lvl > 0) cout << "    H. Tail Area: " << HTailArea << endl;
+    } else if (parameter == "AC_HTAILARM") {
+      *AC_cfg >> HTailArm;
+      if (debug_lvl > 0) cout << "    H. Tail Arm: " << HTailArm << endl;
+    } else if (parameter == "AC_VTAILAREA") {
+      *AC_cfg >> VTailArea;
+      if (debug_lvl > 0) cout << "    V. Tail Area: " << VTailArea << endl;
+    } else if (parameter == "AC_VTAILARM") {
+      *AC_cfg >> VTailArm;
+      if (debug_lvl > 0) cout << "    V. Tail Arm: " << VTailArm << endl;
     } else if (parameter == "AC_IXX") {
     } else if (parameter == "AC_IXX") {
-        *AC_cfg >> baseIxx;
-        cout << "    baseIxx: " << baseIxx << endl;
+      *AC_cfg >> bixx;
+      if (debug_lvl > 0) cout << "    baseIxx: " << bixx << endl;
+      MassBalance->SetBaseIxx(bixx);
     } else if (parameter == "AC_IYY") {
     } else if (parameter == "AC_IYY") {
-        *AC_cfg >> baseIyy;
-        cout << "    baseIyy: " << baseIyy << endl;
-    } else if (parameter == "AC_IZZ") { 
-        *AC_cfg >> baseIzz;
-        cout << "    baseIzz: " << baseIzz << endl;
-    } else if (parameter == "AC_IXZ") { 
-        *AC_cfg >> baseIxz;
-        cout << "    baseIxz: " << baseIxz  << endl;
+      *AC_cfg >> biyy;
+      if (debug_lvl > 0) cout << "    baseIyy: " << biyy << endl;
+      MassBalance->SetBaseIyy(biyy);
+    } else if (parameter == "AC_IZZ") {
+      *AC_cfg >> bizz;
+      if (debug_lvl > 0) cout << "    baseIzz: " << bizz << endl;
+      MassBalance->SetBaseIzz(bizz);
+    } else if (parameter == "AC_IXY") {
+      *AC_cfg >> bixy;
+      if (debug_lvl > 0) cout << "    baseIxy: " << bixy  << endl;
+      MassBalance->SetBaseIxy(bixy);
+    } else if (parameter == "AC_IXZ") {
+      *AC_cfg >> bixz;
+      if (debug_lvl > 0) cout << "    baseIxz: " << bixz  << endl;
+      MassBalance->SetBaseIxz(bixz);
     } else if (parameter == "AC_EMPTYWT") {
     } else if (parameter == "AC_EMPTYWT") {
-        *AC_cfg >> EmptyWeight;
-        cout << "    EmptyWeight: " << EmptyWeight  << endl;
+      *AC_cfg >> EW;
+      MassBalance->SetEmptyWeight(EW);
+      if (debug_lvl > 0) cout << "    EmptyWeight: " << EW  << endl;
     } else if (parameter == "AC_CGLOC") {
     } else if (parameter == "AC_CGLOC") {
-        *AC_cfg >> vbaseXYZcg(eX) >> vbaseXYZcg(eY) >> vbaseXYZcg(eZ);
-        cout << "    CG (x, y, z): " << vbaseXYZcg << endl;
+      *AC_cfg >> vbaseXYZcg(eX) >> vbaseXYZcg(eY) >> vbaseXYZcg(eZ);
+      MassBalance->SetBaseCG(vbaseXYZcg);
+      if (debug_lvl > 0) cout << "    CG (x, y, z): " << vbaseXYZcg << endl;
     } else if (parameter == "AC_EYEPTLOC") {
     } else if (parameter == "AC_EYEPTLOC") {
-        *AC_cfg >> vXYZep(eX) >> vXYZep(eY) >> vXYZep(eZ);
-        cout << "    Eyepoint (x, y, z): " << vXYZep << endl;
+      *AC_cfg >> vXYZep(eX) >> vXYZep(eY) >> vXYZep(eZ);
+      if (debug_lvl > 0) cout << "    Eyepoint (x, y, z): " << vXYZep << endl;
     } else if (parameter == "AC_AERORP") {
     } else if (parameter == "AC_AERORP") {
-        *AC_cfg >> vXYZrp(eX) >> vXYZrp(eY) >> vXYZrp(eZ);
-        cout << "    Ref Pt (x, y, z): " << vXYZrp << endl;
-    } else if (parameter == "AC_ALPHALIMITS") {
-        *AC_cfg >> alphaclmin >> alphaclmax;
-        cout << "    Maximum Alpha: " << alphaclmax
-             << "    Minimum Alpha: " << alphaclmin 
-             << endl;
-    }         
-  }
-}
-
-/******************************************************************************/
-
-void FGAircraft::ReadPropulsion(FGConfigFile* AC_cfg) {
-  string token;
-  string engine_name;
-  string parameter;
-
-  AC_cfg->GetNextConfigLine();
-
-  while ((token = AC_cfg->GetValue()) != "/PROPULSION") {
-    *AC_cfg >> parameter;
-
-    if (parameter == "AC_ENGINE") {
-
-      *AC_cfg >> engine_name;
-      Engine[numEngines] = new FGEngine(FDMExec, EnginePath, engine_name, numEngines);
-      numEngines++;
-
-    } else if (parameter == "AC_TANK") {
-
-      Tank[numTanks] = new FGTank(AC_cfg);
-      switch(Tank[numTanks]->GetType()) {
-      case FGTank::ttFUEL:
-        numSelectedFuelTanks++;
-        break;
-      case FGTank::ttOXIDIZER:
-        numSelectedOxiTanks++;
-        break;
-      }
-      numTanks++;
+      *AC_cfg >> vXYZrp(eX) >> vXYZrp(eY) >> vXYZrp(eZ);
+      if (debug_lvl > 0) cout << "    Ref Pt (x, y, z): " << vXYZrp << endl;
+    } else if (parameter == "AC_POINTMASS") {
+      *AC_cfg >> pmWt >> pmX >> pmY >> pmZ;
+      MassBalance->AddPointMass(pmWt, pmX, pmY, pmZ);
+      if (debug_lvl > 0) cout << "    Point Mass Object: " << pmWt << " lbs. at "
+                         << "X, Y, Z (in.): " << pmX << "  " << pmY << "  " << pmZ
+                         << endl;
     }
   }
     }
   }
-}
-
-/******************************************************************************/
-
-void FGAircraft::ReadFlightControls(FGConfigFile* AC_cfg) {
-  string token;
-
-  FCS->LoadFCS(AC_cfg);
-}
-
-/******************************************************************************/
-
-void FGAircraft::ReadAerodynamics(FGConfigFile* AC_cfg) {
-  string token, axis;
-
-  AC_cfg->GetNextConfigLine();
   
   
-  while ((token = AC_cfg->GetValue()) != "/AERODYNAMICS") {
-    if (token == "AXIS") {
-      CoeffArray ca;
-      axis = AC_cfg->GetValue("NAME");
-      AC_cfg->GetNextConfigLine();
-      while ((token = AC_cfg->GetValue()) != "/AXIS") {
-        ca.push_back(new FGCoefficient(FDMExec, AC_cfg));
-        DisplayCoeffFactors(ca.back()->Getmultipliers());
-      }
-      Coeff[AxisIdx[axis]]=ca;
-      AC_cfg->GetNextConfigLine();
+  // calculate some derived parameters
+  if (cbar != 0.0) {
+    lbarh = HTailArm/cbar;
+    lbarv = VTailArm/cbar;
+    if (WingArea != 0.0) {
+      vbarh = HTailArm*HTailArea / (cbar*WingArea);
+      vbarv = VTailArm*VTailArea / (cbar*WingArea);
     }
     }
-  }
+  }     
+  return true;
 }
 
 }
 
-/******************************************************************************/
-
-void FGAircraft::ReadUndercarriage(FGConfigFile* AC_cfg) {
-  string token;
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-  AC_cfg->GetNextConfigLine();
-
-  while ((token = AC_cfg->GetValue()) != "/UNDERCARRIAGE") {
-    lGear.push_back(FGLGear(AC_cfg, FDMExec));
-  }
+void FGAircraft::bind(void)
+{
+  typedef double (FGAircraft::*PMF)(int) const;
+  PropertyManager->Tie("metrics/Sw-sqft", this,
+                       &FGAircraft::GetWingArea);
+  PropertyManager->Tie("metrics/bw-ft", this,
+                       &FGAircraft::GetWingSpan);
+  PropertyManager->Tie("metrics/cbarw-ft", this,
+                       &FGAircraft::Getcbar);
+  PropertyManager->Tie("metrics/iw-deg", this,
+                       &FGAircraft::GetWingIncidence);
+  PropertyManager->Tie("metrics/Sh-sqft", this,
+                       &FGAircraft::GetHTailArea);
+  PropertyManager->Tie("metrics/lh-ft", this,
+                       &FGAircraft::GetHTailArm);
+  PropertyManager->Tie("metrics/Sv-sqft", this,
+                       &FGAircraft::GetVTailArea);
+  PropertyManager->Tie("metrics/lv-ft", this,
+                       &FGAircraft::GetVTailArm);
+  PropertyManager->Tie("metrics/lh-norm", this,
+                       &FGAircraft::Getlbarh);
+  PropertyManager->Tie("metrics/lv-norm", this,
+                       &FGAircraft::Getlbarv);
+  PropertyManager->Tie("metrics/vbarh-norm", this,
+                       &FGAircraft::Getvbarh);
+  PropertyManager->Tie("metrics/vbarv-norm", this,
+                       &FGAircraft::Getvbarv);
+  PropertyManager->Tie("moments/l-total-lbsft", this,1,
+                       (PMF)&FGAircraft::GetMoments);
+  PropertyManager->Tie("moments/m-total-lbsft", this,2,
+                       (PMF)&FGAircraft::GetMoments);
+  PropertyManager->Tie("moments/n-total-lbsft", this,3,
+                       (PMF)&FGAircraft::GetMoments);
+  PropertyManager->Tie("forces/fbx-total-lbs", this,1,
+                       (PMF)&FGAircraft::GetForces);
+  PropertyManager->Tie("forces/fby-total-lbs", this,2,
+                       (PMF)&FGAircraft::GetForces);
+  PropertyManager->Tie("forces/fbz-total-lbs", this,3,
+                       (PMF)&FGAircraft::GetForces);
+  PropertyManager->Tie("metrics/aero-rp-x-ft", this,1,
+                       (PMF)&FGAircraft::GetXYZrp);
+  PropertyManager->Tie("metrics/aero-rp-y-ft", this,2,
+                       (PMF)&FGAircraft::GetXYZrp);
+  PropertyManager->Tie("metrics/aero-rp-z-ft", this,3,
+                       (PMF)&FGAircraft::GetXYZrp);
+  PropertyManager->Tie("metrics/eyepoint-x-ft", this,1,
+                       (PMF)&FGAircraft::GetXYZep);
+  PropertyManager->Tie("metrics/eyepoint-y-ft", this,2,
+                       (PMF)&FGAircraft::GetXYZep);
+  PropertyManager->Tie("metrics/eyepoint-z-ft", this,3,
+                       (PMF)&FGAircraft::GetXYZep);
 }
 
 }
 
-/******************************************************************************/
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
-void FGAircraft::ReadOutput(FGConfigFile* AC_cfg) {
-  string token, parameter;
-  int OutRate = 0;
-  int subsystems = 0;
+void FGAircraft::unbind(void)
+{
+  PropertyManager->Untie("metrics/Sw-sqft");
+  PropertyManager->Untie("metrics/bw-ft");
+  PropertyManager->Untie("metrics/cbarw-ft");
+  PropertyManager->Untie("metrics/iw-deg");
+  PropertyManager->Untie("metrics/Sh-sqft");
+  PropertyManager->Untie("metrics/lh-ft");
+  PropertyManager->Untie("metrics/Sv-sqft");
+  PropertyManager->Untie("metrics/lv-ft");
+  PropertyManager->Untie("metrics/lh-norm");
+  PropertyManager->Untie("metrics/lv-norm");
+  PropertyManager->Untie("metrics/vbarh-norm");
+  PropertyManager->Untie("metrics/vbarv-norm");
+  PropertyManager->Untie("moments/l-total-lbsft");
+  PropertyManager->Untie("moments/m-total-lbsft");
+  PropertyManager->Untie("moments/n-total-lbsft");
+  PropertyManager->Untie("forces/fbx-total-lbs");
+  PropertyManager->Untie("forces/fby-total-lbs");
+  PropertyManager->Untie("forces/fbz-total-lbs");
+  PropertyManager->Untie("metrics/aero-rp-x-ft");
+  PropertyManager->Untie("metrics/aero-rp-y-ft");
+  PropertyManager->Untie("metrics/aero-rp-z-ft");
+  PropertyManager->Untie("metrics/eyepoint-x-ft");
+  PropertyManager->Untie("metrics/eyepoint-y-ft");
+  PropertyManager->Untie("metrics/eyepoint-z-ft");
+}
 
 
-  token = AC_cfg->GetValue("NAME");
-  Output->SetFilename(token);
-  token = AC_cfg->GetValue("TYPE");
-  Output->SetType(token);
-  AC_cfg->GetNextConfigLine();
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//    The bitmasked value choices are as follows:
+//    unset: In this case (the default) JSBSim would only print
+//       out the normally expected messages, essentially echoing
+//       the config files as they are read. If the environment
+//       variable is not set, debug_lvl is set to 1 internally
+//    0: This requests JSBSim not to output any messages
+//       whatsoever.
+//    1: This value explicity requests the normal JSBSim
+//       startup messages
+//    2: This value asks for a message to be printed out when
+//       a class is instantiated
+//    4: When this value is set, a message is displayed when a
+//       FGModel object executes its Run() method
+//    8: When this value is set, various runtime state variables
+//       are printed out periodically
+//    16: When set various parameters are sanity checked and
+//       a message is printed out when they go out of bounds
+
+void FGAircraft::Debug(int from)
+{
+  if (debug_lvl <= 0) return;
 
 
-  while ((token = AC_cfg->GetValue()) != "/OUTPUT") {
-    *AC_cfg >> parameter;
-    if (parameter == "RATE_IN_HZ") *AC_cfg >> OutRate;
-    if (parameter == "SIMULATION") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssSimulation;
-    }
-    if (parameter == "AEROSURFACES") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssAerosurfaces;
-    }
-    if (parameter == "RATES") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssRates;
-    }
-    if (parameter == "VELOCITIES") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssVelocities;
-    }
-    if (parameter == "FORCES") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssForces;
-    }
-    if (parameter == "MOMENTS") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssMoments;
-    }
-    if (parameter == "ATMOSPHERE") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssAtmosphere;
-    }
-    if (parameter == "MASSPROPS") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssMassProps;
-    }
-    if (parameter == "POSITION") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssPosition;
-    }
-    if (parameter == "COEFFICIENTS") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssCoefficients;
-    }
-    if (parameter == "GROUND_REACTIONS") {
-      *AC_cfg >> parameter;
-      if (parameter == "ON") subsystems += ssGroundReactions;
+  if (debug_lvl & 1) { // Standard console startup message output
+    if (from == 0) { // Constructor
     }
   }
     }
   }
-
-  Output->SetSubsystems(subsystems);
-
-  OutRate = OutRate>120?120:(OutRate<0?0:OutRate);
-  Output->SetRate( (int)(0.5 + 1.0/(State->Getdt()*OutRate)) );
-}
-
-/******************************************************************************/
-
-void FGAircraft::ReadPrologue(FGConfigFile* AC_cfg) {
-  string token = AC_cfg->GetValue();
-  string scratch;
-  AircraftName = AC_cfg->GetValue("NAME");
-  cout << "Reading Aircraft Configuration File: " << AircraftName << endl;
-  scratch=AC_cfg->GetValue("VERSION").c_str();
-
-  CFGVersion = AC_cfg->GetValue("VERSION");
-  cout << "                            Version: " << CFGVersion << endl;
-  if (CFGVersion != NEEDED_CFG_VERSION) {
-    cout << endl << "YOU HAVE AN INCOMPATIBLE CFG FILE FOR THIS AIRCRAFT."
-    " RESULTS WILL BE UNPREDICTABLE !!" << endl;
-    cout << "Current version needed is: " << NEEDED_CFG_VERSION << endl;
-    cout << "         You have version: " << CFGVersion << endl << endl;
-    //exit(-1);
+  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+    if (from == 0) cout << "Instantiated: FGAircraft" << endl;
+    if (from == 1) cout << "Destroyed:    FGAircraft" << endl;
   }
   }
-
-
-}
-
-/******************************************************************************/
-
-void FGAircraft::DisplayCoeffFactors(vector <eParam> multipliers) {
-  cout << "   Non-Dimensionalized by: ";
-
-  for (unsigned int i=0; i<multipliers.size();i++)
-    cout << State->paramdef[multipliers[i]];
-
-  cout << endl;
-}
-
-/******************************************************************************/
-
-string FGAircraft::GetCoefficientStrings(void) {
-  string CoeffStrings = "";
-  bool firstime = true;
-
-  for (unsigned int axis = 0; axis < 6; axis++) {
-    for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
-      if (firstime) {
-        firstime = false;
-      } else {
-        CoeffStrings += ", ";
-      }
-      CoeffStrings += Coeff[axis][sd]->Getname();
-    }
+  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
   }
   }
-
-  return CoeffStrings;
-}
-
-/******************************************************************************/
-
-string FGAircraft::GetCoefficientValues(void) {
-  string SDValues = "";
-  char buffer[10];
-  bool firstime = true;
-
-  for (unsigned int axis = 0; axis < 6; axis++) {
-    for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
-      if (firstime) {
-        firstime = false;
-      } else {
-        SDValues += ", ";
-      }
-      sprintf(buffer, "%9.6f", Coeff[axis][sd]->GetSD());
-      SDValues += string(buffer);
-    }
+  if (debug_lvl & 8 ) { // Runtime state variables
   }
   }
-
-  return SDValues;
-  ;
-}
-
-/******************************************************************************/
-
-string FGAircraft::GetGroundReactionStrings(void) {
-  string GroundReactionStrings = "";
-  bool firstime = true;
-
-  for (unsigned int i=0;i<lGear.size();i++) {
-    if (!firstime) GroundReactionStrings += ", ";
-    GroundReactionStrings += (lGear[i].GetName() + "_WOW, ");
-    GroundReactionStrings += (lGear[i].GetName() + "_compressLength, ");
-    GroundReactionStrings += (lGear[i].GetName() + "_compressSpeed, ");
-    GroundReactionStrings += (lGear[i].GetName() + "_Force");
-
-    firstime = false;
+  if (debug_lvl & 16) { // Sanity checking
   }
   }
-
-  return GroundReactionStrings;
-}
-
-/******************************************************************************/
-
-string FGAircraft::GetGroundReactionValues(void) {
-  char buff[20];
-  string GroundReactionValues = "";
-
-  bool firstime = true;
-
-  for (unsigned int i=0;i<lGear.size();i++) {
-    if (!firstime) GroundReactionValues += ", ";
-    GroundReactionValues += string( lGear[i].GetWOW()?"1":"0" ) + ", ";
-    GroundReactionValues += (string(gcvt(lGear[i].GetCompLen(),    5, buff)) + ", ");
-    GroundReactionValues += (string(gcvt(lGear[i].GetCompVel(),    6, buff)) + ", ");
-    GroundReactionValues += (string(gcvt(lGear[i].GetCompForce(), 10, buff)));
-
-    firstime = false;
+  if (debug_lvl & 64) {
+    if (from == 0) { // Constructor
+      cout << IdSrc << endl;
+      cout << IdHdr << endl;
+    }
   }
   }
-
-  return GroundReactionValues;
 }
 
 }