1 #include <simgear/debug/logstream.hxx>
4 #include "Rotorpart.hpp"
9 const float pi=3.14159;
11 Rotorpart::Rotorpart()
18 #define set3(x,a,b,c) x[0]=a;x[1]=b;x[2]=c;
20 set3 (_directionofzentipetalforce,1,0,0);
21 set3 (_directionofrotorpart,0,1,0);
22 set3 (_direction_of_movement,1,0,0);
23 set3 (_last_torque,0,0,0);
41 _alphaoutputbuf[0][0]=0;
42 _alphaoutputbuf[1][0]=0;
62 _number_of_segments=1;
63 _rel_len_where_incidence_is_measured=0.7;
66 _rel_len_blade_start=0;
68 _rotor_correction_factor=0.6;
71 void Rotorpart::inititeration(float dt,float *rot)
75 while (_phi>(2*pi)) _phi-=2*pi;
76 while (_phi<(0 )) _phi+=2*pi;
77 float a=Math::dot3(rot,_normal);
79 _alphaalt=_alpha*Math::cos(a)
80 +_next90rp->getrealAlpha()*Math::sin(a);
82 _alphaalt=_alpha*Math::cos(a)
83 +_last90rp->getrealAlpha()*Math::sin(-a);
84 //calculate the rotation of the fuselage, determine
85 //the part in the same direction as alpha
86 //and add it ro _alphaalt
87 //alpha is rotation about "normal cross dirofzentf"
90 Math::cross3(_directionofzentipetalforce,_normal,dir);
91 a=Math::dot3(rot,dir);
93 _alphaalt= Math::clamp(_alphaalt,_alphamin,_alphamax);
96 void Rotorpart::setRotor(Rotor *rotor)
101 void Rotorpart::setParameter(char *parametername, float value)
103 #define p(a) if (strcmp(parametername,#a)==0) _##a = value; else
106 p(number_of_segments)
107 p(rel_len_where_incidence_is_measured)
108 p(rel_len_blade_start)
109 p(rotor_correction_factor)
110 SG_LOG(SG_INPUT, SG_ALERT,
111 "internal error in parameter set up for rotorpart: '"
112 << parametername <<"'" << endl);
116 void Rotorpart::setTorque(float torque_max_force,float torque_no_force)
118 _torque_max_force=torque_max_force;
119 _torque_no_force=torque_no_force;
122 void Rotorpart::setTorqueOfInertia(float toi)
124 _torque_of_inertia=toi;
127 void Rotorpart::setWeight(float value)
132 float Rotorpart::getWeight(void)
134 return(_mass/.453); //_mass is in kg, returns pounds
137 void Rotorpart::setPosition(float* p)
140 for(i=0; i<3; i++) _pos[i] = p[i];
143 float Rotorpart::getIncidence()
148 void Rotorpart::getPosition(float* out)
151 for(i=0; i<3; i++) out[i] = _pos[i];
154 void Rotorpart::setPositionForceAttac(float* p)
157 for(i=0; i<3; i++) _posforceattac[i] = p[i];
160 void Rotorpart::getPositionForceAttac(float* out)
163 for(i=0; i<3; i++) out[i] = _posforceattac[i];
166 void Rotorpart::setSpeed(float* p)
169 for(i=0; i<3; i++) _speed[i] = p[i];
170 Math::unit3(_speed,_direction_of_movement);
173 void Rotorpart::setDirectionofZentipetalforce(float* p)
176 for(i=0; i<3; i++) _directionofzentipetalforce[i] = p[i];
179 void Rotorpart::setDirectionofRotorPart(float* p)
182 for(i=0; i<3; i++) _directionofrotorpart[i] = p[i];
185 void Rotorpart::setOmega(float value)
190 void Rotorpart::setOmegaN(float value)
195 void Rotorpart::setDdtOmega(float value)
200 void Rotorpart::setZentipetalForce(float f)
205 void Rotorpart::setMinpitch(float f)
210 void Rotorpart::setMaxpitch(float f)
215 void Rotorpart::setMaxcyclic(float f)
220 void Rotorpart::setMincyclic(float f)
225 void Rotorpart::setDelta3(float f)
230 void Rotorpart::setRelamp(float f)
235 void Rotorpart::setTranslift(float f)
240 void Rotorpart::setDynamic(float f)
245 void Rotorpart::setRelLenHinge(float f)
250 void Rotorpart::setC2(float f)
255 void Rotorpart::setAlpha0(float f)
260 void Rotorpart::setAlphamin(float f)
265 void Rotorpart::setAlphamax(float f)
270 void Rotorpart::setAlpha0factor(float f)
275 void Rotorpart::setDiameter(float f)
280 float Rotorpart::getPhi()
285 float Rotorpart::getAlpha(int i)
290 return _alpha*180/pi;//in Grad = 1
293 if (_alpha2type==1) //yaw or roll
294 return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
296 return (getAlpha(0)+_oppositerp->getAlpha(0)+
297 _next90rp->getAlpha(0)+_last90rp->getAlpha(0))/4;
300 float Rotorpart::getrealAlpha(void)
305 void Rotorpart::setAlphaoutput(char *text,int i)
307 strncpy(_alphaoutputbuf[i>0],text,255);
308 if (i>0) _alpha2type=i;
311 char* Rotorpart::getAlphaoutput(int i)
313 return _alphaoutputbuf[i&1];
316 void Rotorpart::setLen(float value)
321 void Rotorpart::setNormal(float* p)
324 for(i=0; i<3; i++) _normal[i] = p[i];
327 void Rotorpart::getNormal(float* out)
330 for(i=0; i<3; i++) out[i] = _normal[i];
333 void Rotorpart::setCollective(float pos)
338 void Rotorpart::setCyclic(float pos)
343 void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
344 Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp)
348 _oppositerp=oppositerp;
353 void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
356 while(src[n]&&n<(maxlen-1))
364 // Calculate the flapping angle, where zentripetal force and
365 //lift compensate each other
366 float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
367 float incidence, float cyc, float alphaalt, float *torque,
370 float moment[3],v_local[3],v_local_scalar,lift_moment,v_flap[3],v_help[3];
371 float ias;//nur f. dgb
377 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
378 return 0.0;//not initialized. Can happen during startupt of flightgear
379 if (returnlift!=NULL) *returnlift=0;
380 /*float flap_omega=(_nextrp->getrealAlpha()-_lastrp->getrealAlpha())
381 *_omega / pi*_rotor->getNumberOfParts()/4; hier mal die alte version probieren?
383 float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
385 float local_width=_diameter*(1-_rel_len_blade_start)/2.
386 /(float (_number_of_segments));
387 for (n=0;n<_number_of_segments;n++)
389 float rel = (n+.5)/(float (_number_of_segments));
390 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
391 +_rel_len_blade_start);
392 float local_incidence=incidence+_twist *rel -
393 _twist *_rel_len_where_incidence_is_measured;
394 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
395 *_rotor->getTaper()*(1-rel);
396 float A = local_chord * local_width;
397 //calculate the local air speed and the incidence to this speed;
398 Math::mul3(_omega * r , _direction_of_movement , v_local);
400 // add speed component due to flapping
401 Math::mul3(flap_omega * r,_normal,v_flap);
402 Math::add3(v_flap,v_local,v_local);
403 Math::sub3(v_rel_air,v_local,v_local);
404 //v_local is now the total airspeed at the blade
405 //apparent missing: calculating the local_wind = v_rel_air at
406 //every point of the rotor. It differs due to aircraft-rotation
407 //it is considered in v_flap
409 //substract now the component of the air speed parallel to
411 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
412 _directionofrotorpart,v_help);
413 Math::sub3(v_local,v_help,v_local);
415 //split into direction and magnitude
416 v_local_scalar=Math::mag3(v_local);
417 if (v_local_scalar!=0)
418 //Math::unit3(v_local,v_help);
419 Math::mul3(1/v_local_scalar,v_local,v_help);
420 float incidence_of_airspeed = Math::asin(Math::clamp(
421 Math::dot3(v_help,_normal),-1,1)) + local_incidence;
422 ias = incidence_of_airspeed;
424 //reduce the ias (Prantl factor)
425 float prantl_factor=2/pi*Math::acos(Math::exp(
426 -_rotor->getNumberOfBlades()/2.*(1-rel)
427 *Math::sqrt(1+1/Math::sqr(Math::tan(
428 pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
429 incidence_of_airspeed = (incidence_of_airspeed+
430 _rotor->getAirfoilIncidenceNoLift())*prantl_factor
431 *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
432 ias = incidence_of_airspeed;
433 float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
434 -cyc*_rotor_correction_factor,v_local_scalar)
435 * v_local_scalar * v_local_scalar * A *rho *0.5;
436 float lift_with_cyc =
437 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
438 * v_local_scalar * v_local_scalar *A *rho*0.5;
439 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
440 //take into account that the rotor is a resonant system where
441 //the cyclic input hase increased result
442 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
443 * v_local_scalar * v_local_scalar * A *rho*0.5;
444 float angle = incidence_of_airspeed - incidence;
445 //angle between blade movement caused by rotor-rotation and the
446 //total movement of the blade
448 /* the next shold look like this, but this is the inner loop of
449 the rotor simulation. For small angles (and we hav only small
450 angles) the first order approximation works well
451 lift_moment += r*(lift * Math::cos(angle)
452 - drag * Math::sin(angle));
453 *torque += r*(drag * Math::cos(angle)
454 + lift * Math::sin(angle));
456 lift_moment += r*(lift * (1-angle*angle)
458 *torque += r*(drag * (1-angle*angle)
461 if (returnlift!=NULL) *returnlift+=lift;
463 //as above, use 1st order approximation
464 //float alpha=Math::atan2(lift_moment,_zentipetalforce * _len);
466 if ((_zentipetalforce >1e-8) || (_zentipetalforce <-1e-8))
467 alpha=lift_moment/(_zentipetalforce * _len);
473 // Calculate the aerodynamic force given a wind vector v (in the
474 // aircraft's "local" coordinates) and an air density rho. Returns a
475 // torque about the Y axis, too.
476 void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
477 float* torque_scalar)
481 for (int i=0;i<3;i++)
486 _zentipetalforce=_mass*_len*_omega*_omega;
487 float vrel[3],vreldir[3];
488 Math::sub3(_speed,v,vrel);
489 float scalar_torque=0,alpha_alteberechnung=0;
490 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
491 float delta=Math::asin(Math::dot3(_normal,vreldir));
492 //Angle of blade which would produce no vertical force (where the
493 //effective incidence is zero)
495 //float cyc=_mincyclic+(_cyclic+1)/2*(_maxcyclic-_mincyclic);
497 float col=_minpitch+(_collective+1)/2*(_maxpitch-_minpitch);
498 _incidence=(col+cyc)-_delta3*_alphaalt;
499 //the incidence of the rotorblade due to control input reduced by the
500 //delta3 effect, see README.YASIM
501 //float beta=_relamp*cyc+col;
502 //the incidence of the rotorblade which is used for the calculation
504 float alpha,factor; //alpha is the flapping angle
505 //the new flapping angle will be the old flapping angle
506 //+ factor *(alpha - "old flapping angle")
507 if((_omega*10)>_omegan)
508 //the rotor is rotaing quite fast.
509 //(at least 10% of the nominal rotational speed)
511 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
512 //the incidence is a function of alpha (if _delta* != 0)
513 //Therefore missing: wrap this function in an integrator
514 //(runge kutta e. g.)
517 if (factor>1) factor=1;
519 else //the rotor is not rotating or rotating very slowly
521 alpha=calculateAlpha(v,rho,_incidence,cyc,alpha_alteberechnung,
523 //calculate drag etc., e. g. for deccelrating the rotor if engine
524 //is off and omega <10%
525 alpha = Math::clamp(alpha,_alphamin,_alphamax);
526 float rel =_omega*10 / _omegan;
527 alpha=rel * alpha + (1-rel)* _alpha0;
528 factor=_dt*_dynamic/10;
529 if (factor>1) factor=1;
532 float vz=Math::dot3(_normal,v); //the s
534 Math::cross3(_normal,_directionofzentipetalforce,dirblade);
535 float vblade=Math::abs(Math::dot3(dirblade,v));
536 float tliftfactor=Math::sqrt(1+vblade*_translift);
538 alpha=_alphaalt+(alpha-_alphaalt)*factor;
540 float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
541 +1*Math::cos(_next90rp->getrealAlpha())
542 +1*Math::cos(_oppositerp->getrealAlpha())
543 +1*Math::cos(alpha))/4;
544 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
546 //missing: consideration of rellenhinge
547 float xforce = Math::cos(alpha)*_zentipetalforce;
548 float zforce = schwenkfactor*Math::sin(alpha)*_zentipetalforce;
549 *torque_scalar=scalar_torque;
550 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
551 float thetorque = scalar_torque;
553 float f=_rotor->getCcw()?1:-1;
555 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
556 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
557 +_directionofzentipetalforce[i]*xforce;
561 void Rotorpart::getAccelTorque(float relaccel,float *t)
564 float f=_rotor->getCcw()?1:-1;
566 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
567 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
570 std::ostream & operator<<(std::ostream & out, const Rotorpart& rp)
572 #define i(x) << #x << ":" << rp.x << endl
573 #define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
574 out << "Writing Info on Rotorpart " << endl
578 iv( _pos) // position in local coords
579 iv( _posforceattac) // position in local coords
580 iv( _normal) //direcetion of the rotation axis
581 i( _torque_max_force)
584 iv( _direction_of_movement)
585 iv( _directionofzentipetalforce)
586 iv( _directionofrotorpart)
601 i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
604 i( _omega) i(_omegan) i(_ddt_omega)
608 i( _twist) //outer incidence = inner inner incidence + _twist
609 i( _number_of_segments)
610 i( _rel_len_where_incidence_is_measured)
611 i( _rel_len_blade_start)
613 i( _torque_of_inertia)
615 i (_alphaoutputbuf[0])
616 i (_alphaoutputbuf[1])
618 i(_rotor_correction_factor)
624 }; // namespace yasim