1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7 ------------- Copyright (C) 2010 T. Kreitler (t.kreitler@web.de) -------------
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 Software
11 Foundation; either version 2 of the License, or (at your option) any later
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
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA.
23 Further information about the GNU Lesser General Public License can also be found on
24 the world wide web at http://www.gnu.org.
27 --------------------------------------------------------------------------------
28 01/01/10 T.Kreitler test implementation
29 01/10/11 T.Kreitler changed to single rotor model
30 03/06/11 T.Kreitler added brake, clutch, and experimental free-wheeling-unit
31 02/05/12 T.Kreitler brake, clutch, and FWU now in FGTransmission class
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44 #include "FGThruster.h"
45 #include "FGTransmission.h"
47 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51 #define ID_ROTOR "$Id: FGRotor.h,v 1.14 2012/03/18 15:48:36 jentron Exp $"
53 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
63 /** Models a helicopter rotor.
66 <h3>Configuration File Format</h3>
68 <rotor name="{string}">
69 <diameter unit="{LENGTH}"> {number} </diameter>
70 <numblades> {number} </numblades>
71 <gearratio> {number} </gearratio>
72 <nominalrpm> {number} </nominalrpm>
73 <minrpm> {number} </minrpm>
74 <maxrpm> {number} </maxrpm>
75 <chord unit="{LENGTH}"> {number} </chord>
76 <liftcurveslope Xunit="1/RAD"> {number} </liftcurveslope>
77 <twist unit="{ANGLE}"> {number} </twist>
78 <hingeoffset unit="{LENGTH}"> {number} </hingeoffset>
79 <flappingmoment unit="{MOMENT}"> {number} </flappingmoment>
80 <massmoment Xunit="SLUG*FT"> {number} </massmoment>
81 <polarmoment unit="{MOMENT}"> {number} </polarmoment>
82 <inflowlag> {number} </inflowlag>
83 <tiplossfactor> {number} </tiplossfactor>
84 <maxbrakepower unit="{POWER}"> {number} </maxbrakepower>
85 <gearloss unit="{POWER}"> {number} </gearloss>
86 <gearmoment unit="{MOMENT}"> {number} </gearmoment>
88 <controlmap> {MAIN|TAIL|TANDEM} </controlmap>
89 <ExternalRPM> {number} </ExternalRPM>
91 <groundeffectexp> {number} </groundeffectexp>
92 <groundeffectshift unit="{LENGTH}"> {number} </groundeffectshift>
96 // LENGTH means any of the supported units, same for ANGLE and MOMENT.
97 // Xunit-attributes are a hint for currently unsupported units, so
98 // values must be provided accordingly.
102 <h3>Configuration Parameters:</h3>
104 Brief description and the symbol frequently found in the literature.
107 \<diameter> - Rotor disk diameter (2x R).
108 \<numblades> - Number of blades (b).
109 \<gearratio> - Ratio of (engine rpm) / (rotor rpm), usually > 1.
110 \<nominalrpm> - RPM at which the rotor usally operates.
111 \<minrpm> - Lowest RPM used in the model, optional and defaults to 1.
112 \<maxrpm> - Largest RPM used in the model, optional and defaults to 2 x nominalrpm.
113 \<chord> - Blade chord, (c).
114 \<liftcurveslope> - Slope of curve of section lift against section angle of attack,
116 \<twist> - Blade twist from root to tip, (theta_1).
117 \<hingeoffset> - Rotor flapping-hinge offset (e).
118 \<flappingmoment> - Flapping moment of inertia (I_b).
119 \<massmoment> - Blade mass moment. Mass of a single blade times the blade's
120 cg-distance from the hub, optional.
121 \<polarmoment> - Moment of inertia for the whole rotor disk, optional.
122 \<inflowlag> - Rotor inflow time constant, sec. Smaller values yield to quicker
123 responses (typical values for main rotor: 0.1 - 0.2 s).
124 \<tiplossfactor> - Tip-loss factor. The Blade fraction that produces lift.
125 Value usually ranges between 0.95 - 1.0, optional (B).
127 \<maxbrakepower> - Rotor brake, 20-30 hp should work for a mid size helicopter.
128 \<gearloss> - Friction in gear, 0.2% to 3% of the engine power, optional (see notes).
129 \<gearmoment> - Approximation for the moment of inertia of the gear (and engine),
130 defaults to 0.1 * polarmoment, optional.
132 \<controlmap> - Defines the control inputs used (see notes).
134 \<ExternalRPM> - Links the rotor to another rotor, or an user controllable property.
136 Experimental properties
138 \<groundeffectexp> - Exponent for ground effect approximation. Values usually range from 0.04
139 for large rotors to 0.1 for smaller ones. As a rule of thumb the effect
140 vanishes at a height 2-3 times the rotor diameter.
141 formula used: exp ( - groundeffectexp * (height+groundeffectshift) )
142 Omitting or setting to 0.0 disables the effect calculation.
143 \<groundeffectshift> - Further adjustment of ground effect, approx. hub height or slightly above
144 (This lessens the influence of the ground effect).
150 <h4>- Controls -</h4>
152 The behavior of the rotor is controlled/influenced by following inputs.<ul>
153 <li> The power provided by the engine. This is handled by the regular engine controls.</li>
154 <li> The collective control input. This is read from the <tt>fdm</tt> property
155 <tt>propulsion/engine[x]/collective-ctrl-rad</tt>. See below for tail rotor</li>
156 <li> The lateral cyclic input. Read from
157 <tt>propulsion/engine[x]/lateral-ctrl-rad</tt>.</li>
158 <li> The longitudinal cyclic input. Read from
159 <tt>propulsion/engine[x]/longitudinal-ctrl-rad</tt>.</li>
160 <li> The tail rotor collective (aka antitorque, aka pedal) control input. Read from
161 <tt>propulsion/engine[x]/antitorque-ctrl-rad</tt> or
162 <tt>propulsion/engine[x]/tail-collective-ctrl-rad</tt>.</li>
166 <h4>- Tail/tandem rotor -</h4>
168 Providing <tt>\<ExternalRPM\> 0 \</ExternalRPM\></tt> the tail rotor's RPM
169 is linked to to the main (=first, =0) rotor, and specifing
170 <tt>\<controlmap\> TAIL \</controlmap\></tt> tells this rotor to read the
171 collective input from <tt>propulsion/engine[1]/antitorque-ctrl-rad</tt>
172 (The TAIL-map ignores lateral and longitudinal input). The rotor needs to be
173 attached to a dummy engine, e.g. an 1HP electrical engine.
174 A tandem rotor is setup analogous.
178 The 'sense' parameter from the thruster is interpreted as follows, sense=1 means
179 counter clockwise rotation of the main rotor, as viewed from above. This is as a far
180 as I know more popular than clockwise rotation, which is defined by setting sense to
181 -1. Concerning coaxial designs - by setting 'sense' to zero, a Kamov-style rotor is
182 modeled (i.e. the rotor produces no torque).
184 <h4>- Engine issues -</h4>
186 In order to keep the rotor/engine speed constant, use of a RPM-Governor system is
187 encouraged (see examples).
189 In case the model requires the manual use of a clutch the <tt>\<gearloss\></tt>
190 property might need attention.<ul>
192 <li> Electrical: here the gear-loss should be rather large to keep the engine
193 controllable when the clutch is open (although full throttle might still make it
195 <li> Piston: this engine model already has some internal friction loss and also
196 looses power if it spins too high. Here the gear-loss could be set to 0.25%
197 of the engine power (which is also the approximated default).</li>
198 <li> Turboprop: Here the default value might be a bit too small. Also it's advisable
199 to adjust the power table for rpm values that are far beyond the nominal value.</li>
203 <h4>- Scaling the ground effect -</h4>
205 The property <tt>propulsion/engine[x]/groundeffect-scale-norm</tt> allows fdm based
206 scaling of the ground effect influence. For instance the effect vanishes at speeds
207 above approx. 50kts, or one likes to land on a 'perforated' helipad.
209 <h4>- Development hints -</h4>
211 Setting <tt>\<ExternalRPM> -1 \</ExternalRPM></tt> the rotor's RPM is controlled by
212 the <tt>propulsion/engine[x]/x-rpm-dict</tt> property. This feature can be useful
213 when developing a FDM.
219 <dt>/SH79/</dt><dd>Shaugnessy, J. D., Deaux, Thomas N., and Yenni, Kenneth R.,
220 "Development and Validation of a Piloted Simulation of a
221 Helicopter and External Sling Load", NASA TP-1285, 1979.</dd>
222 <dt>/BA41/</dt><dd>Bailey,F.J.,Jr., "A Simplified Theoretical Method of Determining
223 the Characteristics of a Lifting Rotor in Forward Flight", NACA Rep.716, 1941.</dd>
224 <dt>/AM50/</dt><dd>Amer, Kenneth B.,"Theory of Helicopter Damping in Pitch or Roll and a
225 Comparison With Flight Measurements", NACA TN-2136, 1950.</dd>
226 <dt>/TA77/</dt><dd>Talbot, Peter D., Corliss, Lloyd D., "A Mathematical Force and Moment
227 Model of a UH-1H Helicopter for Flight Dynamics Simulations", NASA TM-73,254, 1977.</dd>
228 <dt>/GE49/</dt><dd>Gessow, Alfred, Amer, Kenneth B. "An Introduction to the Physical
229 Aspects of Helicopter Stability", NACA TN-1982, 1949.</dd>
232 @author Thomas Kreitler
233 @version $Id: FGRotor.h,v 1.14 2012/03/18 15:48:36 jentron Exp $
238 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
242 class FGRotor : public FGThruster {
244 enum eCtrlMapping {eMainCtrl=0, eTailCtrl, eTandemCtrl};
248 /** Constructor for FGRotor.
249 @param exec a pointer to the main executive object
250 @param rotor_element a pointer to the thruster config file XML element
251 @param num the number of this rotor */
252 FGRotor(FGFDMExec *exec, Element* rotor_element, int num);
254 /// Destructor for FGRotor
257 /// Returns the power required by the rotor.
258 double GetPowerRequired(void)const { return PowerRequired; }
260 /// Returns the scalar thrust of the rotor, and adjusts the RPM value.
261 double Calculate(double EnginePower);
264 /// Retrieves the RPMs of the rotor.
265 double GetRPM(void) const { return RPM; }
266 void SetRPM(double rpm) { RPM = rpm; }
268 /// Retrieves the RPMs of the Engine, as seen from this rotor.
269 double GetEngineRPM(void) const {return EngineRPM;} //{ return GearRatio*RPM; }
270 void SetEngineRPM(double rpm) {EngineRPM = rpm;} //{ RPM = rpm/GearRatio; }
271 /// Tells the rotor's gear ratio, usually the engine asks for this.
272 double GetGearRatio(void) { return GearRatio; }
273 /// Retrieves the thrust of the rotor.
274 double GetThrust(void) const { return Thrust; }
276 /// Retrieves the rotor's coning angle
277 double GetA0(void) const { return a0; }
278 /// Retrieves the longitudinal flapping angle with respect to the rotor shaft
279 double GetA1(void) const { return a1s; }
280 /// Retrieves the lateral flapping angle with respect to the rotor shaft
281 double GetB1(void) const { return b1s; }
283 /// Retrieves the inflow ratio
284 double GetLambda(void) const { return lambda; }
285 /// Retrieves the tip-speed (aka advance) ratio
286 double GetMu(void) const { return mu; }
287 /// Retrieves the induced inflow ratio
288 double GetNu(void) const { return nu; }
289 /// Retrieves the induced velocity
290 double GetVi(void) const { return v_induced; }
291 /// Retrieves the thrust coefficient
292 double GetCT(void) const { return C_T; }
293 /// Retrieves the torque
294 double GetTorque(void) const { return Torque; }
296 /// Downwash angle - positive values point forward (given a horizontal spinning rotor)
297 double GetThetaDW(void) const { return theta_downwash; }
298 /// Downwash angle - positive values point leftward (given a horizontal spinning rotor)
299 double GetPhiDW(void) const { return phi_downwash; }
301 /// Retrieves the ground effect scaling factor.
302 double GetGroundEffectScaleNorm(void) const { return GroundEffectScaleNorm; }
303 /// Sets the ground effect scaling factor.
304 void SetGroundEffectScaleNorm(double g) { GroundEffectScaleNorm = g; }
306 /// Retrieves the collective control input in radians.
307 double GetCollectiveCtrl(void) const { return CollectiveCtrl; }
308 /// Retrieves the lateral control input in radians.
309 double GetLateralCtrl(void) const { return LateralCtrl; }
310 /// Retrieves the longitudinal control input in radians.
311 double GetLongitudinalCtrl(void) const { return LongitudinalCtrl; }
313 /// Sets the collective control input in radians.
314 void SetCollectiveCtrl(double c) { CollectiveCtrl = c; }
315 /// Sets the lateral control input in radians.
316 void SetLateralCtrl(double c) { LateralCtrl = c; }
317 /// Sets the longitudinal control input in radians.
318 void SetLongitudinalCtrl(double c) { LongitudinalCtrl = c; }
320 // Stubs. Only main rotor RPM is returned
321 string GetThrusterLabels(int id, const string& delimeter);
322 string GetThrusterValues(int id, const string& delimeter);
326 // assist in parameter retrieval
327 double ConfigValueConv( Element* e, const string& ename, double default_val=0.0,
328 const string& unit = "", bool tell=false);
330 double ConfigValue( Element* e, const string& ename, double default_val=0.0,
333 double Configure(Element* rotor_element);
335 void CalcRotorState(void);
338 void calc_flow_and_thrust(double theta_0, double Uw, double Ww, double flow_scale = 1.0);
339 void calc_coning_angle(double theta_0);
340 void calc_flapping_angles(double theta_0, const FGColumnVector3 &pqr_fus_w);
341 void calc_drag_and_side_forces(double theta_0);
342 void calc_torque(double theta_0);
343 void calc_downwash_angles();
346 FGColumnVector3 hub_vel_body2ca( const FGColumnVector3 &uvw, const FGColumnVector3 &pqr,
347 double a_ic = 0.0 , double b_ic = 0.0 );
348 FGColumnVector3 fus_angvel_body2ca( const FGColumnVector3 &pqr);
349 FGColumnVector3 body_forces(double a_ic = 0.0 , double b_ic = 0.0 );
350 FGColumnVector3 body_moments(double a_ic = 0.0 , double b_ic = 0.0 );
353 bool BindModel(void);
354 void Debug(int from);
361 // configuration parameters
372 FGPropertyManager* ExtRPMsource;
373 double SourceGearRatio;
375 // 'real' rotor parameters
377 double LiftCurveSlope;
380 double BladeFlappingMoment;
381 double BladeMassMoment;
387 double GroundEffectExp;
388 double GroundEffectShift;
389 double GroundEffectScaleNorm;
391 // derived parameters
392 double LockNumberByRho;
393 double Solidity; // aka sigma
394 double R[5]; // Radius powers
395 double B[5]; // TipLossB powers
397 // Some of the calculations require shaft axes. So the
398 // thruster orientation (Tbo, with b for body) needs to be
399 // expressed/represented in helicopter shaft coordinates (Hsr).
400 FGMatrix33 InvTransform;
406 double Omega; // must be > 0
407 double beta_orient; // rotor orientation angle (rad)
408 double a0; // coning angle (rad)
409 double a_1, b_1, a_dw; // flapping angles
410 double a1s, b1s; // cyclic flapping relative to shaft axes, /SH79/ eqn(43)
411 double H_drag, J_side; // Forces
414 double C_T; // rotor thrust coefficient
415 double lambda; // inflow ratio
416 double mu; // tip-speed ratio
417 double nu; // induced inflow ratio
418 double v_induced; // induced velocity, usually positive [ft/s]
420 double theta_downwash;
424 eCtrlMapping ControlMap;
425 double CollectiveCtrl;
427 double LongitudinalCtrl;
429 // interaction with engine
430 FGTransmission *Transmission;
432 double MaxBrakePower;
439 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%