JSBSim Flight Dynamics Model 1.3.3 (16 Oct 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGBallonet Class Reference

Detailed Description

Models a ballonet inside a gas cell.

Not intended to be used outside FGGasCell. See FGGasCell for the configuration file format.

Author
Anders Gidenstam

Definition at line 302 of file FGGasCell.h.

#include <FGGasCell.h>

+ Inheritance diagram for FGBallonet:
+ Collaboration diagram for FGBallonet:

Public Member Functions

 FGBallonet (FGFDMExec *exec, Element *el, unsigned int num, FGGasCell *parent, const struct FGGasCell::Inputs &input)
 
void Calculate (double dt)
 Runs the ballonet model; called by FGGasCell.
 
double GetHeatFlow (void) const
 Get the current heat flow into the ballonet.
 
const FGMatrix33 & GetInertia (void) const
 Get the moments of inertia of the ballonet.
 
double GetMass (void) const
 Get the current mass of the ballonets.
 
double GetVolume (void) const
 Get the current volume of the ballonet.
 
double GetXYZ (int idx) const
 Get the center of gravity location of the ballonet.
 
const FGColumnVector3 & GetXYZ (void) const
 Get the center of gravity location of the ballonet.
 
- Public Member Functions inherited from FGJSBBase
 FGJSBBase ()
 Constructor for FGJSBBase.
 
virtual ~FGJSBBase ()
 Destructor for FGJSBBase.
 

Public Attributes

const struct FGGasCell::Inputs & in
 

Additional Inherited Members

- Public Types inherited from FGJSBBase
enum  { eL = 1 , eM , eN }
 Moments L, M, N. More...
 
enum  { eP = 1 , eQ , eR }
 Rates P, Q, R. More...
 
enum  { eU = 1 , eV , eW }
 Velocities U, V, W. More...
 
enum  { eX = 1 , eY , eZ }
 Positions X, Y, Z. More...
 
enum  { ePhi = 1 , eTht , ePsi }
 Euler angles Phi, Theta, Psi. More...
 
enum  { eDrag = 1 , eSide , eLift }
 Stability axis forces, Drag, Side force, Lift. More...
 
enum  { eRoll = 1 , ePitch , eYaw }
 Local frame orientation Roll, Pitch, Yaw. More...
 
enum  { eNorth = 1 , eEast , eDown }
 Local frame position North, East, Down. More...
 
enum  { eLat = 1 , eLong , eRad }
 Locations Radius, Latitude, Longitude. More...
 
enum  {
  inNone = 0 , inDegrees , inRadians , inMeters ,
  inFeet
}
 Conversion specifiers. More...
 
- Static Public Member Functions inherited from FGJSBBase
static constexpr double CelsiusToFahrenheit (double celsius)
 Converts from degrees Celsius to degrees Fahrenheit.
 
static constexpr double CelsiusToKelvin (double celsius)
 Converts from degrees Celsius to degrees Kelvin.
 
static constexpr double CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
static short debug_lvl = 1
 
- Static Protected Member Functions inherited from FGJSBBase
static std::string CreateIndexedPropertyName (const std::string &Property, int index)
 
- Static Protected Attributes inherited from FGJSBBase
static constexpr double degtorad = M_PI / 180.
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double fttom = 0.3048
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double inhgtopa = 3386.38
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static const std::string needed_cfg_version = "2.0"
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double radtodeg = 180. / M_PI
 
static constexpr double slugtolb = 32.174049
 Note that definition of lbtoslug by the inverse of slugtolb and not to a different constant you can also get from some tables will make lbtoslug*slugtolb == 1 up to the magnitude of roundoff.
 

Constructor & Destructor Documentation

◆ FGBallonet()

FGBallonet ( FGFDMExec *  exec,
Element *  el,
unsigned int  num,
FGGasCell *  parent,
const struct FGGasCell::Inputs &  input 
)

Definition at line 500 of file FGGasCell.cpp.

502 : in(input)
503{
504 string token;
505 Element* element;
506
507 auto PropertyManager = exec->GetPropertyManager();
508 MassBalance = exec->GetMassBalance();
509
510 MaxVolume = MaxOverpressure = Temperature = Pressure =
511 Contents = Volume = dVolumeIdeal = dU = 0.0;
512 Xradius = Yradius = Zradius = Xwidth = Ywidth = Zwidth = 0.0;
513 ValveCoefficient = ValveOpen = 0.0;
514 BlowerInput = NULL;
515 CellNum = num;
516 Parent = parent;
517
518 // NOTE: In the local system X points north, Y points east and Z points down.
519 element = el->FindElement("location");
520 if (element) {
521 vXYZ = element->FindElementTripletConvertTo("IN");
522 } else {
523 XMLLogException err(el);
524 err << "\nFatal Error: No location found for this ballonet.\n";
525 throw err;
526 }
527 if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
528 (el->FindElement("y_radius") || el->FindElement("y_width")) &&
529 (el->FindElement("z_radius") || el->FindElement("z_width"))) {
530
531 if (el->FindElement("x_radius")) {
532 Xradius = el->FindElementValueAsNumberConvertTo("x_radius", "FT");
533 }
534 if (el->FindElement("y_radius")) {
535 Yradius = el->FindElementValueAsNumberConvertTo("y_radius", "FT");
536 }
537 if (el->FindElement("z_radius")) {
538 Zradius = el->FindElementValueAsNumberConvertTo("z_radius", "FT");
539 }
540
541 if (el->FindElement("x_width")) {
542 Xwidth = el->FindElementValueAsNumberConvertTo("x_width", "FT");
543 }
544 if (el->FindElement("y_width")) {
545 Ywidth = el->FindElementValueAsNumberConvertTo("y_width", "FT");
546 }
547 if (el->FindElement("z_width")) {
548 Zwidth = el->FindElementValueAsNumberConvertTo("z_width", "FT");
549 }
550
551 // The volume is a (potentially) extruded ellipsoid.
552 // FIXME: However, currently only a few combinations of radius and
553 // width are fully supported.
554 if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
555 (Xwidth == 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
556 // Ellipsoid volume.
557 MaxVolume = 4.0 * M_PI * Xradius * Yradius * Zradius / 3.0;
558 } else if ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
559 (Xwidth != 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
560 // Cylindrical volume.
561 MaxVolume = M_PI * Yradius * Zradius * Xwidth;
562 } else {
563 FGXMLLogging log(el, LogLevel::WARN);
564 log << "Unsupported ballonet shape.\n";
565 MaxVolume =
566 (4.0 * M_PI * Xradius * Yradius * Zradius / 3.0 +
567 M_PI * Yradius * Zradius * Xwidth +
568 M_PI * Xradius * Zradius * Ywidth +
569 M_PI * Xradius * Yradius * Zwidth +
570 2.0 * Xradius * Ywidth * Zwidth +
571 2.0 * Yradius * Xwidth * Zwidth +
572 2.0 * Zradius * Xwidth * Ywidth +
573 Xwidth * Ywidth * Zwidth);
574 }
575 } else {
576 XMLLogException err(el);
577 err << "\nFatal Error: Ballonet shape must be given.\n";
578 throw err;
579 }
580 if (el->FindElement("max_overpressure")) {
581 MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
582 "LBS/FT2");
583 }
584 if (el->FindElement("fullness")) {
585 const double Fullness = el->FindElementValueAsNumber("fullness");
586 if (0 <= Fullness) {
587 Volume = Fullness * MaxVolume;
588 } else {
589 FGXMLLogging log(el, LogLevel::WARN);
590 log << "Invalid initial ballonet fullness value.\n";
591 }
592 }
593 if (el->FindElement("valve_coefficient")) {
594 ValveCoefficient =
595 el->FindElementValueAsNumberConvertTo("valve_coefficient",
596 "FT4*SEC/SLUG");
597 ValveCoefficient = max(ValveCoefficient, 0.0);
598 }
599
600 // Initialize state
601 if (Temperature == 0.0) {
602 Temperature = Parent->GetTemperature();
603 }
604 if (Pressure == 0.0) {
605 Pressure = Parent->GetPressure();
606 }
607 if (Volume != 0.0) {
608 // Calculate initial air content.
609 Contents = Pressure * Volume / (R * Temperature);
610
611 // Clip to max allowed value.
612 const double IdealPressure = Contents * R * Temperature / MaxVolume;
613 if (IdealPressure > Pressure + MaxOverpressure) {
614 Contents = (Pressure + MaxOverpressure) * MaxVolume / (R * Temperature);
615 Pressure = Pressure + MaxOverpressure;
616 } else {
617 Pressure = max(IdealPressure, Pressure);
618 }
619 } else {
620 // Calculate initial air content.
621 Contents = Pressure * MaxVolume / (R * Temperature);
622 }
623
624 Volume = Contents * R * Temperature / Pressure;
625
626 // Bind relevant properties
627 string property_name, base_property_name;
628 base_property_name = CreateIndexedPropertyName("buoyant_forces/gas-cell", Parent->GetIndex());
629 base_property_name = CreateIndexedPropertyName(base_property_name + "/ballonet", CellNum);
630
631 property_name = base_property_name + "/max_volume-ft3";
632 PropertyManager->Tie( property_name, &MaxVolume);
633 PropertyManager->GetNode(property_name)->setAttribute( SGPropertyNode::WRITE, false );
634
635 property_name = base_property_name + "/temp-R";
636 PropertyManager->Tie( property_name, &Temperature);
637
638 property_name = base_property_name + "/pressure-psf";
639 PropertyManager->Tie( property_name, &Pressure);
640
641 property_name = base_property_name + "/volume-ft3";
642 PropertyManager->Tie( property_name, &Volume);
643
644 property_name = base_property_name + "/contents-mol";
645 PropertyManager->Tie( property_name, &Contents);
646
647 property_name = base_property_name + "/valve_open";
648 PropertyManager->Tie( property_name, &ValveOpen);
649
650 Debug(0);
651
652 // Read heat transfer coefficients
653 if (Element* heat = el->FindElement("heat")) {
654 Element* function_element = heat->FindElement("function");
655 while (function_element) {
656 HeatTransferCoeff.push_back(new FGFunction(exec, function_element));
657 function_element = heat->FindNextElement("function");
658 }
659 }
660 // Read blower input function
661 if (Element* blower = el->FindElement("blower_input")) {
662 Element* function_element = blower->FindElement("function");
663 BlowerInput = new FGFunction(exec, function_element);
664 }
665}
double GetTemperature(void) const
Get the current gas temperature inside the gas cell.
Definition FGGasCell.h:220
int GetIndex(void) const
Get the index of this gas cell.
Definition FGGasCell.h:190
double GetPressure(void) const
Get the current gas pressure inside the gas cell.
Definition FGGasCell.h:224

