]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGMassBalance.cpp
69c3a67230064b9d5c945b28728f239e507de1ef
[flightgear.git] / src / FDM / JSBSim / models / FGMassBalance.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGMassBalance.cpp
4  Author:       Jon S. Berndt
5  Date started: 09/12/2000
6  Purpose:      This module models weight and balance
7
8  ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) --------------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free Software
12  Foundation; either version 2 of the License, or (at your option) any later
13  version.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
18  details.
19
20  You should have received a copy of the GNU Lesser General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22  Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  Further information about the GNU Lesser General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29
30 This class models the change in weight and balance of the aircraft due to fuel
31 burnoff, etc.
32
33 HISTORY
34 --------------------------------------------------------------------------------
35 09/12/2000  JSB  Created
36
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40
41 #include "FGMassBalance.h"
42 #include "FGPropulsion.h"
43 #include "FGBuoyantForces.h"
44 #include <input_output/FGPropertyManager.h>
45
46 namespace JSBSim {
47
48 static const char *IdSrc = "$Id$";
49 static const char *IdHdr = ID_MASSBALANCE;
50
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 CLASS IMPLEMENTATION
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54
55
56 FGMassBalance::FGMassBalance(FGFDMExec* fdmex) : FGModel(fdmex)
57 {
58   Name = "FGMassBalance";
59   Weight = EmptyWeight = Mass = 0.0;
60
61   vbaseXYZcg.InitMatrix(0.0);
62   baseJ.InitMatrix();
63   mJ.InitMatrix();
64   mJinv.InitMatrix();
65   pmJ.InitMatrix();
66
67   bind();
68
69   Debug(0);
70 }
71
72 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73
74 FGMassBalance::~FGMassBalance()
75 {
76   for (unsigned int i=0; i<PointMasses.size(); i++) delete PointMasses[i];
77   PointMasses.clear();
78
79   Debug(1);
80 }
81
82 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83
84 bool FGMassBalance::InitModel(void)
85 {
86   if (!FGModel::InitModel()) return false;
87
88   return true;
89 }
90
91 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92
93 bool FGMassBalance::Load(Element* el)
94 {
95   Element *element;
96   string element_name = "";
97   double bixx, biyy, bizz, bixy, bixz, biyz;
98
99   bixx = biyy = bizz = bixy = bixz = biyz = 0.0;
100   if (el->FindElement("ixx"))
101     bixx = el->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
102   if (el->FindElement("iyy"))
103     biyy = el->FindElementValueAsNumberConvertTo("iyy", "SLUG*FT2");
104   if (el->FindElement("izz"))
105     bizz = el->FindElementValueAsNumberConvertTo("izz", "SLUG*FT2");
106   if (el->FindElement("ixy"))
107     bixy = el->FindElementValueAsNumberConvertTo("ixy", "SLUG*FT2");
108   if (el->FindElement("ixz"))
109     bixz = el->FindElementValueAsNumberConvertTo("ixz", "SLUG*FT2");
110   if (el->FindElement("iyz"))
111     biyz = el->FindElementValueAsNumberConvertTo("iyz", "SLUG*FT2");
112   SetAircraftBaseInertias(FGMatrix33(  bixx,  -bixy,  bixz,
113                                       -bixy,  biyy,  -biyz,
114                                        bixz,  -biyz,  bizz ));
115   EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
116
117   element = el->FindElement("location");
118   while (element) {
119     element_name = element->GetAttributeValue("name");
120     if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
121     element = el->FindNextElement("location");
122   }
123
124 // Find all POINTMASS elements that descend from this METRICS branch of the
125 // config file.
126
127   element = el->FindElement("pointmass");
128   while (element) {
129     AddPointMass(element);
130     element = el->FindNextElement("pointmass");
131   }
132
133   Debug(2);
134   return true;
135 }
136
137 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138
139 bool FGMassBalance::Run(void)
140 {
141   double denom, k1, k2, k3, k4, k5, k6;
142   double Ixx, Iyy, Izz, Ixy, Ixz, Iyz;
143
144   if (FGModel::Run()) return true;
145   if (FDMExec->Holding()) return false;
146
147   Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight()
148     + BuoyantForces->GetGasMass()*slugtolb;
149
150   Mass = lbtoslug*Weight;
151
152 // Calculate new CG
153
154   vXYZcg = (Propulsion->GetTanksMoment() + EmptyWeight*vbaseXYZcg
155             + GetPointMassMoment()
156             + BuoyantForces->GetGasMassMoment()) / Weight;
157
158 // Calculate new total moments of inertia
159
160   // At first it is the base configuration inertia matrix ...
161   mJ = baseJ;
162   // ... with the additional term originating from the parallel axis theorem.
163   mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
164   // Then add the contributions from the additional pointmasses.
165   mJ += CalculatePMInertias();
166   mJ += Propulsion->CalculateTankInertias();
167   mJ += BuoyantForces->GetGasMassInertia();
168
169   Ixx = mJ(1,1);
170   Iyy = mJ(2,2);
171   Izz = mJ(3,3);
172   Ixy = -mJ(1,2);
173   Ixz = -mJ(1,3);
174   Iyz = -mJ(2,3);
175
176 // Calculate inertia matrix inverse (ref. Stevens and Lewis, "Flight Control & Simulation")
177
178   k1 = (Iyy*Izz - Iyz*Iyz);
179   k2 = (Iyz*Ixz + Ixy*Izz);
180   k3 = (Ixy*Iyz + Iyy*Ixz);
181
182   denom = 1.0/(Ixx*k1 - Ixy*k2 - Ixz*k3 );
183   k1 = k1*denom;
184   k2 = k2*denom;
185   k3 = k3*denom;
186   k4 = (Izz*Ixx - Ixz*Ixz)*denom;
187   k5 = (Ixy*Ixz + Iyz*Ixx)*denom;
188   k6 = (Ixx*Iyy - Ixy*Ixy)*denom;
189
190   mJinv.InitMatrix( k1, k2, k3,
191                     k2, k4, k5,
192                     k3, k5, k6 );
193
194   Debug(0);
195
196   return false;
197 }
198
199 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200
201 void FGMassBalance::AddPointMass(Element* el)
202 {
203   char tmp[80];
204
205   Element* loc_element = el->FindElement("location");
206   string pointmass_name = el->GetAttributeValue("name");
207   if (!loc_element) {
208     cerr << "Pointmass " << pointmass_name << " has no location." << endl;
209     exit(-1);
210   }
211
212   double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
213   FGColumnVector3 vXYZ = loc_element->FindElementTripletConvertTo("IN");
214   PointMasses.push_back(new PointMass(w, vXYZ));
215
216   int num = PointMasses.size()-1;
217
218   snprintf(tmp, 80, "inertia/pointmass-weight-lbs[%u]", num);
219   PropertyManager->Tie( tmp, this, num, &FGMassBalance::GetPointMassWeight,
220                                         &FGMassBalance::SetPointMassWeight);
221 }
222
223 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224
225 double FGMassBalance::GetPointMassWeight(void)
226 {
227   double PM_total_weight = 0.0;
228
229   for (unsigned int i=0; i<PointMasses.size(); i++) {
230     PM_total_weight += PointMasses[i]->Weight;
231   }
232   return PM_total_weight;
233 }
234
235 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236
237 FGColumnVector3& FGMassBalance::GetPointMassMoment(void)
238 {
239   PointMassCG.InitMatrix();
240
241   for (unsigned int i=0; i<PointMasses.size(); i++) {
242     PointMassCG += PointMasses[i]->Weight*PointMasses[i]->Location;
243   }
244   return PointMassCG;
245 }
246
247 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248
249 FGMatrix33& FGMassBalance::CalculatePMInertias(void)
250 {
251   unsigned int size;
252
253   size = PointMasses.size();
254   if (size == 0) return pmJ;
255
256   pmJ = FGMatrix33();
257
258   for (unsigned int i=0; i<size; i++)
259     pmJ += GetPointmassInertia( lbtoslug * PointMasses[i]->Weight, PointMasses[i]->Location );
260
261   return pmJ;
262 }
263
264 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265
266 FGColumnVector3 FGMassBalance::StructuralToBody(const FGColumnVector3& r) const
267 {
268   // Under the assumption that in the structural frame the:
269   //
270   // - X-axis is directed afterwards,
271   // - Y-axis is directed towards the right,
272   // - Z-axis is directed upwards,
273   //
274   // (as documented in http://jsbsim.sourceforge.net/JSBSimCoordinates.pdf)
275   // we have to subtract first the center of gravity of the plane which
276   // is also defined in the structural frame:
277   //
278   //   FGColumnVector3 cgOff = r - vXYZcg;
279   //
280   // Next, we do a change of units:
281   //
282   //   cgOff *= inchtoft;
283   //
284   // And then a 180 degree rotation is done about the Y axis so that the:
285   //
286   // - X-axis is directed forward,
287   // - Y-axis is directed towards the right,
288   // - Z-axis is directed downward.
289   //
290   // This is needed because the structural and body frames are 180 degrees apart.
291
292   return FGColumnVector3(inchtoft*(vXYZcg(1)-r(1)),
293                          inchtoft*(r(2)-vXYZcg(2)),
294                          inchtoft*(vXYZcg(3)-r(3)));
295 }
296
297 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298
299 void FGMassBalance::bind(void)
300 {
301   typedef double (FGMassBalance::*PMF)(int) const;
302   PropertyManager->Tie("inertia/mass-slugs", this,
303                        &FGMassBalance::GetMass);
304   PropertyManager->Tie("inertia/weight-lbs", this,
305                        &FGMassBalance::GetWeight);
306   PropertyManager->Tie("inertia/empty-weight-lbs", this,
307     &FGMassBalance::GetWeight, &FGMassBalance::SetEmptyWeight);
308   PropertyManager->Tie("inertia/cg-x-in", this,1,
309                        (PMF)&FGMassBalance::GetXYZcg);
310   PropertyManager->Tie("inertia/cg-y-in", this,2,
311                        (PMF)&FGMassBalance::GetXYZcg);
312   PropertyManager->Tie("inertia/cg-z-in", this,3,
313                        (PMF)&FGMassBalance::GetXYZcg);
314 }
315
316 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 //    The bitmasked value choices are as follows:
318 //    unset: In this case (the default) JSBSim would only print
319 //       out the normally expected messages, essentially echoing
320 //       the config files as they are read. If the environment
321 //       variable is not set, debug_lvl is set to 1 internally
322 //    0: This requests JSBSim not to output any messages
323 //       whatsoever.
324 //    1: This value explicity requests the normal JSBSim
325 //       startup messages
326 //    2: This value asks for a message to be printed out when
327 //       a class is instantiated
328 //    4: When this value is set, a message is displayed when a
329 //       FGModel object executes its Run() method
330 //    8: When this value is set, various runtime state variables
331 //       are printed out periodically
332 //    16: When set various parameters are sanity checked and
333 //       a message is printed out when they go out of bounds
334
335 void FGMassBalance::Debug(int from)
336 {
337   if (debug_lvl <= 0) return;
338
339   if (debug_lvl & 1) { // Standard console startup message output
340     if (from == 2) { // Loading
341       cout << endl << "  Mass and Balance:" << endl;
342       cout << "    baseIxx: " << baseJ(1,1) << " slug-ft2" << endl;
343       cout << "    baseIyy: " << baseJ(2,2) << " slug-ft2" << endl;
344       cout << "    baseIzz: " << baseJ(3,3) << " slug-ft2" << endl;
345       cout << "    baseIxy: " << baseJ(1,2) << " slug-ft2" << endl;
346       cout << "    baseIxz: " << baseJ(1,3) << " slug-ft2" << endl;
347       cout << "    baseIyz: " << baseJ(2,3) << " slug-ft2" << endl;
348       cout << "    EmptyWeight: " << EmptyWeight << " lbm" << endl;
349       cout << "    CG (x, y, z): " << vbaseXYZcg << endl;
350       // ToDo: Need to add point mass outputs here
351       for (unsigned int i=0; i<PointMasses.size(); i++) {
352         cout << "    Point Mass Object: " << PointMasses[i]->Weight << " lbs. at "
353                    << "X, Y, Z (in.): " << PointMasses[i]->Location(eX) << "  "
354                    << PointMasses[i]->Location(eY) << "  "
355                    << PointMasses[i]->Location(eZ) << endl;
356       }
357     }
358   }
359   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
360     if (from == 0) cout << "Instantiated: FGMassBalance" << endl;
361     if (from == 1) cout << "Destroyed:    FGMassBalance" << endl;
362   }
363   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
364   }
365   if (debug_lvl & 8 ) { // Runtime state variables
366   }
367   if (debug_lvl & 16) { // Sanity checking
368     if (from == 2) {
369       if (EmptyWeight <= 0.0 || EmptyWeight > 1e9)
370         cout << "MassBalance::EmptyWeight out of bounds: " << EmptyWeight << endl;
371       if (Weight <= 0.0 || Weight > 1e9)
372         cout << "MassBalance::Weight out of bounds: " << Weight << endl;
373       if (Mass <= 0.0 || Mass > 1e9)
374         cout << "MassBalance::Mass out of bounds: " << Mass << endl;
375     }
376   }
377   if (debug_lvl & 64) {
378     if (from == 0) { // Constructor
379       cout << IdSrc << endl;
380       cout << IdHdr << endl;
381     }
382   }
383 }
384 }