]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/models/FGMassBalance.cpp
sync with JSB JSBSim CVS
[flightgear.git] / src / FDM / JSBSim / models / FGMassBalance.cpp
index f39e97a65cb1eef8839af06a097973d6525ab9eb..dbd8ab3a64565c40fa7b0ac28d4bab5bcd69a30c 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
@@ -38,13 +38,18 @@ HISTORY
 INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
 #include "FGMassBalance.h"
-#include "FGPropulsion.h"
-#include <input_output/FGPropertyManager.h>
+#include "FGFDMExec.h"
+#include "input_output/FGPropertyManager.h"
+
+using namespace std;
 
 namespace JSBSim {
 
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGMassBalance.cpp,v 1.39 2011/11/09 21:58:26 bcoconni Exp $";
 static const char *IdHdr = ID_MASSBALANCE;
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -58,6 +63,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();
@@ -72,19 +80,32 @@ FGMassBalance::FGMassBalance(FGFDMExec* fdmex) : FGModel(fdmex)
 
 FGMassBalance::~FGMassBalance()
 {
-  unbind();
+  for (unsigned int i=0; i<PointMasses.size(); i++) delete PointMasses[i];
   PointMasses.clear();
+
   Debug(1);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+bool FGMassBalance::InitModel(void)
+{
+  vLastXYZcg.InitMatrix(0.0);
+  vDeltaXYZcg.InitMatrix(0.0);
+
+  return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
 bool FGMassBalance::Load(Element* el)
 {
   Element *element;
   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");
@@ -98,10 +119,12 @@ bool FGMassBalance::Load(Element* el)
     bixz = el->FindElementValueAsNumberConvertTo("ixz", "SLUG*FT2");
   if (el->FindElement("iyz"))
     biyz = el->FindElementValueAsNumberConvertTo("iyz", "SLUG*FT2");
-  SetAircraftBaseInertias(FGMatrix33(  bixx,  -bixy,  -bixz,
+  SetAircraftBaseInertias(FGMatrix33(  bixx,  -bixy,  bixz,
                                       -bixy,  biyy,  -biyz,
-                                      -bixz,  -biyz,  bizz ));
-  EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
+                                       bixz,  -biyz,  bizz ));
+  if (el->FindElement("emptywt")) {
+    EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
+  }
 
   element = el->FindElement("location");
   while (element) {
@@ -119,28 +142,58 @@ 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 + in.TanksWeight + GetTotalPointMassWeight()
+    + in.GasMass*slugtolb + ChildFDMWeight;
+
+  Mass = lbtoslug*Weight;
+
+  PostLoad(el, PropertyManager);
+
   Debug(2);
   return true;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-bool FGMassBalance::Run(void)
+bool FGMassBalance::Run(bool Holding)
 {
   double denom, k1, k2, k3, k4, k5, k6;
   double Ixx, Iyy, Izz, Ixy, Ixz, Iyz;
 
-  if (FGModel::Run()) return true;
-  if (FDMExec->Holding()) return false;
+  if (FGModel::Run(Holding)) return true;
+  if (Holding) return false;
 
-  Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight();
+  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 + in.TanksWeight + GetTotalPointMassWeight()
+    + in.GasMass*slugtolb + ChildFDMWeight;
 
   Mass = lbtoslug*Weight;
 
 // Calculate new CG
 
-  vXYZcg = (Propulsion->GetTanksMoment() + EmptyWeight*vbaseXYZcg
-                                     + GetPointMassMoment() ) / Weight;
+  vXYZcg = (EmptyWeight*vbaseXYZcg
+            + GetPointMassMoment()
+            + in.TanksMoment
+            + in.GasMoment) / 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
 
@@ -150,7 +203,8 @@ bool FGMassBalance::Run(void)
   mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
   // Then add the contributions from the additional pointmasses.
   mJ += CalculatePMInertias();
-  mJ += Propulsion->CalculateTankInertias();
+  mJ += in.TankInertia;
+  mJ += in.GasInertia;
 
   Ixx = mJ(1,1);
   Iyy = mJ(2,2);
@@ -177,6 +231,8 @@ bool FGMassBalance::Run(void)
                     k2, k4, k5,
                     k3, k5, k6 );
 
+  RunPostFunctions();
+
   Debug(0);
 
   return false;
@@ -186,6 +242,7 @@ bool FGMassBalance::Run(void)
 
 void FGMassBalance::AddPointMass(Element* el)
 {
+  double radius=0, length=0;
   Element* loc_element = el->FindElement("location");
   string pointmass_name = el->GetAttributeValue("name");
   if (!loc_element) {
@@ -195,36 +252,70 @@ void FGMassBalance::AddPointMass(Element* el)
 
   double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
   FGColumnVector3 vXYZ = loc_element->FindElementTripletConvertTo("IN");
-  PointMasses.push_back(PointMass(w, vXYZ));
+
+  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 {
+    }
+  }
+
+  pm->bind(PropertyManager, PointMasses.size());
+  PointMasses.push_back(pm);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-double FGMassBalance::GetPointMassWeight(void)
+double FGMassBalance::GetTotalPointMassWeight(void) const
 {
   double PM_total_weight = 0.0;
 
   for (unsigned int i=0; i<PointMasses.size(); i++) {
-    PM_total_weight += PointMasses[i].Weight;
+    PM_total_weight += PointMasses[i]->Weight;
   }
   return PM_total_weight;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGColumnVector3& FGMassBalance::GetPointMassMoment(void)
+const FGColumnVector3& FGMassBalance::GetPointMassMoment(void)
 {
   PointMassCG.InitMatrix();
 
   for (unsigned int i=0; i<PointMasses.size(); i++) {
-    PointMassCG += PointMasses[i].Weight*PointMasses[i].Location;
+    PointMassCG += PointMasses[i]->Weight*PointMasses[i]->Location;
   }
   return PointMassCG;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGMatrix33& FGMassBalance::CalculatePMInertias(void)
+const FGMatrix33& FGMassBalance::CalculatePMInertias(void)
 {
   unsigned int size;
 
@@ -233,8 +324,10 @@ FGMatrix33& FGMassBalance::CalculatePMInertias(void)
 
   pmJ = FGMatrix33();
 
-  for (unsigned int i=0; i<size; i++)
-    pmJ += GetPointmassInertia( lbtoslug * PointMasses[i].Weight, PointMasses[i].Location );
+  for (unsigned int i=0; i<size; i++) {
+    pmJ += GetPointmassInertia( lbtoslug * PointMasses[i]->Weight, PointMasses[i]->Location );
+    pmJ += PointMasses[i]->GetPointMassInertia();
+  }
 
   return pmJ;
 }
@@ -281,6 +374,8 @@ void FGMassBalance::bind(void)
                        &FGMassBalance::GetMass);
   PropertyManager->Tie("inertia/weight-lbs", this,
                        &FGMassBalance::GetWeight);
+  PropertyManager->Tie("inertia/empty-weight-lbs", this,
+                       &FGMassBalance::GetEmptyWeight);
   PropertyManager->Tie("inertia/cg-x-in", this,1,
                        (PMF)&FGMassBalance::GetXYZcg);
   PropertyManager->Tie("inertia/cg-y-in", this,2,
@@ -289,15 +384,64 @@ 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::unbind(void)
+void FGMassBalance::GetMassPropertiesReport(void) const
 {
-  PropertyManager->Untie("inertia/mass-slugs");
-  PropertyManager->Untie("inertia/weight-lbs");
-  PropertyManager->Untie("inertia/cg-x-in");
-  PropertyManager->Untie("inertia/cg-y-in");
-  PropertyManager->Untie("inertia/cg-z-in");
+  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;
+  }
+
+  cout << FDMExec->GetPropulsionTankReport();
+
+  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);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -332,14 +476,14 @@ 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++) {
-        cout << "    Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
-                   << "X, Y, Z (in.): " << PointMasses[i].Location(eX) << "  "
-                   << PointMasses[i].Location(eY) << "  "
-                   << PointMasses[i].Location(eZ) << endl;
+        cout << "    Point Mass Object: " << PointMasses[i]->Weight << " lbs. at "
+                   << "X, Y, Z (in.): " << PointMasses[i]->Location(eX) << "  "
+                   << PointMasses[i]->Location(eY) << "  "
+                   << PointMasses[i]->Location(eZ) << endl;
       }
     }
   }