◆ ~FGBallonet()

~FGBallonet ( )

Definition at line 669 of file FGGasCell.cpp.

670{
671 unsigned int i;
672
673 for (i = 0; i < HeatTransferCoeff.size(); i++) delete HeatTransferCoeff[i];
674 HeatTransferCoeff.clear();
675
676 delete BlowerInput;
677 BlowerInput = NULL;
678
679 Debug(1);
680}

Member Function Documentation

◆ Calculate()

void Calculate ( double  dt)

Runs the ballonet model; called by FGGasCell.

Definition at line 684 of file FGGasCell.cpp.

685{
686 const double ParentPressure = Parent->GetPressure(); // [lbs/ft^2]
687 const double AirPressure = in.Pressure; // [lbs/ft^2]
688
689 const double OldTemperature = Temperature;
690 const double OldPressure = Pressure;
691 unsigned int i;
692
693 //-- Gas temperature --
694
695 // The model is based on the ideal gas law.
696 // However, it does look a bit fishy. Please verify.
697 // dT/dt = dU / (Cv n R)
698 dU = 0.0;
699 for (i = 0; i < HeatTransferCoeff.size(); i++) {
700 dU += HeatTransferCoeff[i]->GetValue();
701 }
702 // dt is already accounted for in dVolumeIdeal.
703 if (Contents > 0) {
704 Temperature +=
705 (dU * dt - Pressure * dVolumeIdeal) / (Cv_air * Contents * R);
706 } else {
707 Temperature = Parent->GetTemperature();
708 }
709
710 //-- Pressure --
711 const double IdealPressure = Contents * R * Temperature / MaxVolume;
712 // The pressure is at least that of the parent gas cell.
713 Pressure = max(IdealPressure, ParentPressure);
714
715 //-- Blower input --
716 if (BlowerInput) {
717 const double AddedVolume = BlowerInput->GetValue() * dt;
718 if (AddedVolume > 0.0) {
719 Contents += Pressure * AddedVolume / (R * Temperature);
720 }
721 }
722
723 //-- Pressure relief and manual valving --
724 // FIXME: Presently the effect of valving is computed using
725 // an ad hoc formula which might not be a good representation
726 // of reality.
727 if ((ValveCoefficient > 0.0) &&
728 ((ValveOpen > 0.0) || (Pressure > AirPressure + MaxOverpressure))) {
729 const double DeltaPressure = Pressure - AirPressure;
730 const double VolumeValved =
731 ((Pressure > AirPressure + MaxOverpressure) ? 1.0 : ValveOpen) *
732 ValveCoefficient * DeltaPressure * dt;
733 // FIXME: Too small values of Contents sometimes leads to NaN.
734 // Currently the minimum is restricted to a safe value.
735 Contents =
736 max(1.0, Contents - Pressure * VolumeValved / (R * Temperature));
737 }
738
739 //-- Volume --
740 Volume = Contents * R * Temperature / Pressure;
741 dVolumeIdeal =
742 Contents * R * (Temperature / Pressure - OldTemperature / OldPressure);
743
744 // Compute the inertia of the ballonet.
745 // Consider the ballonet as a shape of uniform density.
746 // FIXME: If the ballonet isn't ellipsoid or cylindrical the inertia will
747 // be wrong.
748 ballonetJ.InitMatrix();
749 const double mass = Contents * M_air;
750 double Ixx, Iyy, Izz;
751 if ((Xradius != 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
752 (Xwidth == 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
753 // Ellipsoid volume.
754 Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius);
755 Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius);
756 Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
757 } else if ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
758 (Xwidth != 0.0) && (Ywidth == 0.0) && (Zwidth == 0.0)) {
759 // Cylindrical volume (might not be valid with an elliptical cross-section).
760 Ixx = (1.0 / 2.0) * mass * Yradius * Zradius;
761 Iyy =
762 (1.0 / 4.0) * mass * Yradius * Zradius +
763 (1.0 / 12.0) * mass * Xwidth * Xwidth;
764 Izz =
765 (1.0 / 4.0) * mass * Yradius * Zradius +
766 (1.0 / 12.0) * mass * Xwidth * Xwidth;
767 } else {
768 // Not supported. Revert to pointmass model.
769 Ixx = Iyy = Izz = 0.0;
770 }
771 // The volume is symmetric, so Ixy = Ixz = Iyz = 0.
772 ballonetJ(1,1) = Ixx;
773 ballonetJ(2,2) = Iyy;
774 ballonetJ(3,3) = Izz;
775 // Transform the moments of inertia to the body frame.
776 ballonetJ += MassBalance->GetPointmassInertia(GetMass(), GetXYZ());
777}
double GetMass(void) const
Get the current mass of the ballonets.
Definition FGGasCell.h:323
const FGColumnVector3 & GetXYZ(void) const
Get the center of gravity location of the ballonet.
Definition FGGasCell.h:316
double GetValue(void) const override
Retrieves the value of the function object.
void InitMatrix(void)
Initialize the matrix.
+ Here is the call graph for this function:

