59 Name =
"FGMassBalance";
60 Weight = EmptyWeight = Mass = 0.0;
62 vbaseXYZcg.InitMatrix();
64 vLastXYZcg.InitMatrix();
65 vDeltaXYZcg.InitMatrix();
81 for(
auto pm: PointMasses)
delete pm;
92 vLastXYZcg.InitMatrix();
93 vDeltaXYZcg.InitMatrix();
102 double bixx, biyy, bizz, bixy, bixz, biyz;
104 bixx = biyy = bizz = bixy = bixz = biyz = 0.0;
120 if (document->
GetAttributeValue(
"negated_crossproduct_inertia") ==
string(
"false"))
134 string element_name =
"";
163 double ChildFDMWeight = 0.0;
164 for (
int fdm=0; fdm<
FDMExec->GetFDMCount(); fdm++) {
165 if (
FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight +=
FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
183 double denom, k1, k2, k3, k4, k5, k6;
184 double Ixx, Iyy, Izz, Ixy, Ixz, Iyz;
187 if (Holding)
return false;
191 double ChildFDMWeight = 0.0;
192 for (
int fdm=0; fdm<
FDMExec->GetFDMCount(); fdm++) {
193 if (
FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight +=
FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
203 vXYZcg = (EmptyWeight*vbaseXYZcg
206 +
in.GasMoment) / Weight;
210 if (vLastXYZcg.Magnitude() == 0.0) vLastXYZcg = vXYZcg;
211 vDeltaXYZcg = vXYZcg - vLastXYZcg;
218 Propagate->NudgeBodyLocation(vDeltaXYZcgBody);
227 mJ += CalculatePMInertias();
228 mJ +=
in.TankInertia;
241 k1 = (Iyy*Izz - Iyz*Iyz);
242 k2 = (Iyz*Ixz + Ixy*Izz);
243 k3 = (Ixy*Iyz + Iyy*Ixz);
245 denom = 1.0/(Ixx*k1 - Ixy*k2 - Ixz*k3 );
249 k4 = (Izz*Ixx - Ixz*Ixz)*denom;
250 k5 = (Ixy*Ixz + Iyz*Ixx)*denom;
251 k6 = (Ixx*Iyy - Ixy*Ixy)*denom;
253 mJinv = { k1, k2, k3,
272 s << el->
ReadFrom() <<
"Pointmass " << pointmass_name
273 <<
" has no location.";
274 cerr << endl << s.str() << endl;
281 PointMass *pm =
new PointMass(w, vXYZ);
282 pm->SetName(pointmass_name);
286 double radius=0, length=0;
292 if (shape ==
"tube") {
293 pm->SetPointMassShapeType(PointMass::esTube);
294 pm->SetRadius(radius);
295 pm->SetLength(length);
296 pm->CalculateShapeInertia();
297 }
else if (shape ==
"cylinder") {
298 pm->SetPointMassShapeType(PointMass::esCylinder);
299 pm->SetRadius(radius);
300 pm->SetLength(length);
301 pm->CalculateShapeInertia();
302 }
else if (shape ==
"sphere") {
303 pm->SetPointMassShapeType(PointMass::esSphere);
304 pm->SetRadius(radius);
305 pm->CalculateShapeInertia();
306 }
else if (shape ==
"ball") {
307 pm->SetPointMassShapeType(PointMass::esBall);
308 pm->SetRadius(radius);
309 pm->CalculateShapeInertia();
314 pm->SetPointMassShapeType(PointMass::esUnspecified);
319 PointMasses.push_back(pm);
326 double PM_total_weight = 0.0;
328 for(
auto pm: PointMasses)
329 PM_total_weight += pm->Weight;
331 return PM_total_weight;
340 for (
auto pm: PointMasses)
341 PointMassCG += pm->Weight * pm->Location;
348const FGMatrix33& FGMassBalance::CalculatePMInertias(
void)
350 if (PointMasses.empty())
return pmJ;
354 for (
auto pm: PointMasses) {
356 pmJ += pm->GetPointMassInertia();
397void FGMassBalance::bind(
void)
413 &FGMassBalance::GetIxx);
415 &FGMassBalance::GetIyy);
417 &FGMassBalance::GetIzz);
419 &FGMassBalance::GetIxy);
421 &FGMassBalance::GetIxz);
423 &FGMassBalance::GetIyz);
433void FGMassBalance::PointMass::bind(FGPropertyManager* PropertyManager,
437 &PointMass::SetPointMassWeight);
441 &PointMass::SetPointMassLocation);
444 &PointMass::SetPointMassLocation);
447 &PointMass::SetPointMassLocation);
455 <<
" Mass Properties Report (English units: lbf, in, slug-ft^2)"
457 cout <<
" " <<
underon <<
" Weight CG-X CG-Y"
458 <<
" CG-Z Ixx Iyy Izz"
459 <<
" Ixy Ixz Iyz" <<
underoff << endl;
461 cout <<
highint << setw(34) << left <<
" Base Vehicle " <<
normint
462 << right << setw(10) << EmptyWeight
463 << setw(8) << vbaseXYZcg(
eX) << setw(8) << vbaseXYZcg(
eY) << setw(8) << vbaseXYZcg(
eZ)
464 << setw(12) << baseJ(1,1) << setw(12) << baseJ(2,2) << setw(12) << baseJ(3,3)
465 << setw(12) << baseJ(1,2) << setw(12) << baseJ(1,3) << setw(12) << baseJ(2,3) << endl;
467 for (
unsigned int i=0;
i<PointMasses.size();
i++) {
468 PointMass* pm = PointMasses[
i];
469 double pmweight = pm->GetPointMassWeight();
470 cout <<
highint << left << setw(4) <<
i << setw(30) << pm->GetName() <<
normint
471 << right << setw(10) << pmweight << setw(8) << pm->GetLocation()(
eX)
472 << setw(8) << pm->GetLocation()(
eY) << setw(8) << pm->GetLocation()(
eZ)
473 << setw(12) << pm->GetPointMassMoI(1,1) << setw(12) << pm->GetPointMassMoI(2,2) << setw(12) << pm->GetPointMassMoI(3,3)
474 << setw(12) << pm->GetPointMassMoI(1,2) << setw(12) << pm->GetPointMassMoI(1,3) << setw(12) << pm->GetPointMassMoI(2,3) << endl;
477 cout <<
FDMExec->GetPropulsionTankReport();
480 cout <<
highint << left << setw(30) <<
" Total: " << right << setw(14) << Weight
481 << setw(8) << vXYZcg(
eX)
482 << setw(8) << vXYZcg(
eY)
483 << setw(8) << vXYZcg(
eZ)
484 << setw(12) << mJ(1,1)
485 << setw(12) << mJ(2,2)
486 << setw(12) << mJ(3,3)
487 << setw(12) << mJ(1,2)
488 << setw(12) << mJ(1,3)
489 << setw(12) << mJ(2,3)
492 cout.setf(ios_base::fixed);
514void FGMassBalance::Debug(
int from)
520 cout << endl <<
" Mass and Balance:" << endl;
521 cout <<
" baseIxx: " << baseJ(1,1) <<
" slug-ft2" << endl;
522 cout <<
" baseIyy: " << baseJ(2,2) <<
" slug-ft2" << endl;
523 cout <<
" baseIzz: " << baseJ(3,3) <<
" slug-ft2" << endl;
524 cout <<
" baseIxy: " << baseJ(1,2) <<
" slug-ft2" << endl;
525 cout <<
" baseIxz: " << baseJ(1,3) <<
" slug-ft2" << endl;
526 cout <<
" baseIyz: " << baseJ(2,3) <<
" slug-ft2" << endl;
527 cout <<
" Empty Weight: " << EmptyWeight <<
" lbm" << endl;
528 cout <<
" CG (x, y, z): " << vbaseXYZcg << endl;
530 for (
unsigned int i=0;
i<PointMasses.size();
i++) {
531 cout <<
" Point Mass Object: " << PointMasses[
i]->Weight <<
" lbs. at "
532 <<
"X, Y, Z (in.): " << PointMasses[
i]->Location(
eX) <<
" "
533 << PointMasses[
i]->Location(
eY) <<
" "
534 << PointMasses[
i]->Location(
eZ) << endl;
539 if (from == 0) cout <<
"Instantiated: FGMassBalance" << endl;
540 if (from == 1) cout <<
"Destroyed: FGMassBalance" << endl;
548 if (EmptyWeight <= 0.0 || EmptyWeight > 1e9)
549 cout <<
"MassBalance::EmptyWeight out of bounds: " << EmptyWeight << endl;
550 if (Weight <= 0.0 || Weight > 1e9)
551 cout <<
"MassBalance::Weight out of bounds: " << Weight << endl;
552 if (Mass <= 0.0 || Mass > 1e9)
553 cout <<
"MassBalance::Mass out of bounds: " << Mass << endl;
double FindElementValueAsNumberConvertTo(const std::string &el, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it.
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Element * FindElement(const std::string &el="")
Searches for a specified element.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
This class implements a 3 element column vector.
FGPropagate * GetPropagate(void)
Returns the FGPropagate pointer.
static constexpr double inchtoft
static constexpr double slugtolb
Note that definition of lbtoslug by the inverse of slugtolb and not to a different constant you can a...
static char highint[5]
highlights text
static char reset[5]
resets text properties
static char fgblue[6]
blue text
static char normint[6]
normal intensity text
static char underoff[6]
underline off
static constexpr double lbtoslug
static char underon[5]
underlines text
static std::string CreateIndexedPropertyName(const std::string &Property, int index)
Models weight, balance and moment of inertia information.
void SetAircraftBaseInertias(const FGMatrix33 &BaseJ)
FGMatrix33 GetPointmassInertia(double mass_sl, const FGColumnVector3 &r) const
Computes the inertia contribution of a pointmass.
bool InitModel(void) override
FGColumnVector3 StructuralToBody(const FGColumnVector3 &r) const
Conversion from the structural frame to the body frame.
double GetEmptyWeight(void) const
FGMassBalance(FGFDMExec *)
double GetWeight(void) const
void AddPointMass(Element *el)
double GetTotalPointMassWeight(void) const
bool Run(bool Holding) override
Runs the Mass Balance model; called by the Executive Can pass in a value indicating if the executive ...
double GetMass(void) const
const FGColumnVector3 & GetXYZcg(void) const
Returns the coordinates of the center of gravity expressed in the structural frame.
const FGColumnVector3 & GetPointMassMoment(void)
struct JSBSim::FGMassBalance::Inputs in
void GetMassPropertiesReport(int i)
bool Load(Element *el) override
Handles matrix math operations.
void InitMatrix(void)
Initialize the matrix.
void RunPostFunctions(void)
void PostLoad(Element *el, FGFDMExec *fdmex, std::string prefix="")
void RunPreFunctions(void)
FGPropertyManager * PropertyManager
bool InitModel(void) override
FGModel(FGFDMExec *)
Constructor.
bool Upload(Element *el, bool preLoad)
Uploads this model in memory.
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
void Tie(const std::string &name, T *pointer)
Tie a property to an external variable.
static FGMatrix33 ReadInertiaMatrix(Element *document)