1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header:       FGMassBalance.h
4  Author:       Jon S. Berndt
5  Date started: 09/12/2000
6 
7  ------------- Copyright (C) 2000  Jon S. Berndt (jon@jsbsim.org) --------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free
11  Software Foundation; either version 2 of the License, or (at your option) any
12  later version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along
20  with this program; if not, write to the Free Software Foundation, Inc., 59
21  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be
24  found on the world wide web at http://www.gnu.org.
25 
26 HISTORY
27 --------------------------------------------------------------------------------
28 09/12/2000  JSB  Created
29 
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 SENTRY
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
33 
34 #ifndef FGMASSBALANCE_H
35 #define FGMASSBALANCE_H
36 
37 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40 
41 #include "FGModel.h"
42 #include "math/FGMatrix33.h"
43 
44 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 FORWARD DECLARATIONSS
46 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47 
48 namespace JSBSim {
49 
50 class FGPropagate;
51 class FGGroundReactions;
52 
53 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54 CLASS DOCUMENTATION
55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56 
57 /** Models weight, balance and moment of inertia information.
58 
59     Maintains a vector of point masses. Sums the contribution of all, and
60     provides this to FGPropagate.  Loads the <mass_balance> section of the
61     aircraft configuration file. There can be any number of <pointmasses>. Each
62     can also have a shape which - if present - causes an associated moment of
63     inertia to be calculated based on the shape. Note that a cylinder is solid,
64     a tube is hollow, a ball is solid and a sphere is hollow.
65 
66     The inertia tensor must be specified in the structural frame (x axis
67     positive aft, y axis positive out of the right wing and z axis upward). The
68     sign of the inertia cross products are not modified by JSBSim so in most
69     cases, negative values should be provided for <ixy>, <ixz> and <iyz>.
70 
71     <h3>Configuration File Format for \<mass_balance> Section:</h3>
72 @code{.xml}
73     <mass_balance>
74         <ixx unit="{SLUG*FT2 | KG*M2}"> {number} </ixx>
75         <iyy unit="{SLUG*FT2 | KG*M2}"> {number} </iyy>
76         <izz unit="{SLUG*FT2 | KG*M2}"> {number} </izz>
77         <ixy unit="{SLUG*FT2 | KG*M2}"> {number} </ixy>
78         <ixz unit="{SLUG*FT2 | KG*M2}"> {number} </ixz>
79         <iyz unit="{SLUG*FT2 | KG*M2}"> {number} </iyz>
80         <emptywt unit="{LBS | KG"> {number} </emptywt>
81         <location name="CG" unit="{IN | FT | M}">
82             <x> {number} </x>
83             <y> {number} </y>
84             <z> {number} </z>
85         </location>
86         [<pointmass name="{string}">
87             <form shape="{tube | cylinder | sphere | ball}">
88                <radius unit="{IN | FT | M}"> {number} </radius>
89                <length unit="{IN | FT | M}"> {number} </length>
90             </form>
91             <weight unit="{LBS | KG}"> {number} </weight>
92             <location name="{string}" unit="{IN | FT | M}">
93                 <x> {number} </x>
94                 <y> {number} </y>
95                 <z> {number} </z>
96             </location>
97         </pointmass>
98         ... other point masses ...]
99     </mass_balance>
100 @endcode
101   */
102 
103 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 CLASS DECLARATION
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
106 
107 class FGMassBalance : public FGModel
108 {
109 
110 public:
111   explicit FGMassBalance(FGFDMExec*);
112   ~FGMassBalance();
113 
114   bool Load(Element* el);
115   bool InitModel(void) override;
116   /** Runs the Mass Balance model; called by the Executive
117       Can pass in a value indicating if the executive is directing the
118       simulation to Hold.
119       @param Holding if true, the executive has been directed to hold the sim
120                      from advancing time. Some models may ignore this flag, such
121                      as the Input model, which may need to be active to listen
122                      on a socket for the "Resume" command to be given.  @return
123                      false if no error */
124   bool Run(bool Holding) override;
125 
GetMass(void)126   double GetMass(void) const {return Mass;}
GetWeight(void)127   double GetWeight(void) const {return Weight;}
GetEmptyWeight(void)128   double GetEmptyWeight(void) const {return EmptyWeight;}
129   /** Returns the coordinates of the center of gravity expressed in the
130       structural frame. */
GetXYZcg(void)131   const FGColumnVector3& GetXYZcg(void) const {return vXYZcg;}
GetXYZcg(int axis)132   double GetXYZcg(int axis) const  {return vXYZcg(axis);}
GetDeltaXYZcg(void)133   const FGColumnVector3& GetDeltaXYZcg(void) const {return vDeltaXYZcg;}
GetDeltaXYZcg(int axis)134   double GetDeltaXYZcg(int axis) const  {return vDeltaXYZcg(axis);}
135 
136   /** Computes the inertia contribution of a pointmass.
137       Computes and returns the inertia matrix of a pointmass of mass
138       slugs at the given vector r in the structural frame. The units
139       should be for the mass in slug and the vector in the structural
140       frame as usual in inches.
141       @param mass_sl the mass of this single pointmass given in slugs
142       @param r the location of this single pointmass in the structural frame
143    */
GetPointmassInertia(double mass_sl,const FGColumnVector3 & r)144   FGMatrix33 GetPointmassInertia(double mass_sl, const FGColumnVector3& r) const
145   {
146     FGColumnVector3 v = StructuralToBody( r );
147     FGColumnVector3 sv = mass_sl*v;
148     double xx = sv(1)*v(1);
149     double yy = sv(2)*v(2);
150     double zz = sv(3)*v(3);
151     double xy = -sv(1)*v(2);
152     double xz = -sv(1)*v(3);
153     double yz = -sv(2)*v(3);
154     return FGMatrix33( yy+zz, xy, xz,
155                        xy, xx+zz, yz,
156                        xz, yz, xx+yy );
157   }
158 
159   /** Conversion from the structural frame to the body frame.
160       Converts the location given in the structural frame
161       coordinate system to the body frame. The units of the structural
162       frame are assumed to be in inches. The unit of the result is in
163       ft.
164       @param r vector coordinate in the structural reference frame (X positive
165                aft, measurements in inches).
166       @return vector coordinate in the body frame, in feet.
167    */
168   FGColumnVector3 StructuralToBody(const FGColumnVector3& r) const;
169 
SetEmptyWeight(double EW)170   void SetEmptyWeight(double EW) { EmptyWeight = EW;}
SetBaseCG(const FGColumnVector3 & CG)171   void SetBaseCG(const FGColumnVector3& CG) {vbaseXYZcg = vXYZcg = CG;}
172 
173   void AddPointMass(Element* el);
174   double GetTotalPointMassWeight(void) const;
175 
176   const FGColumnVector3& GetPointMassMoment(void);
177   /// Returns the inertia matrix expressed in the body frame.
GetJ(void)178   const FGMatrix33& GetJ(void) const {return mJ;}
179   /// Returns the inverse of the inertia matrix expressed in the body frame.
GetJinv(void)180   const FGMatrix33& GetJinv(void) const {return mJinv;}
SetAircraftBaseInertias(const FGMatrix33 & BaseJ)181   void SetAircraftBaseInertias(const FGMatrix33& BaseJ) {baseJ = BaseJ;}
182   void GetMassPropertiesReport(int i);
183 
184   struct Inputs {
185     double GasMass;
186     double TanksWeight;
187     FGColumnVector3 GasMoment;
188     FGMatrix33 GasInertia;
189     FGColumnVector3 TanksMoment;
190     FGMatrix33 TankInertia;
191   } in;
192 
193 private:
194   FGPropagate* Propagate;
195   FGGroundReactions* GroundReactions;
196   double Weight;
197   double EmptyWeight;
198   double Mass;
199   FGMatrix33 mJ;
200   FGMatrix33 mJinv;
201   FGMatrix33 pmJ;
202   FGMatrix33 baseJ;
203   FGColumnVector3 vXYZcg;
204   FGColumnVector3 vLastXYZcg;
205   FGColumnVector3 vDeltaXYZcg;
206   FGColumnVector3 vDeltaXYZcgBody;
207   FGColumnVector3 vXYZtank;
208   FGColumnVector3 vbaseXYZcg;
209   FGColumnVector3 vPMxyz;
210   FGColumnVector3 PointMassCG;
211   const FGMatrix33& CalculatePMInertias(void);
GetIxx(void)212   double GetIxx(void) const { return mJ(1,1); }
GetIyy(void)213   double GetIyy(void) const { return mJ(2,2); }
GetIzz(void)214   double GetIzz(void) const { return mJ(3,3); }
GetIxy(void)215   double GetIxy(void) const { return -mJ(1,2); }
GetIxz(void)216   double GetIxz(void) const { return mJ(1,3); }
GetIyz(void)217   double GetIyz(void) const { return -mJ(2,3); }
218 
219   /** The PointMass structure encapsulates a point mass object, moments of inertia
220      mass, location, etc. */
221   struct PointMass {
PointMassPointMass222     PointMass(double w, FGColumnVector3& vXYZ) :
223       eShapeType(esUnspecified), Location(vXYZ), Weight(w), Radius(0.0),
224       Length(0.0) {}
225 
CalculateShapeInertiaPointMass226     void CalculateShapeInertia(void) {
227       switch(eShapeType) {
228         case esTube:
229           mPMInertia(1,1) = (Weight/(slugtolb))*Radius*Radius; // mr^2
230           mPMInertia(2,2) = (Weight/(slugtolb*12))*(6*Radius*Radius + Length*Length);
231           mPMInertia(3,3) = mPMInertia(2,2);
232           break;
233         case esCylinder:
234           mPMInertia(1,1) = (Weight/(slugtolb*2))*Radius*Radius; // 0.5*mr^2
235           mPMInertia(2,2) = (Weight/(slugtolb*12))*(3*Radius*Radius + Length*Length);
236           mPMInertia(3,3) = mPMInertia(2,2);
237           break;
238         case esSphere:
239           mPMInertia(1,1) = (Weight/(slugtolb*3))*Radius*Radius*2; // (2mr^2)/3
240           mPMInertia(2,2) = mPMInertia(1,1);
241           mPMInertia(3,3) = mPMInertia(1,1);
242           break;
243         case esBall:
244           mPMInertia(1,1) = (Weight/(slugtolb*5))*Radius*Radius*2; // (2mr^2)/5
245           mPMInertia(2,2) = mPMInertia(1,1);
246           mPMInertia(3,3) = mPMInertia(1,1);
247           break;
248         default:
249           break;
250       }
251     }
252 
253     enum esShape {esUnspecified, esTube, esCylinder, esSphere, esBall} eShapeType;
254     FGColumnVector3 Location;
255     double Weight; /// Weight in pounds.
256     double Radius; /// Radius in feet.
257     double Length; /// Length in feet.
258     std::string Name;
259     FGMatrix33 mPMInertia;
260 
GetPointMassLocationPointMass261     double GetPointMassLocation(int axis) const {return Location(axis);}
GetPointMassWeightPointMass262     double GetPointMassWeight(void) const {return Weight;}
GetShapeTypePointMass263     esShape GetShapeType(void) {return eShapeType;}
GetLocationPointMass264     const FGColumnVector3& GetLocation(void) {return Location;}
GetPointMassInertiaPointMass265     const FGMatrix33& GetPointMassInertia(void) {return mPMInertia;}
GetNamePointMass266     const std::string& GetName(void) {return Name;}
267 
SetPointMassLocationPointMass268     void SetPointMassLocation(int axis, double value) {Location(axis) = value;}
SetPointMassWeightPointMass269     void SetPointMassWeight(double wt) {
270       Weight = wt;
271       CalculateShapeInertia();
272     }
SetPointMassShapeTypePointMass273     void SetPointMassShapeType(esShape st) {eShapeType = st;}
SetRadiusPointMass274     void SetRadius(double r) {Radius = r;}
SetLengthPointMass275     void SetLength(double l) {Length = l;}
SetNamePointMass276     void SetName(const std::string& name) {Name = name;}
SetPointMassMoIPointMass277     void SetPointMassMoI(const FGMatrix33& MoI) { mPMInertia = MoI; }
GetPointMassMoIPointMass278     double GetPointMassMoI(int r, int c) {return mPMInertia(r,c);}
279 
280     void bind(FGPropertyManager* PropertyManager, unsigned int num);
281   };
282 
283   std::vector <struct PointMass*> PointMasses;
284 
285   void bind(void);
286   void Debug(int from) override;
287 };
288 }
289 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 #endif
291