◆ GetHeatFlow()

double GetHeatFlow ( void  ) const
inline

Get the current heat flow into the ballonet.

Returns
heat flow in lbs ft / sec.

Definition at line 335 of file FGGasCell.h.

335{return dU;} // [lbs ft / sec]

◆ GetInertia()

const FGMatrix33 & GetInertia ( void  ) const
inline

Get the moments of inertia of the ballonet.

Returns
moments of inertia matrix in the body frame in slug ft2.

Definition at line 328 of file FGGasCell.h.

328{return ballonetJ;}

◆ GetMass()

double GetMass ( void  ) const
inline

Get the current mass of the ballonets.

Returns
mass in slug.

Definition at line 323 of file FGGasCell.h.

323{return Contents * M_air;}
+ Here is the caller graph for this function:

◆ GetVolume()

double GetVolume ( void  ) const
inline

Get the current volume of the ballonet.

Returns
volume in ft3.

Definition at line 332 of file FGGasCell.h.

332{return Volume;}

◆ GetXYZ() [1/2]

double GetXYZ ( int  idx) const
inline

Get the center of gravity location of the ballonet.

Returns
CoG location in the structural frame in inches.

Definition at line 319 of file FGGasCell.h.

319{return vXYZ(idx);}

◆ GetXYZ() [2/2]

const FGColumnVector3 & GetXYZ ( void  ) const
inline

Get the center of gravity location of the ballonet.

Returns
CoG location in the structural frame in inches.

Definition at line 316 of file FGGasCell.h.

316{return vXYZ;}
+ Here is the caller graph for this function:

Member Data Documentation

◆ in

const struct FGGasCell::Inputs& in

Definition at line 337 of file FGGasCell.h.


The documentation for this class was generated from the following files: