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 lift_moment=-_mass*_len*9.81; //*cos yaw * cos roll
366 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
367 return 0.0;//not initialized. Can happen during startupt of flightgear
368 if (returnlift!=NULL) *returnlift=0;
369 float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
371 float local_width=_diameter*(1-_rel_len_blade_start)/2.
372 /(float (_number_of_segments));
373 for (n=0;n<_number_of_segments;n++)
375 float rel = (n+.5)/(float (_number_of_segments));
376 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
377 +_rel_len_blade_start);
378 float local_incidence=incidence+_twist *rel -
379 _twist *_rel_len_where_incidence_is_measured;
380 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
381 *_rotor->getTaper()*(1-rel);
382 float A = local_chord * local_width;
383 //calculate the local air speed and the incidence to this speed;
384 Math::mul3(_omega * r , _direction_of_movement , v_local);
386 // add speed component due to flapping
387 Math::mul3(flap_omega * r,_normal,v_flap);
388 Math::add3(v_flap,v_local,v_local);
389 Math::sub3(v_rel_air,v_local,v_local);
390 //v_local is now the total airspeed at the blade
391 //apparent missing: calculating the local_wind = v_rel_air at
392 //every point of the rotor. It differs due to aircraft-rotation
393 //it is considered in v_flap
395 //substract now the component of the air speed parallel to
397 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
398 _directionofrotorpart,v_help);
399 Math::sub3(v_local,v_help,v_local);
401 //split into direction and magnitude
402 v_local_scalar=Math::mag3(v_local);
403 if (v_local_scalar!=0)
404 //Math::unit3(v_local,v_help);
405 Math::mul3(1/v_local_scalar,v_local,v_help);
406 float incidence_of_airspeed = Math::asin(Math::clamp(
407 Math::dot3(v_help,_normal),-1,1)) + local_incidence;
408 ias = incidence_of_airspeed;
410 //reduce the ias (Prantl factor)
411 float prantl_factor=2/pi*Math::acos(Math::exp(
412 -_rotor->getNumberOfBlades()/2.*(1-rel)
413 *Math::sqrt(1+1/Math::sqr(Math::tan(
414 pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
415 incidence_of_airspeed = (incidence_of_airspeed+
416 _rotor->getAirfoilIncidenceNoLift())*prantl_factor
417 *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
418 ias = incidence_of_airspeed;
419 float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
420 -cyc*_rotor_correction_factor*prantl_factor,v_local_scalar)
421 * v_local_scalar * v_local_scalar * A *rho *0.5;
422 float lift_with_cyc =
423 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
424 * v_local_scalar * v_local_scalar *A *rho*0.5;
425 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
426 //take into account that the rotor is a resonant system where
427 //the cyclic input hase increased result
428 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
429 * v_local_scalar * v_local_scalar * A *rho*0.5;
430 float angle = incidence_of_airspeed - incidence;
431 //angle between blade movement caused by rotor-rotation and the
432 //total movement of the blade
434 /* the next shold look like this, but this is the inner loop of
435 the rotor simulation. For small angles (and we hav only small
436 angles) the first order approximation works well
437 lift_moment += r*(lift * Math::cos(angle)
438 - drag * Math::sin(angle));
439 *torque += r*(drag * Math::cos(angle)
440 + lift * Math::sin(angle));
442 lift_moment += r*(lift * (1-angle*angle)
444 *torque += r*(drag * (1-angle*angle)
447 if (returnlift!=NULL) *returnlift+=lift;
449 //as above, use 1st order approximation
450 //float alpha=Math::atan2(lift_moment,_centripetalforce * _len);
452 if (_shared_flap_hinge)
455 if (Math::abs(_alphaalt) >1e-6)
456 div=(_centripetalforce * _len - _mass * _len * 9.81 /_alpha0*(_alphaalt+_oppositerp->getAlphaAlt())/(2.0*_alphaalt));
457 if (Math::abs(div)>1e-6)
458 alpha=lift_moment/div;
459 else if(Math::abs(_alphaalt+_oppositerp->getAlphaAlt())>1e-6)
461 float div=(_centripetalforce * _len - _mass * _len * 9.81 *0.5)*(_alphaalt+_oppositerp->getAlphaAlt());
462 if (Math::abs(div)>1e-6)
463 alpha=_oppositerp->getAlphaAlt()+lift_moment/div*_alphaalt;
470 float div=(_centripetalforce * _len - _mass * _len * 9.81 /_alpha0);
471 if (Math::abs(div)>1e-6)
472 alpha=lift_moment/div;
480 // Calculate the aerodynamic force given a wind vector v (in the
481 // aircraft's "local" coordinates) and an air density rho. Returns a
482 // torque about the Y axis, too.
483 void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
484 float* torque_scalar)
488 for (int i=0;i<3;i++)
493 _centripetalforce=_mass*_len*_omega*_omega;
494 float vrel[3],vreldir[3];
495 Math::sub3(_speed,v,vrel);
496 float scalar_torque=0;
497 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
498 //Angle of blade which would produce no vertical force (where the
499 //effective incidence is zero)
502 float col=_collective;
503 if (_shared_flap_hinge)
504 _incidence=(col+cyc)-_delta3*0.5*(_alphaalt-_oppositerp->getAlphaAlt());
506 _incidence=(col+cyc)-_delta3*_alphaalt;
507 //the incidence of the rotorblade due to control input reduced by the
508 //delta3 effect, see README.YASIM
509 //float beta=_relamp*cyc+col;
510 //the incidence of the rotorblade which is used for the calculation
512 float alpha,factor; //alpha is the flapping angle
513 //the new flapping angle will be the old flapping angle
514 //+ factor *(alpha - "old flapping angle")
515 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
516 alpha=Math::clamp(alpha,_alphamin,_alphamax);
517 //the incidence is a function of alpha (if _delta* != 0)
518 //Therefore missing: wrap this function in an integrator
519 //(runge kutta e. g.)
522 if (factor>1) factor=1;
525 Math::cross3(_normal,_directionofcentripetalforce,dirblade);
526 float vblade=Math::abs(Math::dot3(dirblade,v));
528 alpha=_alphaalt+(alpha-_alphaalt)*factor;
530 float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
531 +1*Math::cos(_next90rp->getrealAlpha())
532 +1*Math::cos(_oppositerp->getrealAlpha())
533 +1*Math::cos(alpha))/4;
534 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
536 //missing: consideration of rellenhinge
537 float xforce = Math::cos(alpha)*_centripetalforce;
538 float zforce = schwenkfactor*Math::sin(alpha)*_centripetalforce;
539 *torque_scalar=scalar_torque;
540 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
541 float thetorque = scalar_torque;
543 float f=_rotor->getCcw()?1:-1;
545 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
546 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
547 +_directionofcentripetalforce[i]*xforce;
551 void Rotorpart::getAccelTorque(float relaccel,float *t)
554 float f=_rotor->getCcw()?1:-1;
556 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
557 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
560 std::ostream & operator<<(std::ostream & out, const Rotorpart& rp)
562 #define i(x) << #x << ":" << rp.x << endl
563 #define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
564 out << "Writing Info on Rotorpart " << endl
568 iv( _pos) // position in local coords
569 iv( _posforceattac) // position in local coords
570 iv( _normal) //direcetion of the rotation axis
571 i( _torque_max_force)
574 iv( _direction_of_movement)
575 iv( _directionofcentripetalforce)
576 iv( _directionofrotorpart)
577 i( _centripetalforce)
587 i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
590 i( _omega) i(_omegan) i(_ddt_omega)
594 i( _twist) //outer incidence = inner inner incidence + _twist
595 i( _number_of_segments)
596 i( _rel_len_where_incidence_is_measured)
597 i( _rel_len_blade_start)
599 i( _torque_of_inertia)
601 i (_alphaoutputbuf[0])
602 i (_alphaoutputbuf[1])
604 i(_rotor_correction_factor)
610 }; // namespace yasim