1 #include <simgear/debug/logstream.hxx>
4 #include "Rotorpart.hpp"
9 const float pi=3.14159;
11 Rotorpart::Rotorpart()
17 _shared_flap_hinge=false;
19 #define set3(x,a,b,c) x[0]=a;x[1]=b;x[2]=c;
21 set3 (_directionofcentripetalforce,1,0,0);
22 set3 (_directionofrotorpart,0,1,0);
23 set3 (_direction_of_movement,1,0,0);
24 set3 (_last_torque,0,0,0);
38 _alphaoutputbuf[0][0]=0;
39 _alphaoutputbuf[1][0]=0;
59 _number_of_segments=1;
60 _rel_len_where_incidence_is_measured=0.7;
63 _rel_len_blade_start=0;
65 _rotor_correction_factor=0.6;
68 void Rotorpart::inititeration(float dt,float *rot)
72 while (_phi>(2*pi)) _phi-=2*pi;
73 while (_phi<(0 )) _phi+=2*pi;
74 float a=Math::dot3(rot,_normal);
76 _alphaalt=_alpha*Math::cos(a)
77 +_next90rp->getrealAlpha()*Math::sin(a);
79 _alphaalt=_alpha*Math::cos(a)
80 +_last90rp->getrealAlpha()*Math::sin(-a);
81 //calculate the rotation of the fuselage, determine
82 //the part in the same direction as alpha
83 //and add it ro _alphaalt
84 //alpha is rotation about "normal cross dirofzentf"
87 Math::cross3(_directionofcentripetalforce,_normal,dir);
88 a=Math::dot3(rot,dir);
90 _alphaalt= Math::clamp(_alphaalt,_alphamin,_alphamax);
93 void Rotorpart::setRotor(Rotor *rotor)
98 void Rotorpart::setParameter(char *parametername, float value)
100 #define p(a) if (strcmp(parametername,#a)==0) _##a = value; else
103 p(number_of_segments)
104 p(rel_len_where_incidence_is_measured)
105 p(rel_len_blade_start)
106 p(rotor_correction_factor)
107 SG_LOG(SG_INPUT, SG_ALERT,
108 "internal error in parameter set up for rotorpart: '"
109 << parametername <<"'" << endl);
113 void Rotorpart::setTorque(float torque_max_force,float torque_no_force)
115 _torque_max_force=torque_max_force;
116 _torque_no_force=torque_no_force;
119 void Rotorpart::setTorqueOfInertia(float toi)
121 _torque_of_inertia=toi;
124 void Rotorpart::setWeight(float value)
129 float Rotorpart::getWeight(void)
131 return(_mass/.453); //_mass is in kg, returns pounds
134 void Rotorpart::setPosition(float* p)
137 for(i=0; i<3; i++) _pos[i] = p[i];
140 float Rotorpart::getIncidence()
145 void Rotorpart::getPosition(float* out)
148 for(i=0; i<3; i++) out[i] = _pos[i];
151 void Rotorpart::setPositionForceAttac(float* p)
154 for(i=0; i<3; i++) _posforceattac[i] = p[i];
157 void Rotorpart::getPositionForceAttac(float* out)
160 for(i=0; i<3; i++) out[i] = _posforceattac[i];
163 void Rotorpart::setSpeed(float* p)
166 for(i=0; i<3; i++) _speed[i] = p[i];
167 Math::unit3(_speed,_direction_of_movement);
170 void Rotorpart::setDirectionofZentipetalforce(float* p)
173 for(i=0; i<3; i++) _directionofcentripetalforce[i] = p[i];
176 void Rotorpart::setDirectionofRotorPart(float* p)
179 for(i=0; i<3; i++) _directionofrotorpart[i] = p[i];
182 void Rotorpart::setOmega(float value)
187 void Rotorpart::setPhi(float value)
192 void Rotorpart::setOmegaN(float value)
197 void Rotorpart::setDdtOmega(float value)
202 void Rotorpart::setZentipetalForce(float f)
208 void Rotorpart::setDelta3(float f)
213 void Rotorpart::setRelamp(float f)
218 void Rotorpart::setTranslift(float f)
223 void Rotorpart::setDynamic(float f)
228 void Rotorpart::setRelLenHinge(float f)
233 void Rotorpart::setSharedFlapHinge(bool s)
235 _shared_flap_hinge=s;
238 void Rotorpart::setC2(float f)
243 void Rotorpart::setAlpha0(float f)
245 if (f>-0.01) f=-0.01; //half a degree bending
249 void Rotorpart::setAlphamin(float f)
254 void Rotorpart::setAlphamax(float f)
259 void Rotorpart::setAlpha0factor(float f)
264 void Rotorpart::setDiameter(float f)
269 float Rotorpart::getPhi()
274 float Rotorpart::getAlpha(int i)
279 return _alpha*180/pi;//in Grad = 1
282 if (_alpha2type==1) //yaw or roll
283 return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
285 return (getAlpha(0)+_oppositerp->getAlpha(0)+
286 _next90rp->getAlpha(0)+_last90rp->getAlpha(0))/4;
289 float Rotorpart::getrealAlpha(void)
294 void Rotorpart::setAlphaoutput(char *text,int i)
296 strncpy(_alphaoutputbuf[i>0],text,255);
297 if (i>0) _alpha2type=i;
300 char* Rotorpart::getAlphaoutput(int i)
302 return _alphaoutputbuf[i&1];
305 void Rotorpart::setLen(float value)
310 void Rotorpart::setNormal(float* p)
313 for(i=0; i<3; i++) _normal[i] = p[i];
316 void Rotorpart::getNormal(float* out)
319 for(i=0; i<3; i++) out[i] = _normal[i];
322 void Rotorpart::setCollective(float pos)
327 void Rotorpart::setCyclic(float pos)
332 void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
333 Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp)
337 _oppositerp=oppositerp;
342 void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
345 while(src[n]&&n<(maxlen-1))
353 // Calculate the flapping angle, where zentripetal force and
354 //lift compensate each other
355 float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
356 float incidence, float cyc, float alphaalt, float *torque,
359 float moment[3],v_local[3],v_local_scalar,lift_moment,v_flap[3],v_help[3];
360 float ias;//nur f. dgb
364 float relgrav = Math::dot3(_normal,_rotor->getGravDirection());
365 lift_moment=-_mass*_len*9.81*relgrav;
367 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
368 return 0.0;//not initialized. Can happen during startupt of flightgear
369 if (returnlift!=NULL) *returnlift=0;
370 float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
372 float local_width=_diameter*(1-_rel_len_blade_start)/2.
373 /(float (_number_of_segments));
374 for (n=0;n<_number_of_segments;n++)
376 float rel = (n+.5)/(float (_number_of_segments));
377 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
378 +_rel_len_blade_start);
379 float local_incidence=incidence+_twist *rel -
380 _twist *_rel_len_where_incidence_is_measured;
381 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
382 *_rotor->getTaper()*(1-rel);
383 float A = local_chord * local_width;
384 //calculate the local air speed and the incidence to this speed;
385 Math::mul3(_omega * r , _direction_of_movement , v_local);
387 // add speed component due to flapping
388 Math::mul3(flap_omega * r,_normal,v_flap);
389 Math::add3(v_flap,v_local,v_local);
390 Math::sub3(v_rel_air,v_local,v_local);
391 //v_local is now the total airspeed at the blade
392 //apparent missing: calculating the local_wind = v_rel_air at
393 //every point of the rotor. It differs due to aircraft-rotation
394 //it is considered in v_flap
396 //substract now the component of the air speed parallel to
398 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
399 _directionofrotorpart,v_help);
400 Math::sub3(v_local,v_help,v_local);
402 //split into direction and magnitude
403 v_local_scalar=Math::mag3(v_local);
404 if (v_local_scalar!=0)
405 //Math::unit3(v_local,v_help);
406 Math::mul3(1/v_local_scalar,v_local,v_help);
407 float incidence_of_airspeed = Math::asin(Math::clamp(
408 Math::dot3(v_help,_normal),-1,1)) + local_incidence;
409 ias = incidence_of_airspeed;
411 //reduce the ias (Prantl factor)
412 float prantl_factor=2/pi*Math::acos(Math::exp(
413 -_rotor->getNumberOfBlades()/2.*(1-rel)
414 *Math::sqrt(1+1/Math::sqr(Math::tan(
415 pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
416 incidence_of_airspeed = (incidence_of_airspeed+
417 _rotor->getAirfoilIncidenceNoLift())*prantl_factor
418 *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
419 ias = incidence_of_airspeed;
420 float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
421 -cyc*_rotor_correction_factor*prantl_factor,v_local_scalar)
422 * v_local_scalar * v_local_scalar * A *rho *0.5;
423 float lift_with_cyc =
424 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
425 * v_local_scalar * v_local_scalar *A *rho*0.5;
426 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
427 //take into account that the rotor is a resonant system where
428 //the cyclic input hase increased result
429 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
430 * v_local_scalar * v_local_scalar * A *rho*0.5;
431 float angle = incidence_of_airspeed - incidence;
432 //angle between blade movement caused by rotor-rotation and the
433 //total movement of the blade
435 /* the next shold look like this, but this is the inner loop of
436 the rotor simulation. For small angles (and we hav only small
437 angles) the first order approximation works well
438 lift_moment += r*(lift * Math::cos(angle)
439 - drag * Math::sin(angle));
440 *torque += r*(drag * Math::cos(angle)
441 + lift * Math::sin(angle));
443 lift_moment += r*(lift * (1-angle*angle)
445 *torque += r*(drag * (1-angle*angle)
448 if (returnlift!=NULL) *returnlift+=lift;
450 //as above, use 1st order approximation
451 //float alpha=Math::atan2(lift_moment,_centripetalforce * _len);
453 if (_shared_flap_hinge)
456 if (Math::abs(_alphaalt) >1e-6)
457 div=(_centripetalforce * _len - _mass * _len * 9.81 * relgrav /_alpha0*(_alphaalt+_oppositerp->getAlphaAlt())/(2.0*_alphaalt));
458 if (Math::abs(div)>1e-6)
459 alpha=lift_moment/div;
460 else if(Math::abs(_alphaalt+_oppositerp->getAlphaAlt())>1e-6)
462 float div=(_centripetalforce * _len - _mass * _len * 9.81 *0.5 * relgrav)*(_alphaalt+_oppositerp->getAlphaAlt());
463 if (Math::abs(div)>1e-6)
464 alpha=_oppositerp->getAlphaAlt()+lift_moment/div*_alphaalt;
471 float div=(_centripetalforce * _len - _mass * _len * 9.81 /_alpha0);
472 if (Math::abs(div)>1e-6)
473 alpha=lift_moment/div;
481 // Calculate the aerodynamic force given a wind vector v (in the
482 // aircraft's "local" coordinates) and an air density rho. Returns a
483 // torque about the Y axis, too.
484 void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
485 float* torque_scalar)
489 for (int i=0;i<3;i++)
494 _centripetalforce=_mass*_len*_omega*_omega;
495 float vrel[3],vreldir[3];
496 Math::sub3(_speed,v,vrel);
497 float scalar_torque=0;
498 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
499 //Angle of blade which would produce no vertical force (where the
500 //effective incidence is zero)
503 float col=_collective;
504 if (_shared_flap_hinge)
505 _incidence=(col+cyc)-_delta3*0.5*(_alphaalt-_oppositerp->getAlphaAlt());
507 _incidence=(col+cyc)-_delta3*_alphaalt;
508 //the incidence of the rotorblade due to control input reduced by the
509 //delta3 effect, see README.YASIM
510 //float beta=_relamp*cyc+col;
511 //the incidence of the rotorblade which is used for the calculation
513 float alpha,factor; //alpha is the flapping angle
514 //the new flapping angle will be the old flapping angle
515 //+ factor *(alpha - "old flapping angle")
516 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
517 alpha=Math::clamp(alpha,_alphamin,_alphamax);
518 //the incidence is a function of alpha (if _delta* != 0)
519 //Therefore missing: wrap this function in an integrator
520 //(runge kutta e. g.)
523 if (factor>1) factor=1;
526 Math::cross3(_normal,_directionofcentripetalforce,dirblade);
527 float vblade=Math::abs(Math::dot3(dirblade,v));
529 alpha=_alphaalt+(alpha-_alphaalt)*factor;
531 float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
532 +1*Math::cos(_next90rp->getrealAlpha())
533 +1*Math::cos(_oppositerp->getrealAlpha())
534 +1*Math::cos(alpha))/4;
535 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
537 //missing: consideration of rellenhinge
538 float xforce = Math::cos(alpha)*_centripetalforce;
539 float zforce = schwenkfactor*Math::sin(alpha)*_centripetalforce;
540 *torque_scalar=scalar_torque;
541 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
542 float thetorque = scalar_torque;
544 float f=_rotor->getCcw()?1:-1;
546 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
547 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
548 +_directionofcentripetalforce[i]*xforce;
552 void Rotorpart::getAccelTorque(float relaccel,float *t)
555 float f=_rotor->getCcw()?1:-1;
557 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
558 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
561 std::ostream & operator<<(std::ostream & out, const Rotorpart& rp)
563 #define i(x) << #x << ":" << rp.x << endl
564 #define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
565 out << "Writing Info on Rotorpart " << endl
569 iv( _pos) // position in local coords
570 iv( _posforceattac) // position in local coords
571 iv( _normal) //direcetion of the rotation axis
572 i( _torque_max_force)
575 iv( _direction_of_movement)
576 iv( _directionofcentripetalforce)
577 iv( _directionofrotorpart)
578 i( _centripetalforce)
588 i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
591 i( _omega) i(_omegan) i(_ddt_omega)
595 i( _twist) //outer incidence = inner inner incidence + _twist
596 i( _number_of_segments)
597 i( _rel_len_where_incidence_is_measured)
598 i( _rel_len_blade_start)
600 i( _torque_of_inertia)
602 i (_alphaoutputbuf[0])
603 i (_alphaoutputbuf[1])
605 i(_rotor_correction_factor)
611 }; // namespace yasim