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;
60 _number_of_segments=1;
61 _rel_len_where_incidence_is_measured=0.7;
64 _rel_len_blade_start=0;
67 void Rotorpart::inititeration(float dt,float *rot)
71 while (_phi>(2*pi)) _phi-=2*pi;
72 while (_phi<(0 )) _phi+=2*pi;
73 float a=Math::dot3(rot,_normal);
75 _alphaalt=_alpha*Math::cos(a)
76 +_nextrp->getrealAlpha()*Math::sin(a);
78 _alphaalt=_alpha*Math::cos(a)
79 +_lastrp->getrealAlpha()*Math::sin(-a);
80 //calculate the rotation of the fuselage, determine
81 //the part in the same direction as alpha
82 //and add it ro _alphaalt
83 //alpha is rotation about "normal cross dirofzentf"
86 Math::cross3(_directionofzentipetalforce,_normal,dir);
87 a=Math::dot3(rot,dir);
89 _alphaalt= Math::clamp(_alphaalt,_alphamin,_alphamax);
92 void Rotorpart::setRotor(Rotor *rotor)
97 void Rotorpart::setParameter(char *parametername, float value)
99 #define p(a) if (strcmp(parametername,#a)==0) _##a = value; else
102 p(number_of_segments)
103 p(rel_len_where_incidence_is_measured)
104 p(rel_len_blade_start)
105 cout << "internal error in parameter set up for rotorpart: '"
106 << parametername <<"'" << endl;
110 void Rotorpart::setTorque(float torque_max_force,float torque_no_force)
112 _torque_max_force=torque_max_force;
113 _torque_no_force=torque_no_force;
116 void Rotorpart::setTorqueOfInertia(float toi)
118 _torque_of_inertia=toi;
121 void Rotorpart::setWeight(float value)
126 float Rotorpart::getWeight(void)
128 return(_mass/.453); //_mass is in kg, returns pounds
131 void Rotorpart::setPosition(float* p)
134 for(i=0; i<3; i++) _pos[i] = p[i];
137 float Rotorpart::getIncidence()
142 void Rotorpart::getPosition(float* out)
145 for(i=0; i<3; i++) out[i] = _pos[i];
148 void Rotorpart::setPositionForceAttac(float* p)
151 for(i=0; i<3; i++) _posforceattac[i] = p[i];
154 void Rotorpart::getPositionForceAttac(float* out)
157 for(i=0; i<3; i++) out[i] = _posforceattac[i];
160 void Rotorpart::setSpeed(float* p)
163 for(i=0; i<3; i++) _speed[i] = p[i];
164 Math::unit3(_speed,_direction_of_movement);
167 void Rotorpart::setDirectionofZentipetalforce(float* p)
170 for(i=0; i<3; i++) _directionofzentipetalforce[i] = p[i];
173 void Rotorpart::setDirectionofRotorPart(float* p)
176 for(i=0; i<3; i++) _directionofrotorpart[i] = p[i];
179 void Rotorpart::setOmega(float value)
184 void Rotorpart::setOmegaN(float value)
189 void Rotorpart::setDdtOmega(float value)
194 void Rotorpart::setZentipetalForce(float f)
199 void Rotorpart::setMinpitch(float f)
204 void Rotorpart::setMaxpitch(float f)
209 void Rotorpart::setMaxcyclic(float f)
214 void Rotorpart::setMincyclic(float f)
219 void Rotorpart::setDelta3(float f)
224 void Rotorpart::setRelamp(float f)
229 void Rotorpart::setTranslift(float f)
234 void Rotorpart::setDynamic(float f)
239 void Rotorpart::setRelLenHinge(float f)
244 void Rotorpart::setC2(float f)
249 void Rotorpart::setAlpha0(float f)
254 void Rotorpart::setAlphamin(float f)
259 void Rotorpart::setAlphamax(float f)
264 void Rotorpart::setAlpha0factor(float f)
269 void Rotorpart::setDiameter(float f)
274 float Rotorpart::getPhi()
279 float Rotorpart::getAlpha(int i)
284 return _alpha*180/3.14;//in Grad = 1
287 if (_alpha2type==1) //yaw or roll
288 return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
290 return (getAlpha(0)+_oppositerp->getAlpha(0)+
291 _nextrp->getAlpha(0)+_lastrp->getAlpha(0))/4;
294 float Rotorpart::getrealAlpha(void)
299 void Rotorpart::setAlphaoutput(char *text,int i)
301 SG_LOG(SG_FLIGHT, SG_DEBUG, "setAlphaoutput rotorpart ["
302 << text << "] typ" << i);
304 strncpy(_alphaoutputbuf[i>0],text,255);
306 if (i>0) _alpha2type=i;
309 char* Rotorpart::getAlphaoutput(int i)
311 return _alphaoutputbuf[i&1];
314 void Rotorpart::setLen(float value)
319 void Rotorpart::setNormal(float* p)
322 for(i=0; i<3; i++) _normal[i] = p[i];
325 void Rotorpart::getNormal(float* out)
328 for(i=0; i<3; i++) out[i] = _normal[i];
331 void Rotorpart::setCollective(float pos)
336 void Rotorpart::setCyclic(float pos)
341 void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
342 Rotorpart *oppositerp)
346 _oppositerp=oppositerp;
349 void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
352 while(src[n]&&n<(maxlen-1))
360 // Calculate the flapping angle, where zentripetal force and
361 //lift compensate each other
362 float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
363 float incidence, float cyc, float alphaalt, float *torque,
366 float moment[3],v_local[3],v_local_scalar,lift_moment,v_flap[3],v_help[3];
367 float ias;//nur f. dgb
373 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
374 return 0.0;//not initialized. Can happen during startupt of flightgear
375 if (returnlift!=NULL) *returnlift=0;
376 float flap_omega=(_nextrp->getrealAlpha()-_lastrp->getrealAlpha())
378 float local_width=_diameter*(1-_rel_len_blade_start)/2.
379 /(float (_number_of_segments));
380 for (n=0;n<_number_of_segments;n++)
382 float rel = (n+.5)/(float (_number_of_segments));
383 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
384 +_rel_len_blade_start);
385 float local_incidence=incidence+_twist *rel - _twist
386 *_rel_len_where_incidence_is_measured;
387 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
388 *_rotor->getTaper()*(1-rel);
389 float A = local_chord * local_width;
390 //calculate the local air speed and the incidence to this speed;
391 Math::mul3(_omega * r , _direction_of_movement , v_local);
393 // add speed component due to flapping
394 Math::mul3(flap_omega * r,_normal,v_flap);
395 Math::add3(v_flap,v_local,v_local);
396 Math::sub3(v_rel_air,v_local,v_local);
397 //v_local is now the total airspeed at the blade
398 //apparent missing: calculating the local_wind = v_rel_air at
399 //every point of the rotor. It differs due to aircraft-rotation
400 //it is considered in v_flap
402 //substract now the component of the air speed parallel to
404 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
405 _directionofrotorpart,v_help);
406 Math::sub3(v_local,v_help,v_local);
408 //split into direction and magnitude
409 v_local_scalar=Math::mag3(v_local);
410 if (v_local_scalar!=0)
411 Math::unit3(v_local,v_local);
412 float incidence_of_airspeed = Math::asin(Math::clamp(
413 Math::dot3(v_local,_normal),-1,1)) + local_incidence;
414 ias = incidence_of_airspeed;
416 _rotor->getLiftCoef(incidence_of_airspeed-cyc,v_local_scalar)
417 * v_local_scalar * v_local_scalar * A *rho *0.5;
418 float lift_with_cyc =
419 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
420 * v_local_scalar * v_local_scalar *A *rho*0.5;
421 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
422 //take into account that the rotor is a resonant system where
423 //the cyclic input hase increased result
424 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
425 * v_local_scalar * v_local_scalar * A *rho*0.5;
426 float angle = incidence_of_airspeed - incidence;
427 //angle between blade movement caused by rotor-rotation and the
428 //total movement of the blade
430 lift_moment += r*(lift * Math::cos(angle)
431 - drag * Math::sin(angle));
432 *torque += r*(drag * Math::cos(angle)
433 + lift * Math::sin(angle));
435 if (returnlift!=NULL) *returnlift+=lift;
437 float alpha=Math::atan2(lift_moment,_zentipetalforce * _len);
442 // Calculate the aerodynamic force given a wind vector v (in the
443 // aircraft's "local" coordinates) and an air density rho. Returns a
444 // torque about the Y axis, too.
445 void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
446 float* torque_scalar)
450 for (int i=0;i<3;i++)
455 _zentipetalforce=_mass*_len*_omega*_omega;
456 float vrel[3],vreldir[3];
457 Math::sub3(_speed,v,vrel);
458 float scalar_torque=0,alpha_alteberechnung=0;
459 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
460 float delta=Math::asin(Math::dot3(_normal,vreldir));
461 //Angle of blade which would produce no vertical force (where the
462 //effective incidence is zero)
464 float cyc=_mincyclic+(_cyclic+1)/2*(_maxcyclic-_mincyclic);
465 float col=_minpitch+(_collective+1)/2*(_maxpitch-_minpitch);
466 _incidence=(col+cyc)-_delta3*_alphaalt;
467 //the incidence of the rotorblade due to control input reduced by the
468 //delta3 effect, see README.YASIM
469 float beta=_relamp*cyc+col;
470 //the incidence of the rotorblade which is used for the calculation
472 float alpha,factor; //alpha is the flapping angle
473 //the new flapping angle will be the old flapping angle
474 //+ factor *(alpha - "old flapping angle")
475 if((_omega*10)>_omegan)
476 //the rotor is rotaing quite fast.
477 //(at least 10% of the nominal rotational speed)
479 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
480 //the incidence is a function of alpha (if _delta* != 0)
481 //Therefore missing: wrap this function in an integrator
482 //(runge kutta e. g.)
485 if (factor>1) factor=1;
487 else //the rotor is not rotating or rotating very slowly
489 alpha=calculateAlpha(v,rho,_incidence,cyc,alpha_alteberechnung,
491 //calculate drag etc., e. g. for deccelrating the rotor if engine
492 //is off and omega <10%
494 float rel =_omega*10 / _omegan;
495 alpha=rel * alpha + (1-rel)* _alpha0;
496 factor=_dt*_dynamic/10;
497 if (factor>1) factor=1;
500 float vz=Math::dot3(_normal,v); //the s
502 Math::cross3(_normal,_directionofzentipetalforce,dirblade);
503 float vblade=Math::abs(Math::dot3(dirblade,v));
504 float tliftfactor=Math::sqrt(1+vblade*_translift);
506 alpha=_alphaalt+(alpha-_alphaalt)*factor;
508 float meancosalpha=(1*Math::cos(_lastrp->getrealAlpha())
509 +1*Math::cos(_nextrp->getrealAlpha())
510 +1*Math::cos(_oppositerp->getrealAlpha())
511 +1*Math::cos(alpha))/4;
512 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha);
514 //missing: consideration of rellenhinge
515 float xforce = Math::cos(alpha)*_zentipetalforce;
516 float zforce = schwenkfactor*Math::sin(alpha)*_zentipetalforce;
517 *torque_scalar=scalar_torque;
518 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
519 float thetorque = scalar_torque;
521 float f=_rotor->getCcw()?1:-1;
523 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
524 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
525 +_directionofzentipetalforce[i]*xforce;
529 void Rotorpart::getAccelTorque(float relaccel,float *t)
532 float f=_rotor->getCcw()?1:-1;
534 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;
535 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
538 }; // namespace yasim