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
31 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
42 #include "FGThruster.h"
44 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
48 #define ID_ROTOR "$Id: FGRotor.h,v 1.8 2011/01/17 22:09:59 jberndt Exp $"
50 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60 /** Models a helicopter rotor.
63 <h3>Configuration File Format</h3>
65 <rotor name="{string}">
66 <diameter unit="{LENGTH}"> {number} </diameter>
67 <numblades> {number} </numblades>
68 <gearratio> {number} </gearratio>
69 <nominalrpm> {number} </nominalrpm>
70 <chord unit="{LENGTH}"> {number} </chord>
71 <liftcurveslope Xunit="1/RAD"> {number} </liftcurveslope>
72 <twist unit="{ANGLE}"> {number} </twist>
73 <hingeoffset unit="{LENGTH}"> {number} </hingeoffset>
74 <flappingmoment unit="{MOMENT}"> {number} </flappingmoment>
75 <massmoment Xunit="SLUG*FT"> {number} </massmoment>
76 <polarmoment unit="{MOMENT}"> {number} </polarmoment>
77 <inflowlag> {number} </inflowlag>
78 <tiplossfactor> {number} </tiplossfactor>
80 <controlmap> {MAIN|TAIL|TANDEM} </controlmap>
81 <ExternalRPM> {number} </ExternalRPM>
83 <groundeffectexp> {number} </groundeffectexp>
84 <groundeffectshift unit="{LENGTH}"> {number} </groundeffectshift>
87 // LENGTH means any of the supported units, same for ANGLE and MOMENT.
88 // Xunit-attributes are a hint for currently unsupported units, so
89 // values must be provided accordingly.
93 <h3>Configuration Parameters:</h3>
95 Brief description and the symbol frequently found in the literature.
98 \<diameter> - Rotor disk diameter (2x R).
99 \<numblades> - Number of blades (b).
100 \<gearratio> - Ratio of (engine rpm) / (rotor rpm), usually > 1.
101 \<nominalrpm> - RPM at which the rotor usally operates.
102 \<chord> - Blade chord, (c).
103 \<liftcurveslope> - Slope of curve of section lift against section angle of attack,
105 \<twist> - Blade twist from root to tip, (theta_1).
106 \<hingeoffset> - Rotor flapping-hinge offset (e).
107 \<flappingmoment> - Flapping moment of inertia (I_b).
108 \<massmoment> - Blade mass moment. Mass of a single blade times the blade's
109 cg-distance from the hub, optional.
110 \<polarmoment> - Moment of inertia for the whole rotor disk, optional.
111 \<inflowlag> - Rotor inflow time constant, sec. Smaller values yield to
112 quicker responses to control input (defaults to 0.2).
113 \<tiplossfactor> - Tip-loss factor. The Blade fraction that produces lift.
114 Value usually ranges between 0.95 - 1.0, optional (B).
116 \<controlmap> - Defines the control inputs used (see notes).
117 \<ExternalRPM> - Links the rotor to another rotor, or an user controllable property.
119 Experimental properties
121 \<groundeffectexp> - Exponent for ground effect approximation. Values usually range from 0.04
122 for large rotors to 0.1 for smaller ones. As a rule of thumb the effect
123 vanishes at a height 2-3 times the rotor diameter.
124 formula used: exp ( - groundeffectexp * (height+groundeffectshift) )
125 Omitting or setting to 0.0 disables the effect calculation.
126 \<groundeffectshift> - Further adjustment of ground effect, approx. hub height or slightly above.
132 <h4>- Controls -</h4>
134 The behavior of the rotor is controlled/influenced by following inputs.<ul>
135 <li> The power provided by the engine. This is handled by the regular engine controls.</li>
136 <li> The collective control input. This is read from the <tt>fdm</tt> property
137 <tt>propulsion/engine[x]/collective-ctrl-rad</tt>. See below for tail rotor</li>
138 <li> The lateral cyclic input. Read from
139 <tt>propulsion/engine[x]/lateral-ctrl-rad</tt>.</li>
140 <li> The longitudinal cyclic input. Read from
141 <tt>propulsion/engine[x]/longitudinal-ctrl-rad</tt>.</li>
142 <li> The tail collective (aka antitorque, aka pedal) control input. Read from
143 <tt>propulsion/engine[x]/antitorque-ctrl-rad</tt> or
144 <tt>propulsion/engine[x]/tail-collective-ctrl-rad</tt>.</li>
148 <h4>- Tail/tandem rotor -</h4>
150 Providing <tt>\<ExternalRPM\> 0 \</ExternalRPM\></tt> the tail rotor's RPM
151 is linked to to the main (=first, =0) rotor, and specifing
152 <tt>\<controlmap\> TAIL \</controlmap\></tt> tells this rotor to read the
153 collective input from <tt>propulsion/engine[1]/antitorque-ctrl-rad</tt>
154 (The TAIL-map ignores lateral and longitudinal input). The rotor needs to be
155 attached to a dummy engine, e.g. an 1HP electrical engine.
156 A tandem rotor is setup analogous.
160 The 'sense' parameter from the thruster is interpreted as follows, sense=1 means
161 counter clockwise rotation of the main rotor, as viewed from above. This is as a far
162 as I know more popular than clockwise rotation, which is defined by setting sense to
163 -1. Concerning coaxial designs - by setting 'sense' to zero, a Kamov-style rotor is
164 modeled (i.e. the rotor produces no torque).
166 <h4>- Engine issues -</h4>
168 Currently the rotor can only be driven with piston and electrical engines. An adaption
169 for the turboprop engine might become available in the future.
170 In order to keep the rotor speed constant, use of a RPM-Governor system is
171 encouraged (see examples).
173 <h4>- Development hints -</h4>
175 Setting <tt>\<ExternalRPM> -1 \</ExternalRPM></tt> the rotor's RPM is controlled by
176 the <tt>propulsion/engine[x]/x-rpm-dict</tt> property. This feature can be useful
177 when developing a FDM.
183 <dt>/SH79/</dt><dd>Shaugnessy, J. D., Deaux, Thomas N., and Yenni, Kenneth R.,
184 "Development and Validation of a Piloted Simulation of a
185 Helicopter and External Sling Load", NASA TP-1285, 1979.</dd>
186 <dt>/BA41/</dt><dd>Bailey,F.J.,Jr., "A Simplified Theoretical Method of Determining
187 the Characteristics of a Lifting Rotor in Forward Flight", NACA Rep.716, 1941.</dd>
188 <dt>/AM50/</dt><dd>Amer, Kenneth B.,"Theory of Helicopter Damping in Pitch or Roll and a
189 Comparison With Flight Measurements", NACA TN-2136, 1950.</dd>
190 <dt>/TA77/</dt><dd>Talbot, Peter D., Corliss, Lloyd D., "A Mathematical Force and Moment
191 Model of a UH-1H Helicopter for Flight Dynamics Simulations", NASA TM-73,254, 1977.</dd>
194 @author Thomas Kreitler
195 @version $Id: FGRotor.h,v 1.8 2011/01/17 22:09:59 jberndt Exp $
200 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
204 class FGRotor : public FGThruster {
206 enum eCtrlMapping {eMainCtrl=0, eTailCtrl, eTandemCtrl};
210 /** Constructor for FGRotor.
211 @param exec a pointer to the main executive object
212 @param rotor_element a pointer to the thruster config file XML element
213 @param num the number of this rotor */
214 FGRotor(FGFDMExec *exec, Element* rotor_element, int num);
216 /// Destructor for FGRotor
219 /** Returns the power required by the rotor. Well, to achieve this the rotor
220 is cycled through the whole machinery, yielding to a new state.
221 (hmm, sort of a huge side effect)
223 double GetPowerRequired(void);
225 /** Returns the scalar thrust of the rotor, and adjusts the RPM value. */
226 double Calculate(double PowerAvailable);
229 /// Retrieves the RPMs of the rotor.
230 double GetRPM(void) const { return RPM; }
232 // void SetRPM(double rpm) { RPM = rpm; }
234 /// Retrieves the RPMs of the Engine, as seen from this rotor.
235 double GetEngineRPM(void) const { return GearRatio*RPM; } // bit of a hack.
236 /// Tells the rotor's gear ratio, usually the engine asks for this.
237 double GetGearRatio(void) { return GearRatio; }
238 /// Retrieves the thrust of the rotor.
239 double GetThrust(void) const { return Thrust; }
241 /// Retrieves the rotor's coning angle
242 double GetA0(void) const { return a0; }
243 /// Retrieves the longitudinal flapping angle with respect to the rotor shaft
244 double GetA1(void) const { return a1s; }
245 /// Retrieves the lateral flapping angle with respect to the rotor shaft
246 double GetB1(void) const { return b1s; }
248 /// Retrieves the inflow ratio
249 double GetLambda(void) const { return lambda; }
250 /// Retrieves the tip-speed (aka advance) ratio
251 double GetMu(void) const { return mu; }
252 /// Retrieves the induced inflow ratio
253 double GetNu(void) const { return nu; }
254 /// Retrieves the induced velocity
255 double GetVi(void) const { return v_induced; }
256 /// Retrieves the thrust coefficient
257 double GetCT(void) const { return C_T; }
258 /// Retrieves the torque
259 double GetTorque(void) const { return Torque; }
261 /// Downwash angle - currently only valid for a rotor that spins horizontally
262 double GetThetaDW(void) const { return theta_downwash; }
263 /// Downwash angle - currently only valid for a rotor that spins horizontally
264 double GetPhiDW(void) const { return phi_downwash; }
266 /// Retrieves the collective control input in radians.
267 double GetCollectiveCtrl(void) const { return CollectiveCtrl; }
268 /// Retrieves the lateral control input in radians.
269 double GetLateralCtrl(void) const { return LateralCtrl; }
270 /// Retrieves the longitudinal control input in radians.
271 double GetLongitudinalCtrl(void) const { return LongitudinalCtrl; }
273 /// Sets the collective control input in radians.
274 void SetCollectiveCtrl(double c) { CollectiveCtrl = c; }
275 /// Sets the lateral control input in radians.
276 void SetLateralCtrl(double c) { LateralCtrl = c; }
277 /// Sets the longitudinal control input in radians.
278 void SetLongitudinalCtrl(double c) { LongitudinalCtrl = c; }
280 // Stubs. Only main rotor RPM is returned
281 string GetThrusterLabels(int id, string delimeter);
282 string GetThrusterValues(int id, string delimeter);
286 // assist in parameter retrieval
287 double ConfigValueConv( Element* e, const string& ename, double default_val=0.0,
288 const string& unit = "", bool tell=false);
290 double ConfigValue( Element* e, const string& ename, double default_val=0.0,
293 void Configure(Element* rotor_element);
296 void CalcStatePart1(void);
297 void CalcStatePart2(double PowerAvailable);
300 void calc_flow_and_thrust(double theta_0, double Uw, double Ww, double flow_scale = 1.0);
301 void calc_coning_angle(double theta_0);
302 void calc_flapping_angles(double theta_0, const FGColumnVector3 &pqr_fus_w);
303 void calc_drag_and_side_forces(double theta_0);
304 void calc_torque(double theta_0);
307 FGColumnVector3 hub_vel_body2ca( const FGColumnVector3 &uvw, const FGColumnVector3 &pqr,
308 double a_ic = 0.0 , double b_ic = 0.0 );
309 FGColumnVector3 fus_angvel_body2ca( const FGColumnVector3 &pqr);
310 FGColumnVector3 body_forces(double a_ic = 0.0 , double b_ic = 0.0 );
311 FGColumnVector3 body_moments(double a_ic = 0.0 , double b_ic = 0.0 );
314 bool BindModel(void);
315 void Debug(int from);
322 // configuration parameters
330 FGPropertyManager* ExtRPMsource;
333 double LiftCurveSlope;
336 double BladeFlappingMoment;
337 double BladeMassMoment;
342 double GroundEffectExp;
343 double GroundEffectShift;
345 // derived parameters
346 double LockNumberByRho;
347 double Solidity; // aka sigma
348 double R[5]; // Radius powers
349 double B[5]; // TipLossB powers
351 // Some of the calculations require shaft axes. So the
352 // thruster orientation (Tbo, with b for body) needs to be
353 // expressed/represented in helicopter shaft coordinates (Hsr).
354 FGMatrix33 InvTransform;
360 double Omega; // must be > 0
361 double beta_orient; // rotor orientation angle (rad)
362 double a0; // coning angle (rad)
363 double a_1, b_1, a_dw; // flapping angles
364 double a1s, b1s; // cyclic flapping relative to shaft axes, /SH79/ eqn(43)
365 double H_drag, J_side; // Forces
368 double C_T; // rotor thrust coefficient
369 double lambda; // inflow ratio
370 double mu; // tip-speed ratio
371 double nu; // induced inflow ratio
372 double v_induced; // induced velocity, always positive [ft/s]
374 double theta_downwash;
378 eCtrlMapping ControlMap;
379 double CollectiveCtrl;
381 double LongitudinalCtrl;
386 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%