]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/models/FGMassBalance.cpp
Sync. with JSBSim CVS
[flightgear.git] / src / FDM / JSBSim / models / FGMassBalance.cpp
index 69c3a67230064b9d5c945b28728f239e507de1ef..fd067ab5160817aca07f4662c372c379fc78fd38 100644 (file)
@@ -5,7 +5,7 @@
  Date started: 09/12/2000
  Purpose:      This module models weight and balance
 
- ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) --------------
+ ------------- Copyright (C) 2000  Jon S. Berndt (jon@jsbsim.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
@@ -40,12 +40,18 @@ INCLUDES
 
 #include "FGMassBalance.h"
 #include "FGPropulsion.h"
+#include "propulsion/FGTank.h"
 #include "FGBuoyantForces.h"
-#include <input_output/FGPropertyManager.h>
+#include "input_output/FGPropertyManager.h"
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+
+using namespace std;
 
 namespace JSBSim {
 
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.34 2010/11/18 12:38:06 jberndt Exp $";
 static const char *IdHdr = ID_MASSBALANCE;
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -59,6 +65,9 @@ FGMassBalance::FGMassBalance(FGFDMExec* fdmex) : FGModel(fdmex)
   Weight = EmptyWeight = Mass = 0.0;
 
   vbaseXYZcg.InitMatrix(0.0);
+  vXYZcg.InitMatrix(0.0);
+  vLastXYZcg.InitMatrix(0.0);
+  vDeltaXYZcg.InitMatrix(0.0);
   baseJ.InitMatrix();
   mJ.InitMatrix();
   mJinv.InitMatrix();
@@ -85,6 +94,9 @@ bool FGMassBalance::InitModel(void)
 {
   if (!FGModel::InitModel()) return false;
 
+  vLastXYZcg.InitMatrix(0.0);
+  vDeltaXYZcg.InitMatrix(0.0);
+
   return true;
 }
 
@@ -96,6 +108,8 @@ bool FGMassBalance::Load(Element* el)
   string element_name = "";
   double bixx, biyy, bizz, bixy, bixz, biyz;
 
+  FGModel::Load(el); // Perform base class Load.
+
   bixx = biyy = bizz = bixy = bixz = biyz = 0.0;
   if (el->FindElement("ixx"))
     bixx = el->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
@@ -112,7 +126,9 @@ bool FGMassBalance::Load(Element* el)
   SetAircraftBaseInertias(FGMatrix33(  bixx,  -bixy,  bixz,
                                       -bixy,  biyy,  -biyz,
                                        bixz,  -biyz,  bizz ));
-  EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
+  if (el->FindElement("emptywt")) {
+    EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
+  }
 
   element = el->FindElement("location");
   while (element) {
@@ -130,6 +146,18 @@ bool FGMassBalance::Load(Element* el)
     element = el->FindNextElement("pointmass");
   }
 
+  double ChildFDMWeight = 0.0;
+  for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
+    if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
+  }
+
+  Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
+    + FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
+
+  Mass = lbtoslug*Weight;
+
+  PostLoad(el, PropertyManager);
+
   Debug(2);
   return true;
 }
@@ -144,16 +172,31 @@ bool FGMassBalance::Run(void)
   if (FGModel::Run()) return true;
   if (FDMExec->Holding()) return false;
 
-  Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight()
-    + BuoyantForces->GetGasMass()*slugtolb;
+  RunPreFunctions();
+
+  double ChildFDMWeight = 0.0;
+  for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
+    if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
+  }
+
+  Weight = EmptyWeight + FDMExec->GetPropulsion()->GetTanksWeight() + GetTotalPointMassWeight()
+    + FDMExec->GetBuoyantForces()->GetGasMass()*slugtolb + ChildFDMWeight;
 
   Mass = lbtoslug*Weight;
 
 // Calculate new CG
 
-  vXYZcg = (Propulsion->GetTanksMoment() + EmptyWeight*vbaseXYZcg
+  vXYZcg = (FDMExec->GetPropulsion()->GetTanksMoment() + EmptyWeight*vbaseXYZcg
             + GetPointMassMoment()
-            + BuoyantForces->GetGasMassMoment()) / Weight;
+            + FDMExec->GetBuoyantForces()->GetGasMassMoment()) / Weight;
+
+  // Track frame-by-frame delta CG, and move the EOM-tracked location
+  // by this amount.
+  if (vLastXYZcg.Magnitude() == 0.0) vLastXYZcg = vXYZcg;
+  vDeltaXYZcg = vXYZcg - vLastXYZcg;
+  vDeltaXYZcgBody = StructuralToBody(vLastXYZcg) - StructuralToBody(vXYZcg);
+  vLastXYZcg = vXYZcg;
+  FDMExec->GetPropagate()->NudgeBodyLocation(vDeltaXYZcgBody);
 
 // Calculate new total moments of inertia
 
