JSBSim Flight Dynamics Model 1.3.0 (09 Apr 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 FGMatrix33GetInertia (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 FGColumnVector3GetXYZ (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.
 
void disableHighLighting (void)
 Disables highlighting in the console output.
 

Public Attributes

const struct FGGasCell::Inputsin
 

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 const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
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 KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
static char highint [5] = {27, '[', '1', 'm', '\0' }
 highlights text
 
static char halfint [5] = {27, '[', '2', 'm', '\0' }
 low intensity text
 
static char normint [6] = {27, '[', '2', '2', 'm', '\0' }
 normal intensity text
 
static char reset [5] = {27, '[', '0', 'm', '\0' }
 resets text properties
 
static char underon [5] = {27, '[', '4', 'm', '\0' }
 underlines text
 
static char underoff [6] = {27, '[', '2', '4', 'm', '\0' }
 underline off
 
static char fgblue [6] = {27, '[', '3', '4', 'm', '\0' }
 blue text
 
static char fgcyan [6] = {27, '[', '3', '6', 'm', '\0' }
 cyan text
 
static char fgred [6] = {27, '[', '3', '1', 'm', '\0' }
 red text
 
static char fggreen [6] = {27, '[', '3', '2', 'm', '\0' }
 green text
 
static char fgdef [6] = {27, '[', '3', '9', 'm', '\0' }
 default text
 
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 radtodeg = 180. / M_PI
 
static constexpr double degtorad = M_PI / 180.
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double fttom = 0.3048
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inhgtopa = 3386.38
 
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.
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static const std::string needed_cfg_version = "2.0"
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 

Constructor & Destructor Documentation

◆ FGBallonet()

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

Definition at line 499 of file FGGasCell.cpp.

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

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

Member Function Documentation

◆ Calculate()

void Calculate ( double  dt)

Runs the ballonet model; called by FGGasCell.

Definition at line 683 of file FGGasCell.cpp.

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