JSBSim Flight Dynamics Model  1.1.11 (13 Feb 2022)
An Open Source Flight Dynamics and Control Software Library in C++
FGRotor.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGRotor.cpp
4  Author: Jon S. Berndt
5  Date started: 08/24/00
6  Purpose: Encapsulates the rotor object
7 
8  ------------- Copyright (C) 2000 Jon S. Berndt (jon@jsbsim.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
12  Software Foundation; either version 2 of the License, or (at your option) any
13  later 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
21  with this program; if not, write to the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24  Further information about the GNU Lesser General Public License can also be
25  found on the world wide web at http://www.gnu.org.
26 
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29 
30 HISTORY
31 --------------------------------------------------------------------------------
32 08/24/00 JSB Created
33 01/01/10 T.Kreitler test implementation
34 11/15/10 T.Kreitler treated flow solver bug, flow and torque calculations
35  simplified, tiploss influence removed from flapping angles
36 01/10/11 T.Kreitler changed to single rotor model
37 03/06/11 T.Kreitler added brake, clutch, and experimental free-wheeling-unit,
38  reasonable estimate for inflowlag
39 02/05/12 T.Kreitler brake, clutch, and FWU now in FGTransmission,
40  downwash angles relate to shaft orientation
41 
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 INCLUDES
44 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
45 
46 #include <string>
47 #include <sstream>
48 
49 #include "FGRotor.h"
50 #include "models/FGMassBalance.h"
51 #include "models/FGPropulsion.h" // to get the GearRatio from a linked rotor
52 #include "input_output/FGXMLElement.h"
53 
54 using std::cerr;
55 using std::cout;
56 using std::endl;
57 using std::string;
58 using std::ostringstream;
59 
60 namespace JSBSim {
61 
62 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63 MISC
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
65 
66 static inline double sqr(double x) { return x*x; }
67 
68 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69 CLASS IMPLEMENTATION
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
71 
72 // Constructor
73 
74 FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
75  : FGThruster(exec, rotor_element, num),
76  rho(0.002356), // environment
77  Radius(0.0), BladeNum(0), // configuration parameters
78  Sense(1.0), NominalRPM(0.0), MinimalRPM(0.0), MaximalRPM(0.0),
79  ExternalRPM(0), RPMdefinition(0), ExtRPMsource(NULL), SourceGearRatio(1.0),
80  BladeChord(0.0), LiftCurveSlope(0.0), BladeTwist(0.0), HingeOffset(0.0),
81  BladeFlappingMoment(0.0), BladeMassMoment(0.0), PolarMoment(0.0),
82  InflowLag(0.0), TipLossB(0.0),
83  GroundEffectExp(0.0), GroundEffectShift(0.0), GroundEffectScaleNorm(1.0),
84  LockNumberByRho(0.0), Solidity(0.0), // derived parameters
85  RPM(0.0), Omega(0.0), // dynamic values
86  beta_orient(0.0),
87  a0(0.0), a_1(0.0), b_1(0.0), a_dw(0.0),
88  a1s(0.0), b1s(0.0),
89  H_drag(0.0), J_side(0.0), Torque(0.0), C_T(0.0),
90  lambda(-0.001), mu(0.0), nu(0.001), v_induced(0.0),
91  theta_downwash(0.0), phi_downwash(0.0),
92  ControlMap(eMainCtrl), // control
93  CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
94  Transmission(NULL), // interaction with engine
95  EngineRPM(0.0), MaxBrakePower(0.0), GearLoss(0.0), GearMoment(0.0)
96 {
97  FGColumnVector3 location(0.0, 0.0, 0.0), orientation(0.0, 0.0, 0.0);
98  Element *thruster_element;
99  double engine_power_est = 0.0;
100 
101  // initialise/set remaining variables
102  SetTransformType(FGForce::tCustom);
103  Type = ttRotor;
104  GearRatio = 1.0;
105 
106  dt = exec->GetDeltaT();
107  for (int i=0; i<5; i++) R[i] = 0.0;
108  for (int i=0; i<5; i++) B[i] = 0.0;
109 
110  // get positions
111  thruster_element = rotor_element->GetParent()->FindElement("sense");
112  if (thruster_element) {
113  double s = thruster_element->GetDataAsNumber();
114  if (s < -0.1) {
115  Sense = -1.0; // 'CW' as seen from above
116  } else if (s < 0.1) {
117  Sense = 0.0; // 'coaxial'
118  } else {
119  Sense = 1.0; // 'CCW' as seen from above
120  }
121  }
122 
123  thruster_element = rotor_element->GetParent()->FindElement("location");
124  if (thruster_element) {
125  location = thruster_element->FindElementTripletConvertTo("IN");
126  } else {
127  cerr << "No thruster location found." << endl;
128  }
129 
130  thruster_element = rotor_element->GetParent()->FindElement("orient");
131  if (thruster_element) {
132  orientation = thruster_element->FindElementTripletConvertTo("RAD");
133  } else {
134  cerr << "No thruster orientation found." << endl;
135  }
136 
137  SetLocation(location);
138  SetAnglesToBody(orientation);
139  InvTransform = Transform().Transposed(); // body to custom/native
140 
141  // wire controls
142  ControlMap = eMainCtrl;
143  if (rotor_element->FindElement("controlmap")) {
144  string cm = rotor_element->FindElementValue("controlmap");
145  cm = to_upper(cm);
146  if (cm == "TAIL") {
147  ControlMap = eTailCtrl;
148  } else if (cm == "TANDEM") {
149  ControlMap = eTandemCtrl;
150  } else {
151  cerr << "# found unknown controlmap: '" << cm << "' using main rotor config." << endl;
152  }
153  }
154 
155  // ExternalRPM -- is the RPM dictated ?
156  if (rotor_element->FindElement("ExternalRPM")) {
157  ExternalRPM = 1;
158  SourceGearRatio = 1.0;
159  RPMdefinition = (int) rotor_element->FindElementValueAsNumber("ExternalRPM");
160  int rdef = RPMdefinition;
161  if (RPMdefinition>=0) {
162  // avoid ourself and (still) unknown engines.
163  if (!exec->GetPropulsion()->GetEngine(RPMdefinition) || RPMdefinition==num) {
164  RPMdefinition = -1;
165  } else {
166  FGThruster *tr = exec->GetPropulsion()->GetEngine(RPMdefinition)->GetThruster();
167  SourceGearRatio = tr->GetGearRatio();
168  // cout << "# got sources' GearRatio: " << SourceGearRatio << endl;
169  }
170  }
171  if (RPMdefinition != rdef) {
172  cerr << "# discarded given RPM source (" << rdef << ") and switched to external control (-1)." << endl;
173  }
174  }
175 
176  // process rotor parameters
177  engine_power_est = Configure(rotor_element);
178 
179  // setup transmission if needed
180  if (!ExternalRPM) {
181 
182  Transmission = new FGTransmission(exec, num, dt);
183 
184  Transmission->SetThrusterMoment(PolarMoment);
185 
186  // The MOI sensed behind the gear ( MOI_engine*sqr(GearRatio) ).
187  GearMoment = ConfigValueConv(rotor_element, "gearmoment", 0.1*PolarMoment, "SLUG*FT2");
188  GearMoment = Constrain(1e-6, GearMoment, 1e9);
189  Transmission->SetEngineMoment(GearMoment);
190 
191  Transmission->SetMaxBrakePower(MaxBrakePower);
192 
193  GearLoss = ConfigValueConv(rotor_element, "gearloss", 0.0025 * engine_power_est, "HP");
194  GearLoss = Constrain(0.0, GearLoss, 1e9);
195  GearLoss *= hptoftlbssec;
196  Transmission->SetEngineFriction(GearLoss);
197 
198  }
199 
200  // shaft representation - a rather simple transform,
201  // but using a matrix is safer.
202  TboToHsr = { 0.0, 0.0, 1.0,
203  0.0, 1.0, 0.0,
204  -1.0, 0.0, 0.0 };
205  HsrToTbo = TboToHsr.Transposed();
206 
207  // smooth out jumps in hagl reported, otherwise the ground effect
208  // calculation would cause jumps too. 1Hz seems sufficient.
209  damp_hagl = Filter(1.0, dt);
210 
211  // enable import-export
212  bindmodel(exec->GetPropertyManager());
213 
214  Debug(0);
215 
216 } // Constructor
217 
218 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 
221  if (Transmission) delete Transmission;
222  Debug(1);
223 }
224 
225 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 
227 // 5in1: value-fetch-convert-default-return function
228 
229 double FGRotor::ConfigValueConv( Element* el, const string& ename, double default_val,
230  const string& unit, bool tell)
231 {
232 
233  Element *e = NULL;
234  double val = default_val;
235 
236  string pname = "*No parent element*";
237 
238  if (el) {
239  e = el->FindElement(ename);
240  pname = el->GetName();
241  }
242 
243  if (e) {
244  if (unit.empty()) {
245  val = e->GetDataAsNumber();
246  } else {
247  val = el->FindElementValueAsNumberConvertTo(ename,unit);
248  }
249  } else {
250  if (tell) {
251  cerr << pname << ": missing element '" << ename <<
252  "' using estimated value: " << default_val << endl;
253  }
254  }
255 
256  return val;
257 }
258 
259 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 
261 double FGRotor::ConfigValue(Element* el, const string& ename, double default_val, bool tell)
262 {
263  return ConfigValueConv(el, ename, default_val, "", tell);
264 }
265 
266 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 
268 // 1. read configuration and try to fill holes, ymmv
269 // 2. calculate derived parameters
270 double FGRotor::Configure(Element* rotor_element)
271 {
272 
273  double estimate, engine_power_est=0.0;
274  const bool yell = true;
275  const bool silent = false;
276 
277 
278  Radius = 0.5 * ConfigValueConv(rotor_element, "diameter", 42.0, "FT", yell);
279  Radius = Constrain(1e-3, Radius, 1e9);
280 
281  BladeNum = (int) ConfigValue(rotor_element, "numblades", 3 , yell);
282 
283  GearRatio = ConfigValue(rotor_element, "gearratio", 1.0, yell);
284  GearRatio = Constrain(1e-9, GearRatio, 1e9);
285 
286  // make sure that v_tip (omega*r) is below 0.7mach ~ 750ft/s
287  estimate = (750.0/Radius)/(2.0*M_PI) * 60.0; // 7160/Radius
288  NominalRPM = ConfigValue(rotor_element, "nominalrpm", estimate, yell);
289  NominalRPM = Constrain(2.0, NominalRPM, 1e9);
290 
291  MinimalRPM = ConfigValue(rotor_element, "minrpm", 1.0);
292  MinimalRPM = Constrain(1.0, MinimalRPM, NominalRPM - 1.0);
293 
294  MaximalRPM = ConfigValue(rotor_element, "maxrpm", 2.0*NominalRPM);
295  MaximalRPM = Constrain(NominalRPM, MaximalRPM, 1e9);
296 
297  estimate = Constrain(0.07, 2.0/Radius , 0.14); // guess solidity
298  estimate = estimate * M_PI*Radius/BladeNum;
299  BladeChord = ConfigValueConv(rotor_element, "chord", estimate, "FT", yell);
300 
301  LiftCurveSlope = ConfigValue(rotor_element, "liftcurveslope", 6.0); // "1/RAD"
302  BladeTwist = ConfigValueConv(rotor_element, "twist", -0.17, "RAD");
303 
304  HingeOffset = ConfigValueConv(rotor_element, "hingeoffset", 0.05 * Radius, "FT" );
305 
306  estimate = sqr(BladeChord) * sqr(Radius - HingeOffset) * 0.57;
307  BladeFlappingMoment = ConfigValueConv(rotor_element, "flappingmoment", estimate, "SLUG*FT2");
308  BladeFlappingMoment = Constrain(1e-9, BladeFlappingMoment, 1e9);
309 
310  // guess mass from moment of a thin stick, and multiply by the blades cg distance
311  estimate = ( 3.0 * BladeFlappingMoment / sqr(Radius) ) * (0.45 * Radius) ;
312  BladeMassMoment = ConfigValue(rotor_element, "massmoment", estimate); // unit is slug-ft
313  BladeMassMoment = Constrain(1e-9, BladeMassMoment, 1e9);
314 
315  estimate = 1.1 * BladeFlappingMoment * BladeNum;
316  PolarMoment = ConfigValueConv(rotor_element, "polarmoment", estimate, "SLUG*FT2");
317  PolarMoment = Constrain(1e-9, PolarMoment, 1e9);
318 
319  // "inflowlag" is treated further down.
320 
321  TipLossB = ConfigValue(rotor_element, "tiplossfactor", 1.0, silent);
322 
323  // estimate engine power (bit of a pity, cause our caller already knows)
324  engine_power_est = 0.5 * BladeNum*BladeChord*Radius*Radius;
325 
326  estimate = engine_power_est / 30.0;
327  MaxBrakePower = ConfigValueConv(rotor_element, "maxbrakepower", estimate, "HP");
328  MaxBrakePower *= hptoftlbssec;
329 
330  GroundEffectExp = ConfigValue(rotor_element, "groundeffectexp", 0.0);
331  GroundEffectShift = ConfigValueConv(rotor_element, "groundeffectshift", 0.0, "FT");
332 
333  // precalc often used powers
334  R[0]=1.0; R[1]=Radius; R[2]=R[1]*R[1]; R[3]=R[2]*R[1]; R[4]=R[3]*R[1];
335  B[0]=1.0; B[1]=TipLossB; B[2]=B[1]*B[1]; B[3]=B[2]*B[1]; B[4]=B[3]*B[1];
336 
337  // derived parameters
338  LockNumberByRho = LiftCurveSlope * BladeChord * R[4] / BladeFlappingMoment;
339  Solidity = BladeNum * BladeChord / (M_PI * Radius);
340 
341  // estimate inflow lag, see /GE49/ eqn(1)
342  double omega_tmp = (NominalRPM/60.0)*2.0*M_PI;
343  estimate = 16.0/(LockNumberByRho*rho * omega_tmp ); // 16/(gamma*Omega)
344  // printf("# Est. InflowLag: %f\n", estimate);
345  InflowLag = ConfigValue(rotor_element, "inflowlag", estimate, yell);
346  InflowLag = Constrain(1e-6, InflowLag, 2.0);
347 
348  return engine_power_est;
349 } // Configure
350 
351 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 
353 // calculate control-axes components of total airspeed at the hub.
354 // sets rotor orientation angle (beta) as side effect. /SH79/ eqn(19-22)
355 
356 FGColumnVector3 FGRotor::hub_vel_body2ca( const FGColumnVector3 &uvw,
357  const FGColumnVector3 &pqr,
358  double a_ic, double b_ic)
359 {
360  FGColumnVector3 v_r, v_shaft, v_w;
361  FGColumnVector3 pos;
362 
363  pos = fdmex->GetMassBalance()->StructuralToBody(GetActingLocation());
364 
365  v_r = uvw + pqr*pos;
366  v_shaft = TboToHsr * InvTransform * v_r;
367 
368  beta_orient = atan2(v_shaft(eV),v_shaft(eU));
369 
370  v_w(eU) = v_shaft(eU)*cos(beta_orient) + v_shaft(eV)*sin(beta_orient);
371  v_w(eV) = 0.0;
372  v_w(eW) = v_shaft(eW) - b_ic*v_shaft(eU) - a_ic*v_shaft(eV);
373 
374  return v_w;
375 }
376 
377 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 
379 // express fuselage angular velocity in control axes /SH79/ eqn(30,31)
380 
381 FGColumnVector3 FGRotor::fus_angvel_body2ca( const FGColumnVector3 &pqr)
382 {
383  FGColumnVector3 av_s_fus, av_w_fus;
384 
385  // for comparison:
386  // av_s_fus = BodyToShaft * pqr; /SH79/
387  // BodyToShaft = TboToHsr * InvTransform
388  av_s_fus = TboToHsr * InvTransform * pqr;
389 
390  av_w_fus(eP)= av_s_fus(eP)*cos(beta_orient) + av_s_fus(eQ)*sin(beta_orient);
391  av_w_fus(eQ)= - av_s_fus(eP)*sin(beta_orient) + av_s_fus(eQ)*cos(beta_orient);
392  av_w_fus(eR)= av_s_fus(eR);
393 
394  return av_w_fus;
395 }
396 
397 
398 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399 
400 // The calculation is a bit tricky because thrust depends on induced velocity,
401 // and vice versa.
402 //
403 // The flow_scale parameter (ranging from 0.5-1.0) is used to approximate a
404 // reduction of inflow if the helicopter is close to the ground, yielding to
405 // higher thrust, see /TA77/ eqn(10a).
406 
407 void FGRotor::calc_flow_and_thrust( double theta_0, double Uw, double Ww,
408  double flow_scale)
409 {
410 
411  double ct_over_sigma = 0.0;
412  double c0, ct_l, ct_t0, ct_t1;
413  double mu2;
414 
415  mu = Uw/(Omega*Radius); // /SH79/ eqn(24)
416  if (mu > 0.7) mu = 0.7;
417  mu2 = sqr(mu);
418 
419  ct_t0 = (1.0/3.0*B[3] + 1.0/2.0 * TipLossB*mu2 - 4.0/(9.0*M_PI) * mu*mu2 ) * theta_0;
420  ct_t1 = (1.0/4.0*B[4] + 1.0/4.0 * B[2]*mu2) * BladeTwist;
421 
422  ct_l = (1.0/2.0*B[2] + 1.0/4.0 * mu2) * lambda; // first time
423 
424  c0 = (LiftCurveSlope/2.0)*(ct_l + ct_t0 + ct_t1) * Solidity;
425  c0 = c0 / ( 2.0 * sqrt( sqr(mu) + sqr(lambda) ) + 1e-15);
426 
427  // replacement for /SH79/ eqn(26).
428  // ref: dnu/dt = 1/tau ( Ct / (2*sqrt(mu^2+lambda^2)) - nu )
429  // taking mu and lambda constant, this integrates to
430 
431  nu = flow_scale * ((nu - c0) * exp(-dt/InflowLag) + c0);
432 
433  // now from nu to lambda, C_T, and Thrust
434 
435  lambda = Ww/(Omega*Radius) - nu; // /SH79/ eqn(25)
436 
437  ct_l = (1.0/2.0*B[2] + 1.0/4.0 * mu2) * lambda;
438 
439  ct_over_sigma = (LiftCurveSlope/2.0)*(ct_l + ct_t0 + ct_t1); // /SH79/ eqn(27)
440 
441  Thrust = BladeNum*BladeChord*Radius*rho*sqr(Omega*Radius) * ct_over_sigma;
442 
443  C_T = ct_over_sigma * Solidity;
444  v_induced = nu * (Omega*Radius);
445 
446 }
447 
448 
449 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450 
451 // Two blade teetering rotors are often 'preconed' to a fixed angle, but the
452 // calculated value is pretty close to the real one. /SH79/ eqn(29)
453 
454 void FGRotor::calc_coning_angle(double theta_0)
455 {
456  double lock_gamma = LockNumberByRho * rho;
457 
458  double a0_l = (1.0/6.0 + 0.04 * mu*mu*mu) * lambda;
459  double a0_t0 = (1.0/8.0 + 1.0/8.0 * mu*mu) * theta_0;
460  double a0_t1 = (1.0/10.0 + 1.0/12.0 * mu*mu) * BladeTwist;
461  a0 = lock_gamma * ( a0_l + a0_t0 + a0_t1);
462  return;
463 }
464 
465 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 
467 // Flapping angles relative to control axes /SH79/ eqn(32)
468 
469 void FGRotor::calc_flapping_angles(double theta_0, const FGColumnVector3 &pqr_fus_w)
470 {
471  double lock_gamma = LockNumberByRho * rho;
472 
473 
474  double mu2_2 = sqr(mu)/2.0;
475  double t075 = theta_0 + 0.75 * BladeTwist; // common approximation for rectangular blades
476 
477  a_1 = 1.0/(1.0 - mu2_2) * (
478  (2.0*lambda + (8.0/3.0)*t075)*mu
479  + pqr_fus_w(eP)/Omega
480  - 16.0 * pqr_fus_w(eQ)/(lock_gamma*Omega)
481  );
482 
483  b_1 = 1.0/(1.0 + mu2_2) * (
484  (4.0/3.0)*mu*a0
485  - pqr_fus_w(eQ)/Omega
486  - 16.0 * pqr_fus_w(eP)/(lock_gamma*Omega)
487  );
488 
489  // used in force calc
490  a_dw = 1.0/(1.0 - mu2_2) * (
491  (2.0*lambda + (8.0/3.0)*t075)*mu
492  - 24.0 * pqr_fus_w(eQ)/(lock_gamma*Omega)
493  * ( 1.0 - ( 0.29 * t075 / (C_T/Solidity) ) )
494  );
495 
496  return;
497 }
498 
499 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 
501 // /SH79/ eqn(38,39)
502 
503 void FGRotor::calc_drag_and_side_forces(double theta_0)
504 {
505  double cy_over_sigma;
506  double t075 = theta_0 + 0.75 * BladeTwist;
507 
508  H_drag = Thrust * a_dw;
509 
510  cy_over_sigma = (
511  0.75*b_1*lambda - 1.5*a0*mu*lambda + 0.25*a_1*b_1*mu
512  - a0*a_1*sqr(mu) + (1.0/6.0)*a0*a_1
513  - (0.75*mu*a0 - (1.0/3.0)*b_1 - 0.5*sqr(mu)*b_1)*t075
514  );
515  cy_over_sigma *= LiftCurveSlope/2.0;
516 
517  J_side = BladeNum * BladeChord * Radius * rho * sqr(Omega*Radius) * cy_over_sigma;
518 
519  return;
520 }
521 
522 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 
524 // Simplified version of /SH79/ eqn(36). Uses an estimate for blade drag
525 // (a new config parameter to come...).
526 // From "Bramwell's Helicopter Dynamics", second edition, eqn(3.43) and (3.44)
527 
528 void FGRotor::calc_torque(double theta_0)
529 {
530  // estimate blade drag
531  double delta_dr = 0.009 + 0.3*sqr(6.0*C_T/(LiftCurveSlope*Solidity));
532 
533  Torque = rho * BladeNum * BladeChord * delta_dr * sqr(Omega*Radius) * R[2] *
534  (1.0+4.5*sqr(mu))/8.0
535  - (Thrust*lambda + H_drag*mu)*Radius;
536 
537  return;
538 }
539 
540 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 
542 // Get the downwash angles with respect to the shaft axis.
543 // Given a 'regular' main rotor, the angles are zero when the downwash points
544 // down, positive theta values mean that the downwash turns towards the nose,
545 // and positive phi values mean it turns to the left side. (Note: only airspeed
546 // is transformed, the rotational speed contribution is ignored.)
547 
548 void FGRotor::calc_downwash_angles()
549 {
550  FGColumnVector3 v_shaft;
551  v_shaft = TboToHsr * InvTransform * in.AeroUVW;
552 
553  theta_downwash = atan2( -v_shaft(eU), v_induced - v_shaft(eW)) + a1s;
554  phi_downwash = atan2( v_shaft(eV), v_induced - v_shaft(eW)) + b1s;
555 
556  return;
557 }
558 
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 
561 // transform rotor forces from control axes to shaft axes, and express
562 // in body axes /SH79/ eqn(40,41)
563 
564 FGColumnVector3 FGRotor::body_forces(double a_ic, double b_ic)
565 {
566  FGColumnVector3 F_s(
567  - H_drag*cos(beta_orient) - J_side*sin(beta_orient) + Thrust*b_ic,
568  - H_drag*sin(beta_orient) + J_side*cos(beta_orient) + Thrust*a_ic,
569  - Thrust);
570 
571  return HsrToTbo * F_s;
572 }
573 
574 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 
576 // calculates the additional moments due to hinge offset and handles
577 // torque and sense
578 
579 FGColumnVector3 FGRotor::body_moments(double a_ic, double b_ic)
580 {
581  FGColumnVector3 M_s, M_hub, M_h;
582  double mf;
583 
584  // cyclic flapping relative to shaft axes /SH79/ eqn(43)
585  a1s = a_1*cos(beta_orient) + b_1*sin(beta_orient) - b_ic;
586  b1s = b_1*cos(beta_orient) - a_1*sin(beta_orient) + a_ic;
587 
588  mf = 0.5 * HingeOffset * BladeNum * Omega*Omega * BladeMassMoment;
589 
590  M_s(eL) = mf*b1s;
591  M_s(eM) = mf*a1s;
592  M_s(eN) = Torque * Sense ;
593 
594  return HsrToTbo * M_s;
595 }
596 
597 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 
599 void FGRotor::CalcRotorState(void)
600 {
601  double A_IC; // lateral (roll) control in radians
602  double B_IC; // longitudinal (pitch) control in radians
603  double theta_col; // rotor collective pitch in radians
604 
605  FGColumnVector3 vHub_ca, avFus_ca;
606 
607  double filtered_hagl = 0.0;
608  double ge_factor = 1.0;
609 
610  // fetch needed values from environment
611  rho = in.Density; // slugs/ft^3.
612  double h_agl_ft = in.H_agl;
613 
614  // update InvTransform, the rotor orientation could have been altered
615  InvTransform = Transform().Transposed();
616 
617  // handle RPM requirements, calc omega.
618  if (ExternalRPM && ExtRPMsource) {
619  RPM = ExtRPMsource->getDoubleValue() * ( SourceGearRatio / GearRatio );
620  }
621 
622  // MinimalRPM is always >= 1. MaximalRPM is always >= NominalRPM
623  RPM = Constrain(MinimalRPM, RPM, MaximalRPM);
624 
625  Omega = (RPM/60.0)*2.0*M_PI;
626 
627  // set control inputs
628  A_IC = LateralCtrl;
629  B_IC = LongitudinalCtrl;
630  theta_col = CollectiveCtrl;
631 
632  // optional ground effect, a ge_factor of 1.0 gives no effect
633  // and 0.5 yields to maximal influence.
634  if (GroundEffectExp > 1e-5) {
635  if (h_agl_ft<0.0) h_agl_ft = 0.0; // clamp
636  filtered_hagl = damp_hagl.execute(h_agl_ft) + GroundEffectShift;
637  // actual/nominal factor avoids absurd scales at startup
638  ge_factor -= GroundEffectScaleNorm *
639  ( exp(-filtered_hagl*GroundEffectExp) * (RPM / NominalRPM) );
640  ge_factor = Constrain(0.5, ge_factor, 1.0);
641  }
642 
643  // all set, start calculations ...
644 
645  vHub_ca = hub_vel_body2ca(in.AeroUVW, in.AeroPQR, A_IC, B_IC);
646 
647  avFus_ca = fus_angvel_body2ca(in.AeroPQR);
648 
649  calc_flow_and_thrust(theta_col, vHub_ca(eU), vHub_ca(eW), ge_factor);
650 
651  calc_coning_angle(theta_col);
652 
653  calc_flapping_angles(theta_col, avFus_ca);
654 
655  calc_drag_and_side_forces(theta_col);
656 
657  calc_torque(theta_col);
658 
659  calc_downwash_angles();
660 
661  // ... and assign to inherited vFn and vMn members
662  // (for processing see FGForce::GetBodyForces).
663  vFn = body_forces(A_IC, B_IC);
664  vMn = Transform() * body_moments(A_IC, B_IC);
665 
666 }
667 
668 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 
670 double FGRotor::Calculate(double EnginePower)
671 {
672 
673  CalcRotorState();
674 
675  if (! ExternalRPM) {
676  // the RPM values are handled inside Transmission
677  Transmission->Calculate(EnginePower, Torque, in.TotalDeltaT);
678 
679  EngineRPM = Transmission->GetEngineRPM() * GearRatio;
680  RPM = Transmission->GetThrusterRPM();
681  } else {
682  EngineRPM = RPM * GearRatio;
683  }
684 
685  RPM = Constrain(MinimalRPM, RPM, MaximalRPM); // trim again
686 
687  return Thrust;
688 }
689 
690 
691 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 
693 
694 bool FGRotor::bindmodel(FGPropertyManager* PropertyManager)
695 {
696  string property_name, base_property_name;
697  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNum);
698 
699  property_name = base_property_name + "/rotor-rpm";
700  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetRPM );
701 
702  property_name = base_property_name + "/engine-rpm";
703  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetEngineRPM );
704 
705  property_name = base_property_name + "/a0-rad";
706  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetA0 );
707 
708  property_name = base_property_name + "/a1-rad";
709  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetA1 );
710 
711  property_name = base_property_name + "/b1-rad";
712  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetB1 );
713 
714  property_name = base_property_name + "/inflow-ratio";
715  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLambda );
716 
717  property_name = base_property_name + "/advance-ratio";
718  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetMu );
719 
720  property_name = base_property_name + "/induced-inflow-ratio";
721  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetNu );
722 
723  property_name = base_property_name + "/vi-fps";
724  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetVi );
725 
726  property_name = base_property_name + "/thrust-coefficient";
727  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetCT );
728 
729  property_name = base_property_name + "/torque-lbsft";
730  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetTorque );
731 
732  property_name = base_property_name + "/theta-downwash-rad";
733  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetThetaDW );
734 
735  property_name = base_property_name + "/phi-downwash-rad";
736  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetPhiDW );
737 
738  property_name = base_property_name + "/groundeffect-scale-norm";
739  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetGroundEffectScaleNorm,
741 
742  switch (ControlMap) {
743  case eTailCtrl:
744  property_name = base_property_name + "/antitorque-ctrl-rad";
745  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetCollectiveCtrl, &FGRotor::SetCollectiveCtrl);
746  break;
747  case eTandemCtrl:
748  property_name = base_property_name + "/tail-collective-ctrl-rad";
749  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetCollectiveCtrl, &FGRotor::SetCollectiveCtrl);
750  property_name = base_property_name + "/lateral-ctrl-rad";
751  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLateralCtrl, &FGRotor::SetLateralCtrl);
752  property_name = base_property_name + "/longitudinal-ctrl-rad";
753  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLongitudinalCtrl, &FGRotor::SetLongitudinalCtrl);
754  break;
755  default: // eMainCtrl
756  property_name = base_property_name + "/collective-ctrl-rad";
757  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetCollectiveCtrl, &FGRotor::SetCollectiveCtrl);
758  property_name = base_property_name + "/lateral-ctrl-rad";
759  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLateralCtrl, &FGRotor::SetLateralCtrl);
760  property_name = base_property_name + "/longitudinal-ctrl-rad";
761  PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLongitudinalCtrl, &FGRotor::SetLongitudinalCtrl);
762  }
763 
764  if (ExternalRPM) {
765  if (RPMdefinition == -1) {
766  property_name = base_property_name + "/x-rpm-dict";
767  ExtRPMsource = PropertyManager->GetNode(property_name, true);
768  } else if (RPMdefinition >= 0 && RPMdefinition != EngineNum) {
769  string ipn = CreateIndexedPropertyName("propulsion/engine", RPMdefinition);
770  property_name = ipn + "/rotor-rpm";
771  ExtRPMsource = PropertyManager->GetNode(property_name, false);
772  if (! ExtRPMsource) {
773  cerr << "# Warning: Engine number " << EngineNum << "." << endl;
774  cerr << "# No 'rotor-rpm' property found for engine " << RPMdefinition << "." << endl;
775  cerr << "# Please check order of engine definitons." << endl;
776  }
777  } else {
778  cerr << "# Engine number " << EngineNum;
779  cerr << ", given ExternalRPM value '" << RPMdefinition << "' unhandled." << endl;
780  }
781  }
782 
783  return true;
784 }
785 
786 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 
788 string FGRotor::GetThrusterLabels(int id, const string& delimeter)
789 {
790 
791  ostringstream buf;
792 
793  buf << Name << " RPM (engine " << id << ")";
794 
795  return buf.str();
796 
797 }
798 
799 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800 
801 string FGRotor::GetThrusterValues(int id, const string& delimeter)
802 {
803 
804  ostringstream buf;
805 
806  buf << RPM;
807 
808  return buf.str();
809 
810 }
811 
812 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 // The bitmasked value choices are as follows:
814 // unset: In this case (the default) JSBSim would only print
815 // out the normally expected messages, essentially echoing
816 // the config files as they are read. If the environment
817 // variable is not set, debug_lvl is set to 1 internally
818 // 0: This requests JSBSim not to output any messages
819 // whatsoever.
820 // 1: This value explicity requests the normal JSBSim
821 // startup messages
822 // 2: This value asks for a message to be printed out when
823 // a class is instantiated
824 // 4: When this value is set, a message is displayed when a
825 // FGModel object executes its Run() method
826 // 8: When this value is set, various runtime state variables
827 // are printed out periodically
828 // 16: When set various parameters are sanity checked and
829 // a message is printed out when they go out of bounds
830 
831 void FGRotor::Debug(int from)
832 {
833  string ControlMapName;
834 
835  if (debug_lvl <= 0) return;
836 
837  if (debug_lvl & 1) { // Standard console startup message output
838  if (from == 0) { // Constructor
839  cout << "\n Rotor Name: " << Name << endl;
840  cout << " Diameter = " << 2.0 * Radius << " ft." << endl;
841  cout << " Number of Blades = " << BladeNum << endl;
842  cout << " Gear Ratio = " << GearRatio << endl;
843  cout << " Sense = " << Sense << endl;
844  cout << " Nominal RPM = " << NominalRPM << endl;
845  cout << " Minimal RPM = " << MinimalRPM << endl;
846  cout << " Maximal RPM = " << MaximalRPM << endl;
847 
848  if (ExternalRPM) {
849  if (RPMdefinition == -1) {
850  cout << " RPM is controlled externally" << endl;
851  } else {
852  cout << " RPM source set to thruster " << RPMdefinition << endl;
853  }
854  }
855 
856  cout << " Blade Chord = " << BladeChord << endl;
857  cout << " Lift Curve Slope = " << LiftCurveSlope << endl;
858  cout << " Blade Twist = " << BladeTwist << endl;
859  cout << " Hinge Offset = " << HingeOffset << endl;
860  cout << " Blade Flapping Moment = " << BladeFlappingMoment << endl;
861  cout << " Blade Mass Moment = " << BladeMassMoment << endl;
862  cout << " Polar Moment = " << PolarMoment << endl;
863  cout << " Inflow Lag = " << InflowLag << endl;
864  cout << " Tip Loss = " << TipLossB << endl;
865  cout << " Lock Number = " << LockNumberByRho * 0.002356 << " (SL)" << endl;
866  cout << " Solidity = " << Solidity << endl;
867  cout << " Max Brake Power = " << MaxBrakePower/hptoftlbssec << " HP" << endl;
868  cout << " Gear Loss = " << GearLoss/hptoftlbssec << " HP" << endl;
869  cout << " Gear Moment = " << GearMoment << endl;
870 
871  switch (ControlMap) {
872  case eTailCtrl: ControlMapName = "Tail Rotor"; break;
873  case eTandemCtrl: ControlMapName = "Tandem Rotor"; break;
874  default: ControlMapName = "Main Rotor";
875  }
876  cout << " Control Mapping = " << ControlMapName << endl;
877 
878  }
879  }
880  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
881  if (from == 0) cout << "Instantiated: FGRotor" << endl;
882  if (from == 1) cout << "Destroyed: FGRotor" << endl;
883  }
884  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
885  }
886  if (debug_lvl & 8 ) { // Runtime state variables
887  }
888  if (debug_lvl & 16) { // Sanity checking
889  }
890  if (debug_lvl & 64) {
891  if (from == 0) { // Constructor
892  }
893  }
894 
895 }
896 
897 } // namespace JSBSim
JSBSim::FGRotor::~FGRotor
~FGRotor()
Destructor for FGRotor.
Definition: FGRotor.cpp:220
JSBSim::FGRotor::GetVi
double GetVi(void) const
Retrieves the induced velocity.
Definition: FGRotor.h:283
JSBSim::FGFDMExec
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:185
JSBSim::Element::GetParent
Element * GetParent(void)
Returns a pointer to the parent of an element.
Definition: FGXMLElement.h:225
JSBSim::FGRotor::SetLateralCtrl
void SetLateralCtrl(double c)
Sets the lateral control input in radians.
Definition: FGRotor.h:309
JSBSim::FGRotor::GetThetaDW
double GetThetaDW(void) const
Downwash angle - positive values point forward (given a horizontal spinning rotor)
Definition: FGRotor.h:290
JSBSim::FGColumnVector3
This class implements a 3 element column vector.
Definition: FGColumnVector3.h:63
JSBSim::FGMassBalance::StructuralToBody
FGColumnVector3 StructuralToBody(const FGColumnVector3 &r) const
Conversion from the structural frame to the body frame.
Definition: FGMassBalance.cpp:364
JSBSim::Element::FindElement
Element * FindElement(const std::string &el="")
Searches for a specified element.
Definition: FGXMLElement.cpp:389
JSBSim::Element::FindElementValueAsNumber
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Definition: FGXMLElement.cpp:429
JSBSim::FGPropulsion::GetEngine
FGEngine * GetEngine(unsigned int index) const
Retrieves an engine object pointer from the list of engines.
Definition: FGPropulsion.h:133
JSBSim::FGRotor::GetRPM
double GetRPM(void) const
Retrieves the RPMs of the rotor.
Definition: FGRotor.h:258
JSBSim::FGRotor::SetLongitudinalCtrl
void SetLongitudinalCtrl(double c)
Sets the longitudinal control input in radians.
Definition: FGRotor.h:311
JSBSim::Element::FindElementValueAsNumberConvertTo
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.
Definition: FGXMLElement.cpp:480
JSBSim::FGRotor::GetA1
double GetA1(void) const
Retrieves the longitudinal flapping angle with respect to the rotor shaft.
Definition: FGRotor.h:272
JSBSim::FGFDMExec::GetPropertyManager
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
Definition: FGFDMExec.cpp:1121
JSBSim::FGRotor::GetCT
double GetCT(void) const
Retrieves the thrust coefficient.
Definition: FGRotor.h:285
JSBSim::FGRotor::GetEngineRPM
double GetEngineRPM(void) const
Retrieves the RPMs of the Engine, as seen from this rotor.
Definition: FGRotor.h:262
JSBSim::FGRotor::SetCollectiveCtrl
void SetCollectiveCtrl(double c)
Sets the collective control input in radians.
Definition: FGRotor.h:307
JSBSim::FGRotor::GetLongitudinalCtrl
double GetLongitudinalCtrl(void) const
Retrieves the longitudinal control input in radians.
Definition: FGRotor.h:304
JSBSim::FGTransmission
Utility class that handles power transmission in conjunction with FGRotor.
Definition: FGTransmission.h:108
JSBSim::FGRotor::GetPhiDW
double GetPhiDW(void) const
Downwash angle - positive values point leftward (given a horizontal spinning rotor)
Definition: FGRotor.h:292
JSBSim::FGRotor::SetGroundEffectScaleNorm
void SetGroundEffectScaleNorm(double g)
Sets the ground effect scaling factor.
Definition: FGRotor.h:297
JSBSim::Element::GetDataAsNumber
double GetDataAsNumber(void)
Converts the element data to a number.
Definition: FGXMLElement.cpp:341
JSBSim::FGMatrix33::Transposed
FGMatrix33 Transposed(void) const
Transposed matrix.
Definition: FGMatrix33.h:221
JSBSim::FGFDMExec::GetMassBalance
FGMassBalance * GetMassBalance(void)
Returns the FGAircraft pointer.
Definition: FGFDMExec.h:363
JSBSim::Element::FindElementValue
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
Definition: FGXMLElement.cpp:468
JSBSim::FGFDMExec::GetDeltaT
double GetDeltaT(void) const
Returns the simulation delta T.
Definition: FGFDMExec.h:545
JSBSim::FGRotor::GetCollectiveCtrl
double GetCollectiveCtrl(void) const
Retrieves the collective control input in radians.
Definition: FGRotor.h:300
JSBSim::FGFDMExec::GetPropulsion
FGPropulsion * GetPropulsion(void)
Returns the FGPropulsion pointer.
Definition: FGFDMExec.h:361
JSBSim::FGRotor::GetNu
double GetNu(void) const
Retrieves the induced inflow ratio.
Definition: FGRotor.h:281
JSBSim::Element::GetName
const std::string & GetName(void) const
Retrieves the element name.
Definition: FGXMLElement.h:179
JSBSim::FGRotor::GetA0
double GetA0(void) const
Retrieves the rotor's coning angle.
Definition: FGRotor.h:270
JSBSim::FGJSBBase::Constrain
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
Definition: FGJSBBase.h:333
JSBSim::FGRotor::FGRotor
FGRotor(FGFDMExec *exec, Element *rotor_element, int num)
Constructor for FGRotor.
Definition: FGRotor.cpp:74
JSBSim::FGRotor::GetLambda
double GetLambda(void) const
Retrieves the inflow ratio.
Definition: FGRotor.h:277
JSBSim::FGRotor::GetLateralCtrl
double GetLateralCtrl(void) const
Retrieves the lateral control input in radians.
Definition: FGRotor.h:302
JSBSim::FGRotor::GetB1
double GetB1(void) const
Retrieves the lateral flapping angle with respect to the rotor shaft.
Definition: FGRotor.h:274
JSBSim::FGJSBBase::Filter
First order, (low pass / lag) filter.
Definition: FGJSBBase.h:99
JSBSim::FGThruster
Base class for specific thrusting devices such as propellers, nozzles, etc.
Definition: FGThruster.h:77
JSBSim::FGRotor::GetTorque
double GetTorque(void) const
Retrieves the torque.
Definition: FGRotor.h:287
JSBSim::FGPropertyManager
Definition: FGPropertyManager.h:373
JSBSim::Element
Definition: FGXMLElement.h:143
JSBSim::FGRotor::Calculate
double Calculate(double EnginePower)
Returns the scalar thrust of the rotor, and adjusts the RPM value.
Definition: FGRotor.cpp:670
JSBSim::FGRotor::GetMu
double GetMu(void) const
Retrieves the tip-speed (aka advance) ratio.
Definition: FGRotor.h:279
JSBSim::FGPropertyManager::Tie
void Tie(const std::string &name, T *pointer)
Tie a property to an external variable.
Definition: FGPropertyManager.h:449
JSBSim::FGRotor::GetGroundEffectScaleNorm
double GetGroundEffectScaleNorm(void) const
Retrieves the ground effect scaling factor.
Definition: FGRotor.h:295
JSBSim::Element::FindElementTripletConvertTo
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
Definition: FGXMLElement.cpp:589