@@ -163,8 +206,8 @@ bool FGMassBalance::Run(void)
   mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
   // Then add the contributions from the additional pointmasses.
   mJ += CalculatePMInertias();
-  mJ += Propulsion->CalculateTankInertias();
-  mJ += BuoyantForces->GetGasMassInertia();
+  mJ += FDMExec->GetPropulsion()->CalculateTankInertias();
+  mJ += FDMExec->GetBuoyantForces()->GetGasMassInertia();
 
   Ixx = mJ(1,1);
   Iyy = mJ(2,2);
@@ -191,6 +234,8 @@ bool FGMassBalance::Run(void)
                     k2, k4, k5,
                     k3, k5, k6 );
 
+  RunPostFunctions();
+
   Debug(0);
 
   return false;
@@ -200,8 +245,7 @@ bool FGMassBalance::Run(void)
 
 void FGMassBalance::AddPointMass(Element* el)
 {
-  char tmp[80];
-
+  double radius=0, length=0;
   Element* loc_element = el->FindElement("location");
   string pointmass_name = el->GetAttributeValue("name");
   if (!loc_element) {
@@ -211,18 +255,46 @@ void FGMassBalance::AddPointMass(Element* el)
 
   double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
   FGColumnVector3 vXYZ = loc_element->FindElementTripletConvertTo("IN");
-  PointMasses.push_back(new PointMass(w, vXYZ));
 
-  int num = PointMasses.size()-1;
+  PointMass *pm = new PointMass(w, vXYZ);
+  pm->SetName(pointmass_name);
+
+  Element* form_element = el->FindElement("form");
+  if (form_element) {
+    string shape = form_element->GetAttributeValue("shape");
+    Element* radius_element = form_element->FindElement("radius");
+    Element* length_element = form_element->FindElement("length");
+    if (radius_element) radius = form_element->FindElementValueAsNumberConvertTo("radius", "FT");
+    if (length_element) length = form_element->FindElementValueAsNumberConvertTo("length", "FT");
+    if (shape == "tube") {
+      pm->SetPointMassShapeType(PointMass::esTube);
+      pm->SetRadius(radius);
+      pm->SetLength(length);
+      pm->CalculateShapeInertia();
+    } else if (shape == "cylinder") {
+      pm->SetPointMassShapeType(PointMass::esCylinder);
+      pm->SetRadius(radius);
+      pm->SetLength(length);
+      pm->CalculateShapeInertia();
+    } else if (shape == "sphere") {
+      pm->SetPointMassShapeType(PointMass::esSphere);
+      pm->SetRadius(radius);
+      pm->CalculateShapeInertia();
+    } else if (shape == "ball") {
+      pm->SetPointMassShapeType(PointMass::esBall);
+      pm->SetRadius(radius);
+      pm->CalculateShapeInertia();
+    } else {
+    }
+  }
 
-  snprintf(tmp, 80, "inertia/pointmass-weight-lbs[%u]", num);
-  PropertyManager->Tie( tmp, this, num, &FGMassBalance::GetPointMassWeight,
-                                        &FGMassBalance::SetPointMassWeight);
+  pm->bind(PropertyManager, PointMasses.size());
+  PointMasses.push_back(pm);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-double FGMassBalance::GetPointMassWeight(void)
+double FGMassBalance::GetTotalPointMassWeight(void)
 {
   double PM_total_weight = 0.0;
 
@@ -255,8 +327,10 @@ FGMatrix33& FGMassBalance::CalculatePMInertias(void)
 
   pmJ = FGMatrix33();
 
-  for (unsigned int i=0; i<size; i++)
+  for (unsigned int i=0; i<size; i++) {
     pmJ += GetPointmassInertia( lbtoslug * PointMasses[i]->Weight, PointMasses[i]->Location );
+    pmJ += PointMasses[i]->GetPointMassInertia();
+  }
 
   return pmJ;
 }
@@ -304,7 +378,7 @@ void FGMassBalance::bind(void)
   PropertyManager->Tie("inertia/weight-lbs", this,
                        &FGMassBalance::GetWeight);
   PropertyManager->Tie("inertia/empty-weight-lbs", this,
-    &FGMassBalance::GetWeight, &FGMassBalance::SetEmptyWeight);
+                       &FGMassBalance::GetEmptyWeight);
   PropertyManager->Tie("inertia/cg-x-in", this,1,
                        (PMF)&FGMassBalance::GetXYZcg);
   PropertyManager->Tie("inertia/cg-y-in", this,2,
@@ -313,6 +387,83 @@ void FGMassBalance::bind(void)
                        (PMF)&FGMassBalance::GetXYZcg);
 }
 
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// This function binds properties for each pointmass object created.
+//
+void FGMassBalance::PointMass::bind(FGPropertyManager* PropertyManager, int num) {
+  string tmp = CreateIndexedPropertyName("inertia/pointmass-weight-lbs", num);
+  PropertyManager->Tie( tmp.c_str(), this, &PointMass::GetPointMassWeight,
+                                       &PointMass::SetPointMassWeight);
+
+  tmp = CreateIndexedPropertyName("inertia/pointmass-location-X-inches", num);
+  PropertyManager->Tie( tmp.c_str(), this, eX, &PointMass::GetPointMassLocation,
+                                           &PointMass::SetPointMassLocation);
+  tmp = CreateIndexedPropertyName("inertia/pointmass-location-Y-inches", num);
+  PropertyManager->Tie( tmp.c_str(), this, eY, &PointMass::GetPointMassLocation,
+                                           &PointMass::SetPointMassLocation);
+  tmp = CreateIndexedPropertyName("inertia/pointmass-location-Z-inches", num);
+  PropertyManager->Tie( tmp.c_str(), this, eZ, &PointMass::GetPointMassLocation,
+                                           &PointMass::SetPointMassLocation);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMassBalance::GetMassPropertiesReport(void) const
+{
+  cout << endl << fgblue << highint 
+       << "  Mass Properties Report (English units: lbf, in, slug-ft^2)"
+       << reset << endl;
+  cout << "                                  " << underon << "    Weight    CG-X    CG-Y"
+       << "    CG-Z         Ixx         Iyy         Izz" << underoff << endl;
+  cout.precision(1);
+  cout << highint << setw(34) << left << "    Base Vehicle " << normint
+       << right << setw(10) << EmptyWeight << setw(8) << vbaseXYZcg(eX) << setw(8)
+       << vbaseXYZcg(eY) << setw(8) << vbaseXYZcg(eZ) << setw(12) << baseJ(1,1)
+       << setw(12) << baseJ(2,2) << setw(12) << baseJ(3,3) << endl;
+
+  for (unsigned int i=0;i<PointMasses.size();i++) {
+    PointMass* pm = PointMasses[i];
+    double pmweight = pm->GetPointMassWeight();
+    cout << highint << left << setw(4) << i << setw(30) << pm->GetName() << normint
+         << right << setw(10) << pmweight << setw(8) << pm->GetLocation()(eX)
+         << setw(8) << pm->GetLocation()(eY) << setw(8) << pm->GetLocation()(eZ)
+         << setw(12) << pm->GetPointMassMoI(1,1) << setw(12) << pm->GetPointMassMoI(2,2)
+         << setw(12) << pm->GetPointMassMoI(3,3) << endl;
+  }
+
+  for (unsigned int i=0;i<FDMExec->GetPropulsion()->GetNumTanks() ;i++) {
+    FGTank* tank = FDMExec->GetPropulsion()->GetTank(i);
+    string tankname="";
+    if (tank->GetType() == FGTank::ttFUEL && tank->GetGrainType() != FGTank::gtUNKNOWN) {
+      tankname = "Solid Fuel";
+    } else if (tank->GetType() == FGTank::ttFUEL) {
+      tankname = "Fuel";
+    } else if (tank->GetType() == FGTank::ttOXIDIZER) {
+      tankname = "Oxidizer";
+    } else {
+      tankname = "(Unknown tank type)";
+    }
+    cout << highint << left << setw(4) << i << setw(30) << tankname << normint
+      << right << setw(10) << tank->GetContents() << setw(8) << tank->GetXYZ(eX)
+         << setw(8) << tank->GetXYZ(eY) << setw(8) << tank->GetXYZ(eZ)
+         << setw(12) << "*" << setw(12) << "*"
+         << setw(12) << "*" << endl;
+  }
+
+  cout << underon << setw(104) << " " << underoff << endl;
+  cout << highint << left << setw(30) << "    Total: " << right << setw(14) << Weight 
+       << setw(8) << vXYZcg(eX)
+       << setw(8) << vXYZcg(eY)
+       << setw(8) << vXYZcg(eZ)
+       << setw(12) << mJ(1,1)
+       << setw(12) << mJ(2,2)
+       << setw(12) << mJ(3,3)
+       << normint << endl;
+
+  cout.setf(ios_base::fixed);
+}
+
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 //    The bitmasked value choices are as follows:
 //    unset: In this case (the default) JSBSim would only print
@@ -345,7 +496,7 @@ void FGMassBalance::Debug(int from)
       cout << "    baseIxy: " << baseJ(1,2) << " slug-ft2" << endl;
       cout << "    baseIxz: " << baseJ(1,3) << " slug-ft2" << endl;
       cout << "    baseIyz: " << baseJ(2,3) << " slug-ft2" << endl;
-      cout << "    EmptyWeight: " << EmptyWeight << " lbm" << endl;
+      cout << "    Empty Weight: " << EmptyWeight << " lbm" << endl;
       cout << "    CG (x, y, z): " << vbaseXYZcg << endl;
       // ToDo: Need to add point mass outputs here
       for (unsigned int i=0; i<PointMasses.size(); i++) {