3 #include <simgear/debug/logstream.hxx>
6 #include "Rotorpart.hpp"
13 const float pi=3.14159;
15 Rotorpart::Rotorpart()
21 _shared_flap_hinge=false;
23 #define set3(x,a,b,c) x[0]=a;x[1]=b;x[2]=c;
25 set3 (_directionofcentripetalforce,1,0,0);
26 set3 (_directionofrotorpart,0,1,0);
27 set3 (_direction_of_movement,1,0,0);
28 set3 (_last_torque,0,0,0);
42 _alphaoutputbuf[0][0]=0;
43 _alphaoutputbuf[1][0]=0;
63 _number_of_segments=1;
64 _rel_len_where_incidence_is_measured=0.7;
67 _rel_len_blade_start=0;
69 _rotor_correction_factor=0.6;
74 void Rotorpart::inititeration(float dt,float *rot)
78 while (_phi>(2*pi)) _phi-=2*pi;
79 while (_phi<(0 )) _phi+=2*pi;
80 float a=Math::dot3(rot,_normal);
82 _alphaalt=_alpha*Math::cos(a)
83 +_next90rp->getrealAlpha()*Math::sin(a);
85 _alphaalt=_alpha*Math::cos(a)
86 +_last90rp->getrealAlpha()*Math::sin(-a);
87 //calculate the rotation of the fuselage, determine
88 //the part in the same direction as alpha
89 //and add it ro _alphaalt
90 //alpha is rotation about "normal cross dirofzentf"
93 Math::cross3(_directionofcentripetalforce,_normal,dir);
94 a=Math::dot3(rot,dir);
96 _alphaalt= Math::clamp(_alphaalt,_alphamin,_alphamax);
100 b=_rotor->getBalance();
101 float s =Math::sin(_phi+_direction);
102 //float c =Math::cos(_phi+_direction);
104 _balance=(b>0)?(1.-s*(1.-b)):(1.-s)*(1.+b);
106 _balance=(b>0)?1.:1.+b;
109 void Rotorpart::setRotor(Rotor *rotor)
114 void Rotorpart::setParameter(const char *parametername, float value)
116 #define p(a) if (strcmp(parametername,#a)==0) _##a = value; else
119 p(number_of_segments)
120 p(rel_len_where_incidence_is_measured)
121 p(rel_len_blade_start)
122 p(rotor_correction_factor)
123 SG_LOG(SG_INPUT, SG_ALERT,
124 "internal error in parameter set up for rotorpart: '"
125 << parametername <<"'" << endl);
129 void Rotorpart::setTorque(float torque_max_force,float torque_no_force)
131 _torque_max_force=torque_max_force;
132 _torque_no_force=torque_no_force;
135 void Rotorpart::setTorqueOfInertia(float toi)
137 _torque_of_inertia=toi;
140 void Rotorpart::setWeight(float value)
145 float Rotorpart::getWeight(void)
147 return(_mass/.453); //_mass is in kg, returns pounds
150 void Rotorpart::setPosition(float* p)
153 for(i=0; i<3; i++) _pos[i] = p[i];
156 float Rotorpart::getIncidence()
161 void Rotorpart::getPosition(float* out)
164 for(i=0; i<3; i++) out[i] = _pos[i];
167 void Rotorpart::setPositionForceAttac(float* p)
170 for(i=0; i<3; i++) _posforceattac[i] = p[i];
173 void Rotorpart::getPositionForceAttac(float* out)
176 for(i=0; i<3; i++) out[i] = _posforceattac[i];
179 void Rotorpart::setSpeed(float* p)
182 for(i=0; i<3; i++) _speed[i] = p[i];
183 Math::unit3(_speed,_direction_of_movement);
186 void Rotorpart::setDirectionofZentipetalforce(float* p)
189 for(i=0; i<3; i++) _directionofcentripetalforce[i] = p[i];
192 void Rotorpart::setDirectionofRotorPart(float* p)
195 for(i=0; i<3; i++) _directionofrotorpart[i] = p[i];
198 void Rotorpart::setDirection(float direction)
200 _direction=direction;
203 void Rotorpart::setOmega(float value)
208 void Rotorpart::setPhi(float value)
213 void Rotorpart::setOmegaN(float value)
218 void Rotorpart::setDdtOmega(float value)
223 void Rotorpart::setZentipetalForce(float f)
229 void Rotorpart::setDelta3(float f)
234 void Rotorpart::setRelamp(float f)
239 void Rotorpart::setTranslift(float f)
244 void Rotorpart::setDynamic(float f)
249 void Rotorpart::setRelLenHinge(float f)
254 void Rotorpart::setSharedFlapHinge(bool s)
256 _shared_flap_hinge=s;
259 void Rotorpart::setC2(float f)
264 void Rotorpart::setAlpha0(float f)
266 if (f>-0.01) f=-0.01; //half a degree bending
270 void Rotorpart::setAlphamin(float f)
275 void Rotorpart::setAlphamax(float f)
280 void Rotorpart::setAlpha0factor(float f)
285 void Rotorpart::setDiameter(float f)
290 float Rotorpart::getPhi()
295 float Rotorpart::getAlpha(int i)
300 return _alpha*180/pi;//in Grad = 1
303 if (_alpha2type==1) //yaw or roll
304 return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
306 return (getAlpha(0)+_oppositerp->getAlpha(0)+
307 _next90rp->getAlpha(0)+_last90rp->getAlpha(0))/4;
310 float Rotorpart::getrealAlpha(void)
315 void Rotorpart::setAlphaoutput(char *text,int i)
317 strncpy(_alphaoutputbuf[i>0],text,255);
318 if (i>0) _alpha2type=i;
321 char* Rotorpart::getAlphaoutput(int i)
323 return _alphaoutputbuf[i&1];
326 void Rotorpart::setLen(float value)
331 void Rotorpart::setNormal(float* p)
334 for(i=0; i<3; i++) _normal[i] = p[i];
337 void Rotorpart::getNormal(float* out)
340 for(i=0; i<3; i++) out[i] = _normal[i];
343 void Rotorpart::setCollective(float pos)
348 void Rotorpart::setCyclic(float pos)
353 void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
354 Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp)
358 _oppositerp=oppositerp;
363 void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
366 while(src[n]&&n<(maxlen-1))
374 // Calculate the flapping angle, where zentripetal force and
375 //lift compensate each other
376 float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
377 float incidence, float cyc, float alphaalt, float *torque,
380 float moment[3],v_local[3],v_local_scalar,lift_moment,v_flap[3],v_help[3];
381 float ias;//nur f. dgb
385 float relgrav = Math::dot3(_normal,_rotor->getGravDirection());
386 lift_moment=-_mass*_len*9.81*relgrav;
388 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
389 return 0.0;//not initialized. Can happen during startupt of flightgear
390 if (returnlift!=NULL) *returnlift=0;
391 float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
393 float local_width=_diameter*(1-_rel_len_blade_start)/2.
394 /(float (_number_of_segments));
395 for (n=0;n<_number_of_segments;n++)
397 float rel = (n+.5)/(float (_number_of_segments));
398 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
399 +_rel_len_blade_start);
400 float local_incidence=incidence+_twist *rel -
401 _twist *_rel_len_where_incidence_is_measured;
402 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
403 *_rotor->getTaper()*(1-rel);
404 float A = local_chord * local_width;
405 //calculate the local air speed and the incidence to this speed;
406 Math::mul3(_omega * r , _direction_of_movement , v_local);
408 // add speed component due to flapping
409 Math::mul3(flap_omega * r,_normal,v_flap);
410 Math::add3(v_flap,v_local,v_local);
411 Math::sub3(v_rel_air,v_local,v_local);
412 //v_local is now the total airspeed at the blade
413 //apparent missing: calculating the local_wind = v_rel_air at
414 //every point of the rotor. It differs due to aircraft-rotation
415 //it is considered in v_flap
417 //substract now the component of the air speed parallel to
419 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
420 _directionofrotorpart,v_help);
421 Math::sub3(v_local,v_help,v_local);
423 //split into direction and magnitude
424 v_local_scalar=Math::mag3(v_local);
425 if (v_local_scalar!=0)
426 //Math::unit3(v_local,v_help);
427 Math::mul3(1/v_local_scalar,v_local,v_help);
428 float incidence_of_airspeed = Math::asin(Math::clamp(
429 Math::dot3(v_help,_normal),-1,1)) + local_incidence;
430 ias = incidence_of_airspeed;
432 //reduce the ias (Prantl factor)
433 float prantl_factor=2/pi*Math::acos(Math::exp(
434 -_rotor->getNumberOfBlades()/2.*(1-rel)
435 *Math::sqrt(1+1/Math::sqr(Math::tan(
436 pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
437 incidence_of_airspeed = (incidence_of_airspeed+
438 _rotor->getAirfoilIncidenceNoLift())*prantl_factor
439 *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
440 ias = incidence_of_airspeed;
441 float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
442 -cyc*_rotor_correction_factor*prantl_factor,v_local_scalar)
443 * v_local_scalar * v_local_scalar * A *rho *0.5;
444 float lift_with_cyc =
445 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
446 * v_local_scalar * v_local_scalar *A *rho*0.5;
447 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
448 //take into account that the rotor is a resonant system where
449 //the cyclic input hase increased result
450 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
451 * v_local_scalar * v_local_scalar * A *rho*0.5;
452 float angle = incidence_of_airspeed - incidence;
453 //angle between blade movement caused by rotor-rotation and the
454 //total movement of the blade
456 lift_moment += r*(lift * Math::cos(angle)
457 - drag * Math::sin(angle));
458 *torque += r*(drag * Math::cos(angle)
459 + lift * Math::sin(angle));
460 if (returnlift!=NULL) *returnlift+=lift;
462 //use 1st order approximation for alpha
463 //float alpha=Math::atan2(lift_moment,_centripetalforce * _len);
465 if (_shared_flap_hinge)
468 if (Math::abs(_alphaalt) >1e-6)
469 div=(_centripetalforce * _len - _mass * _len * 9.81 * relgrav /_alpha0*(_alphaalt+_oppositerp->getAlphaAlt())/(2.0*_alphaalt));
470 if (Math::abs(div)>1e-6)
472 alpha=lift_moment/div;
474 else if(Math::abs(_alphaalt+_oppositerp->getAlphaAlt())>1e-6)
476 float div=(_centripetalforce * _len - _mass * _len * 9.81 *0.5 * relgrav)*(_alphaalt+_oppositerp->getAlphaAlt());
477 if (Math::abs(div)>1e-6)
479 alpha=_oppositerp->getAlphaAlt()+lift_moment/div*_alphaalt;
486 if (_omega/_omegan<0.2)
488 float frac = 0.001+_omega/_omegan*4.995;
489 alpha=Math::clamp(alpha,_alphamin,_alphamax);
490 alpha=_alphaalt*(1-frac)+frac*alpha;
495 float div=(_centripetalforce * _len - _mass * _len * 9.81 /_alpha0);
496 if (Math::abs(div)>1e-6)
497 alpha=lift_moment/div;
505 // Calculate the aerodynamic force given a wind vector v (in the
506 // aircraft's "local" coordinates) and an air density rho. Returns a
507 // torque about the Y axis, too.
508 void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
509 float* torque_scalar)
513 for (int i=0;i<3;i++)
518 _centripetalforce=_mass*_len*_omega*_omega;
519 float vrel[3],vreldir[3];
520 Math::sub3(_speed,v,vrel);
521 float scalar_torque=0;
522 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
523 //Angle of blade which would produce no vertical force (where the
524 //effective incidence is zero)
527 float col=_collective;
528 if (_shared_flap_hinge)
529 _incidence=(col+cyc)-_delta3*0.5*(_alphaalt-_oppositerp->getAlphaAlt());
531 _incidence=(col+cyc)-_delta3*_alphaalt;
532 //the incidence of the rotorblade due to control input reduced by the
533 //delta3 effect, see README.YASIM
534 //float beta=_relamp*cyc+col;
535 //the incidence of the rotorblade which is used for the calculation
537 float alpha,factor; //alpha is the flapping angle
538 //the new flapping angle will be the old flapping angle
539 //+ factor *(alpha - "old flapping angle")
540 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
541 alpha=Math::clamp(alpha,_alphamin,_alphamax);
542 //the incidence is a function of alpha (if _delta* != 0)
543 //Therefore missing: wrap this function in an integrator
544 //(runge kutta e. g.)
547 if (factor>1) factor=1;
550 Math::cross3(_normal,_directionofcentripetalforce,dirblade);
551 //float vblade=Math::abs(Math::dot3(dirblade,v));
553 alpha=_alphaalt+(alpha-_alphaalt)*factor;
555 float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
556 +1*Math::cos(_next90rp->getrealAlpha())
557 +1*Math::cos(_oppositerp->getrealAlpha())
558 +1*Math::cos(alpha))/4;
559 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
561 //missing: consideration of rellenhinge
564 _centripetalforce*=_balance;
565 scalar_torque*=_balance;
567 float xforce = Math::cos(alpha)*_centripetalforce;
568 float zforce = schwenkfactor*Math::sin(alpha)*_centripetalforce;
569 *torque_scalar=scalar_torque;
570 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
571 float thetorque = scalar_torque;
573 float f=_rotor->getCcw()?1:-1;
575 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
576 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
577 +_directionofcentripetalforce[i]*xforce;
581 void Rotorpart::getAccelTorque(float relaccel,float *t)
584 float f=_rotor->getCcw()?1:-1;
586 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
587 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
590 std::ostream & operator<<(std::ostream & out, const Rotorpart& rp)
592 #define i(x) << #x << ":" << rp.x << endl
593 #define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
594 out << "Writing Info on Rotorpart " << endl
598 iv( _pos) // position in local coords
599 iv( _posforceattac) // position in local coords
600 iv( _normal) //direcetion of the rotation axis
601 i( _torque_max_force)
604 iv( _direction_of_movement)
605 iv( _directionofcentripetalforce)
606 iv( _directionofrotorpart)
607 i( _centripetalforce)
617 i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
620 i( _omega) i(_omegan) i(_ddt_omega)
624 i( _twist) //outer incidence = inner inner incidence + _twist
625 i( _number_of_segments)
626 i( _rel_len_where_incidence_is_measured)
627 i( _rel_len_blade_start)
629 i( _torque_of_inertia)
631 i (_alphaoutputbuf[0])
632 i (_alphaoutputbuf[1])
634 i(_rotor_correction_factor)
640 }; // namespace yasim