fggascell.cpp

来自「6 DOF Missle Simulation」· C++ 代码 · 共 873 行 · 第 1/3 页

CPP
873
字号
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Header:       FGGasCell.h Author:       Anders Gidenstam Date started: 01/21/2006 ----- Copyright (C) 2006 - 2008  Anders Gidenstam (anders(at)gidenstam.org) -- This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. Further information about the GNU Lesser General Public License can also be found on the world wide web at http://www.gnu.org.FUNCTIONAL DESCRIPTION--------------------------------------------------------------------------------See header file.HISTORY--------------------------------------------------------------------------------01/21/2006  AG   Created%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%INCLUDES%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/#include <FGFDMExec.h>#include <models/FGAuxiliary.h>#include <models/FGAtmosphere.h>#include <models/FGInertial.h>#include <models/FGMassBalance.h>#include "FGGasCell.h"using std::cerr;using std::endl;using std::cout;namespace JSBSim {static const char *IdSrc = "$Id$";static const char *IdHdr = ID_GASCELL;/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%CLASS IMPLEMENTATION%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*//* Constants. */const double FGGasCell::R = 3.4071;              // [lbs ft/(mol Rankine)]const double FGGasCell::M_air = 0.0019186;       // [slug/mol]const double FGGasCell::M_hydrogen = 0.00013841; // [slug/mol]const double FGGasCell::M_helium = 0.00027409;   // [slug/mol]FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, int num) : FGForce(exec){  string token;  Element* element;  Auxiliary = exec->GetAuxiliary();  Atmosphere = exec->GetAtmosphere();  PropertyManager = exec->GetPropertyManager();  Inertial = exec->GetInertial();  MassBalance = exec->GetMassBalance();  gasCellJ = FGMatrix33();  gasCellM = FGColumnVector3();  Buoyancy = MaxVolume = MaxOverpressure = Temperature = Pressure =    Contents = Volume = dVolumeIdeal = 0.0;  Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;  ValveCoefficient = ValveOpen = 0.0;  CellNum = num;  // NOTE: In the local system X points north, Y points east and Z points down.  SetTransformType(FGForce::tLocalBody);  type = el->GetAttributeValue("type");  if      (type == "HYDROGEN") Type = ttHYDROGEN;  else if (type == "HELIUM")   Type = ttHELIUM;  else if (type == "AIR")      Type = ttAIR;  else                         Type = ttUNKNOWN;  element = el->FindElement("location");  if (element) {    vXYZ = element->FindElementTripletConvertTo("IN");  } else {    cerr << "Fatal Error: No location found for this gas cell." << endl;    exit(-1);  }  if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&      (el->FindElement("y_radius") || el->FindElement("y_width")) &&      (el->FindElement("z_radius") || el->FindElement("z_width"))) {    if (el->FindElement("x_radius")) {      Xradius = el->FindElementValueAsNumberConvertTo("x_radius", "FT");    }    if (el->FindElement("y_radius")) {      Yradius = el->FindElementValueAsNumberConvertTo("y_radius", "FT");    }    if (el->FindElement("z_radius")) {      Zradius = el->FindElementValueAsNumberConvertTo("z_radius", "FT");    }    if (el->FindElement("x_width")) {      Xwidth = el->FindElementValueAsNumberConvertTo("x_width", "FT");    }    if (el->FindElement("y_width")) {      Ywidth = el->FindElementValueAsNumberConvertTo("y_width", "FT");    }    if (el->FindElement("z_width")) {      Zwidth = el->FindElementValueAsNumberConvertTo("z_width", "FT");    }    // The volume is a (potentially) extruded ellipsoid.    // However, currently only a few combinations of radius and width are    // fully supported.    if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&        (Xwidth  == 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {      // Ellipsoid volume.      MaxVolume = 4.0  * M_PI * Xradius * Yradius * Zradius / 3.0;    } else if  ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&                (Xwidth  != 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {      // Cylindrical volume.      MaxVolume = M_PI * Yradius * Zradius * Xwidth;    } else {      cerr << "Warning: Unsupported gas cell shape." << endl;      MaxVolume =         (4.0  * M_PI * Xradius * Yradius * Zradius / 3.0 +         M_PI * Yradius * Zradius * Xwidth +         M_PI * Xradius * Zradius * Ywidth +         M_PI * Xradius * Yradius * Zwidth +         2.0  * Xradius * Ywidth * Zwidth +         2.0  * Yradius * Xwidth * Zwidth +         2.0  * Zradius * Xwidth * Ywidth +         Xwidth * Ywidth * Zwidth);    }  } else {    cerr << "Fatal Error: Gas cell shape must be given." << endl;    exit(-1);  }  if (el->FindElement("max_overpressure")) {    MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",                                                            "LBS/FT2");  }  if (el->FindElement("fullness")) {    const double Fullness = el->FindElementValueAsNumber("fullness");    if (0 <= Fullness) {       Volume = Fullness * MaxVolume;     } else {      cerr << "Warning: Invalid initial gas cell fullness value." << endl;    }  }    if (el->FindElement("valve_coefficient")) {    ValveCoefficient =      el->FindElementValueAsNumberConvertTo("valve_coefficient",                                            "FT4*SEC/SLUG");    ValveCoefficient = max(ValveCoefficient, 0.0);  }  // Initialize state  SetLocation(vXYZ);  if (Temperature == 0.0) {    Temperature = Atmosphere->GetTemperature();  }  if (Pressure == 0.0) {    Pressure = Atmosphere->GetPressure();  }  if (Volume != 0.0) {    // Calculate initial gas content.    Contents = Pressure * Volume / (R * Temperature);        // Clip to max allowed value.    const double IdealPressure = Contents * R * Temperature / MaxVolume;    if (IdealPressure > Pressure + MaxOverpressure) {      Contents = (Pressure + MaxOverpressure) * MaxVolume / (R * Temperature);      Pressure = Pressure + MaxOverpressure;    } else {      Pressure = max(IdealPressure, Pressure);    }  } else {    // Calculate initial gas content.    Contents = Pressure * MaxVolume / (R * Temperature);  }  Volume = Contents * R * Temperature / Pressure;  Mass = Contents * M_gas();  // Bind relevant properties  char property_name[80];  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/max_volume-ft3",           CellNum);  PropertyManager->Tie( property_name, &MaxVolume );  PropertyManager->SetWritable( property_name, false );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/temp-R",           CellNum);  PropertyManager->Tie( property_name, &Temperature );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/pressure-psf",           CellNum);  PropertyManager->Tie( property_name, &Pressure );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/volume-ft3",           CellNum);  PropertyManager->Tie( property_name, &Volume );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/buoyancy-lbs",           CellNum);  PropertyManager->Tie( property_name, &Buoyancy );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/contents-mol",           CellNum);  PropertyManager->Tie( property_name, &Contents );  snprintf(property_name, 80, "buoyant_forces/gas-cell[%d]/valve_open",           CellNum);  PropertyManager->Tie( property_name, &ValveOpen );  Debug(0);  // Read heat transfer coefficients  if (Element* heat = el->FindElement("heat")) {    Element* function_element = heat->FindElement("function");    while (function_element) {      HeatTransferCoeff.push_back(new FGFunction(PropertyManager,                                                 function_element));      function_element = heat->FindNextElement("function");    }  }  // Load ballonets if there are any  if (Element* ballonet_element = el->FindElement("ballonet")) {    while (ballonet_element) {      Ballonet.push_back(new FGBallonet(exec,                                        ballonet_element,                                        Ballonet.size(),                                        this));      ballonet_element = el->FindNextElement("ballonet");    }  }}//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%FGGasCell::~FGGasCell(){  unsigned int i;  for (i = 0; i < HeatTransferCoeff.size(); i++) delete HeatTransferCoeff[i];  HeatTransferCoeff.clear();  for (i = 0; i < Ballonet.size(); i++) delete Ballonet[i];  Ballonet.clear();  Debug(1);}//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%void FGGasCell::Calculate(double dt){  const double AirTemperature = Atmosphere->GetTemperature();  // [Rankine]  const double AirPressure    = Atmosphere->GetPressure();     // [lbs/ft瞉  const double AirDensity     = Atmosphere->GetDensity();      // [slug/ft砞  const double g = Inertial->gravity();                        // [lbs/slug]  const double OldTemperature = Temperature;  const double OldPressure    = Pressure;  unsigned int i;  const unsigned int no_ballonets = Ballonet.size();  //-- Read ballonet state --  // NOTE: This model might need a more proper integration technique.   double BallonetsVolume = 0.0;  double BallonetsHeatFlow = 0.0;  for (i = 0; i < no_ballonets; i++) {    BallonetsVolume   += Ballonet[i]->GetVolume();    BallonetsHeatFlow += Ballonet[i]->GetHeatFlow();  }  //-- Gas temperature --  if (HeatTransferCoeff.size() > 0) {    // The model is based on the ideal gas law.    // However, it does look a bit fishy. Please verify.    //   dT/dt = dU / (Cv n R)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?