FlightGear next
Rotorpart.cpp
Go to the documentation of this file.
1#include <ostream>
2
3#include <simgear/debug/logstream.hxx>
4
5#include "Math.hpp"
6#include "Rotorpart.hpp"
7#include "Rotor.hpp"
8#include <stdio.h>
9#include <string.h>
10namespace yasim {
11using std::endl;
12
13const float pi=3.14159;
14float _help = 0;
15Rotorpart::Rotorpart()
16{
17 _compiled=0;
18 _cyclic=0;
19 _collective=0;
20 _rellenhinge=0;
21 _shared_flap_hinge=false;
22 _dt=0;
23#define set3(x,a,b,c) x[0]=a;x[1]=b;x[2]=c;
24 set3 (_speed,1,0,0);
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);
29#undef set3
30 _centripetalforce=1;
31 _delta3=0.5;
32 _cyclic=0;
33 _collective=-1;
34 _relamp=1;
35 _mass=10;
36 _incidence = 0;
37 _alpha=0;
38 _alphamin=-.1;
39 _alphamax= .1;
40 _alpha0=-.05;
41 _alpha0factor=1;
42 _alphaoutputbuf[0][0]=0;
43 _alphaoutputbuf[1][0]=0;
44 _alpha2type=0;
45 _alphaalt=0;
46 _lastrp=0;
47 _nextrp=0;
48 _oppositerp=0;
49 _last90rp=0;
50 _next90rp=0;
51 _translift=0;
52 _dynamic=100;
53 _c2=0;
54 _torque_max_force=0;
55 _torque_no_force=0;
56 _omega=0;
57 _omegan=1;
58 _ddt_omega=0;
59 _phi=0;
60 _len=1;
61 _rotor=NULL;
62 _twist=0;
63 _number_of_segments=1;
64 _rel_len_where_incidence_is_measured=0.7;
65 _diameter=10;
66 _torque_of_inertia=0;
67 _rel_len_blade_start=0;
68 _torque=0;
69 _rotor_correction_factor=0.6;
70 _direction=0;
71 _balance=1;
72}
73
74void Rotorpart::inititeration(float dt,float *rot)
75{
76 _dt=dt;
77 _phi+=_omega*dt;
78 while (_phi>(2*pi)) _phi-=2*pi;
79 while (_phi<(0 )) _phi+=2*pi;
80 float a=Math::dot3(rot,_normal);
81 if(a>0)
82 _alphaalt=_alpha*Math::cos(a)
83 +_next90rp->getrealAlpha()*Math::sin(a);
84 else
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"
91
92 float dir[3];
93 Math::cross3(_directionofcentripetalforce,_normal,dir);
94 a=Math::dot3(rot,dir);
95 _alphaalt -= a;
96 _alphaalt= Math::clamp(_alphaalt,_alphamin,_alphamax);
97
98 //unbalance
99 float b;
100 b=_rotor->getBalance();
101 float s =Math::sin(_phi+_direction);
102 //float c =Math::cos(_phi+_direction);
103 if (s>0)
104 _balance=(b>0)?(1.-s*(1.-b)):(1.-s)*(1.+b);
105 else
106 _balance=(b>0)?1.:1.+b;
107}
108
109void Rotorpart::setRotor(Rotor *rotor)
110{
111 _rotor=rotor;
112}
113
114void Rotorpart::setParameter(const char *parametername, float value)
115{
116#define p(a) if (strcmp(parametername,#a)==0) _##a = value; else
117
118 p(twist)
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);
126#undef p
127}
128
129void Rotorpart::setTorque(float torque_max_force,float torque_no_force)
130{
131 _torque_max_force=torque_max_force;
132 _torque_no_force=torque_no_force;
133}
134
135void Rotorpart::setTorqueOfInertia(float toi)
136{
137 _torque_of_inertia=toi;
138}
139
140void Rotorpart::setWeight(float value)
141{
142 _mass=value;
143}
144
145float Rotorpart::getWeight(void)
146{
147 return(_mass/.453); //_mass is in kg, returns pounds
148}
149
150void Rotorpart::setPosition(float* p)
151{
152 for(int i=0; i<3; i++) _pos[i] = p[i];
153}
154
155float Rotorpart::getIncidence()
156{
157 return(_incidence);
158}
159
160void Rotorpart::getPosition(float* out)
161{
162 for(int i=0; i<3; i++) out[i] = _pos[i];
163}
164
165void Rotorpart::setPositionForceAttac(float* p)
166{
167 for(int i=0; i<3; i++) _posforceattac[i] = p[i];
168}
169
170void Rotorpart::getPositionForceAttac(float* out)
171{
172 for(int i=0; i<3; i++) out[i] = _posforceattac[i];
173}
174
175void Rotorpart::setSpeed(float* p)
176{
177 for(int i=0; i<3; i++) _speed[i] = p[i];
178 Math::unit3(_speed,_direction_of_movement);
179}
180
181void Rotorpart::setDirectionofZentipetalforce(float* p)
182{
183 for(int i=0; i<3; i++) _directionofcentripetalforce[i] = p[i];
184}
185
186void Rotorpart::setDirectionofRotorPart(float* p)
187{
188 for(int i=0; i<3; i++) _directionofrotorpart[i] = p[i];
189}
190
191void Rotorpart::setDirection(float direction)
192{
193 _direction=direction;
194}
195
196void Rotorpart::setOmega(float value)
197{
198 _omega=value;
199}
200
201void Rotorpart::setPhi(float value)
202{
203 _phi=value;
204}
205
206void Rotorpart::setOmegaN(float value)
207{
208 _omegan=value;
209}
210
211void Rotorpart::setDdtOmega(float value)
212{
213 _ddt_omega=value;
214}
215
216void Rotorpart::setZentipetalForce(float f)
217{
218 _centripetalforce=f;
219}
220
221
222void Rotorpart::setDelta3(float f)
223{
224 _delta3=f;
225}
226
227void Rotorpart::setRelamp(float f)
228{
229 _relamp=f;
230}
231
232void Rotorpart::setTranslift(float f)
233{
234 _translift=f;
235}
236
237void Rotorpart::setDynamic(float f)
238{
239 _dynamic=f;
240}
241
242void Rotorpart::setRelLenHinge(float f)
243{
244 _rellenhinge=f;
245}
246
247void Rotorpart::setSharedFlapHinge(bool s)
248{
249 _shared_flap_hinge=s;
250}
251
252void Rotorpart::setC2(float f)
253{
254 _c2=f;
255}
256
257void Rotorpart::setAlpha0(float f)
258{
259 if (f>-0.01) f=-0.01; //half a degree bending
260 _alpha0=f;
261}
262
263void Rotorpart::setAlphamin(float f)
264{
265 _alphamin=f;
266}
267
268void Rotorpart::setAlphamax(float f)
269{
270 _alphamax=f;
271}
272
273void Rotorpart::setAlpha0factor(float f)
274{
275 _alpha0factor=f;
276}
277
278void Rotorpart::setDiameter(float f)
279{
280 _diameter=f;
281}
282
283float Rotorpart::getPhi()
284{
285 return(_phi);
286}
287
288float Rotorpart::getAlpha(int i)
289{
290 i=i&1;
291
292 if (i==0)
293 return _alpha*180/pi;//in Grad = 1
294 else
295 {
296 if (_alpha2type==1) //yaw or roll
297 return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
298 else //collective
299 return (getAlpha(0)+_oppositerp->getAlpha(0)+
300 _next90rp->getAlpha(0)+_last90rp->getAlpha(0))/4;
301 }
302}
303float Rotorpart::getrealAlpha(void)
304{
305 return _alpha;
306}
307
308void Rotorpart::setAlphaoutput(char *text,int i)
309{
310 strncpy(_alphaoutputbuf[i>0],text,255);
311 if (i>0) _alpha2type=i;
312}
313
314char* Rotorpart::getAlphaoutput(int i)
315{
316 return _alphaoutputbuf[i&1];
317}
318
319void Rotorpart::setLen(float value)
320{
321 _len=value;
322}
323
324void Rotorpart::setNormal(float* p)
325{
326 for(int i=0; i<3; i++) _normal[i] = p[i];
327}
328
329void Rotorpart::getNormal(float* out)
330{
331 for(int i=0; i<3; i++) out[i] = _normal[i];
332}
333
334void Rotorpart::setCollective(float pos)
335{
336 _collective = pos;
337}
338
339void Rotorpart::setCyclic(float pos)
340{
341 _cyclic = pos;
342}
343
344void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
345 Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp)
346{
347 _lastrp=lastrp;
348 _nextrp=nextrp;
349 _oppositerp=oppositerp;
350 _last90rp=last90rp;
351 _next90rp=next90rp;
352}
353
354void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
355{
356 int n=0;
357 while(src[n]&&n<(maxlen-1))
358 {
359 dest[n]=src[n];
360 n++;
361 }
362 dest[n]=0;
363}
364
365// Calculate the flapping angle, where zentripetal force and
366//lift compensate each other
367float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
368 float incidence, float cyc, float alphaalt, float *torque,
369 float *returnlift)
370{
371 float v_local[3],v_local_scalar,lift_moment,v_flap[3],v_help[3];
372 float relgrav = Math::dot3(_normal,_rotor->getGravDirection());
373 lift_moment=-_mass*_len*9.81*relgrav;
374 *torque=0;//
375 if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL))
376 return 0.0;//not initialized. Can happen during startup of flightgear
377 if (returnlift!=NULL) *returnlift=0;
378 float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
379 *_omega / pi;
380 float local_width=_diameter*(1-_rel_len_blade_start)/2.
381 /(float (_number_of_segments));
382 for (int n=0;n<_number_of_segments;n++)
383 {
384 float rel = (n+.5)/(float (_number_of_segments));
385 float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
386 +_rel_len_blade_start);
387 float local_incidence=incidence+_twist *rel -
388 _twist *_rel_len_where_incidence_is_measured;
389 float local_chord = _rotor->getChord()*rel+_rotor->getChord()
390 *_rotor->getTaper()*(1-rel);
391 float A = local_chord * local_width;
392 //calculate the local air speed and the incidence to this speed;
393 Math::mul3(_omega * r , _direction_of_movement , v_local);
394
395 // add speed component due to flapping
396 Math::mul3(flap_omega * r,_normal,v_flap);
397 Math::add3(v_flap,v_local,v_local);
398 Math::sub3(v_rel_air,v_local,v_local);
399 //v_local is now the total airspeed at the blade
400 //apparent missing: calculating the local_wind = v_rel_air at
401 //every point of the rotor. It differs due to aircraft-rotation
402 //it is considered in v_flap
403
404 //substract now the component of the air speed parallel to
405 //the blade;
406 Math::mul3(Math::dot3(v_local,_directionofrotorpart),
407 _directionofrotorpart,v_help);
408 Math::sub3(v_local,v_help,v_local);
409
410 //split into direction and magnitude
411 v_local_scalar=Math::mag3(v_local);
412 if (v_local_scalar!=0)
413 //Math::unit3(v_local,v_help);
414 Math::mul3(1/v_local_scalar,v_local,v_help);
415 float incidence_of_airspeed = Math::asin(Math::clamp(
416 Math::dot3(v_help,_normal),-1,1)) + local_incidence;
417 //ias = incidence_of_airspeed;
418
419 //reduce the ias (Prantl factor)
420 float prantl_factor=2/pi*Math::acos(Math::exp(
421 -_rotor->getNumberOfBlades()/2.*(1-rel)
422 *Math::sqrt(1+1/Math::sqr(Math::tan(
423 pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
424 incidence_of_airspeed = (incidence_of_airspeed+
425 _rotor->getAirfoilIncidenceNoLift())*prantl_factor
426 *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
427 //ias = incidence_of_airspeed;
428 float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
429 -cyc*_rotor_correction_factor*prantl_factor,v_local_scalar)
430 * v_local_scalar * v_local_scalar * A *rho *0.5;
431 float lift_with_cyc =
432 _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
433 * v_local_scalar * v_local_scalar *A *rho*0.5;
434 float lift=lift_wo_cyc+_relamp*(lift_with_cyc-lift_wo_cyc);
435 //take into account that the rotor is a resonant system where
436 //the cyclic input hase increased result
437 float drag = -_rotor->getDragCoef(incidence_of_airspeed,v_local_scalar)
438 * v_local_scalar * v_local_scalar * A *rho*0.5;
439 float angle = incidence_of_airspeed - incidence;
440 //angle between blade movement caused by rotor-rotation and the
441 //total movement of the blade
442
443 lift_moment += r*(lift * Math::cos(angle)
444 - drag * Math::sin(angle));
445 *torque += r*(drag * Math::cos(angle)
446 + lift * Math::sin(angle));
447 if (returnlift!=NULL) *returnlift+=lift;
448 }
449 //use 1st order approximation for alpha
450 //float alpha=Math::atan2(lift_moment,_centripetalforce * _len);
451 float alpha;
452 if (_shared_flap_hinge)
453 {
454 float div=0;
455 if (Math::abs(_alphaalt) >1e-6)
456 div=(_centripetalforce * _len - _mass * _len * 9.81 * relgrav /_alpha0*(_alphaalt+_oppositerp->getAlphaAlt())/(2.0*_alphaalt));
457 if (Math::abs(div)>1e-6)
458 {
459 alpha=lift_moment/div;
460 }
461 else if(Math::abs(_alphaalt+_oppositerp->getAlphaAlt())>1e-6)
462 {
463 float div=(_centripetalforce * _len - _mass * _len * 9.81 *0.5 * relgrav)*(_alphaalt+_oppositerp->getAlphaAlt());
464 if (Math::abs(div)>1e-6)
465 {
466 alpha=_oppositerp->getAlphaAlt()+lift_moment/div*_alphaalt;
467 }
468 else
469 alpha=_alphaalt;
470 }
471 else
472 alpha=_alphaalt;
473 if (_omega/_omegan<0.2)
474 {
475 float frac = 0.001+_omega/_omegan*4.995;
476 alpha=Math::clamp(alpha,_alphamin,_alphamax);
477 alpha=_alphaalt*(1-frac)+frac*alpha;
478 }
479 }
480 else
481 {
482 float div=(_centripetalforce * _len - _mass * _len * 9.81 /_alpha0);
483 if (Math::abs(div)>1e-6)
484 alpha=lift_moment/div;
485 else
486 alpha=_alphaalt;
487 }
488
489 return (alpha);
490}
491
492// Calculate the aerodynamic force given a wind vector v (in the
493// aircraft's "local" coordinates) and an air density rho. Returns a
494// torque about the Y axis, too.
495void Rotorpart::calcForce(float* v, float rho, float* out, float* torque,
496 float* torque_scalar)
497{
498 if (_compiled!=1)
499 {
500 for (int i=0;i<3;i++)
501 torque[i]=out[i]=0;
502 *torque_scalar=0;
503 return;
504 }
505 _centripetalforce=_mass*_len*_omega*_omega;
506 float vrel[3],vreldir[3];
507 Math::sub3(_speed,v,vrel);
508 float scalar_torque=0;
509 Math::unit3(vrel,vreldir);//direction of blade-movement rel. to air
510 //Angle of blade which would produce no vertical force (where the
511 //effective incidence is zero)
512
513 float cyc=_cyclic;
514 float col=_collective;
515 if (_shared_flap_hinge)
516 _incidence=(col+cyc)-_delta3*0.5*(_alphaalt-_oppositerp->getAlphaAlt());
517 else
518 _incidence=(col+cyc)-_delta3*_alphaalt;
519 //the incidence of the rotorblade due to control input reduced by the
520 //delta3 effect, see README.YASIM
521 //float beta=_relamp*cyc+col;
522 //the incidence of the rotorblade which is used for the calculation
523
524 float alpha,factor; //alpha is the flapping angle
525 //the new flapping angle will be the old flapping angle
526 //+ factor *(alpha - "old flapping angle")
527 alpha=calculateAlpha(v,rho,_incidence,cyc,0,&scalar_torque);
528 alpha=Math::clamp(alpha,_alphamin,_alphamax);
529 //the incidence is a function of alpha (if _delta* != 0)
530 //Therefore missing: wrap this function in an integrator
531 //(runge kutta e. g.)
532
533 factor=_dt*_dynamic;
534 if (factor>1) factor=1;
535
536 float dirblade[3];
537 Math::cross3(_normal,_directionofcentripetalforce,dirblade);
538 //float vblade=Math::abs(Math::dot3(dirblade,v));
539
540 alpha=_alphaalt+(alpha-_alphaalt)*factor;
541 _alpha=alpha;
542 float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
543 +1*Math::cos(_next90rp->getrealAlpha())
544 +1*Math::cos(_oppositerp->getrealAlpha())
545 +1*Math::cos(alpha))/4;
546 float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
547
548 //missing: consideration of rellenhinge
549
550 //add the unbalance
551 _centripetalforce*=_balance;
552 scalar_torque*=_balance;
553
554 float xforce = Math::cos(alpha)*_centripetalforce;
555 float zforce = schwenkfactor*Math::sin(alpha)*_centripetalforce;
556 *torque_scalar=scalar_torque;
557 scalar_torque+= 0*_ddt_omega*_torque_of_inertia;
558 float thetorque = scalar_torque;
559 float f=_rotor->getCcw()?1:-1;
560 for(int i=0; i<3; i++) {
561 _last_torque[i]=torque[i] = f*_normal[i]*thetorque;
562 out[i] = _normal[i]*zforce*_rotor->getLiftFactor()
563 +_directionofcentripetalforce[i]*xforce;
564 }
565}
566
567void Rotorpart::getAccelTorque(float relaccel,float *t)
568{
569 float f=_rotor->getCcw()?1:-1;
570 for(int i=0; i<3; i++) {
571 t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
572 _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
573 }
574}
575
576std::ostream & operator<<(std::ostream & out, const Rotorpart& rp)
577{
578#define i(x) << #x << ":" << rp.x << endl
579#define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
580 out << "Writing Info on Rotorpart " << endl
581 i( _dt)
582 iv( _last_torque)
583 i( _compiled)
584 iv( _pos) // position in local coords
585 iv( _posforceattac) // position in local coords
586 iv( _normal) //direcetion of the rotation axis
587 i( _torque_max_force)
588 i( _torque_no_force)
589 iv( _speed)
590 iv( _direction_of_movement)
591 iv( _directionofcentripetalforce)
592 iv( _directionofrotorpart)
593 i( _centripetalforce)
594 i( _cyclic)
595 i( _collective)
596 i( _delta3)
597 i( _dynamic)
598 i( _translift)
599 i( _c2)
600 i( _mass)
601 i( _alpha)
602 i( _alphaalt)
603 i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
604 i( _rellenhinge)
605 i( _relamp)
606 i( _omega) i(_omegan) i(_ddt_omega)
607 i( _phi)
608 i( _len)
609 i( _incidence)
610 i( _twist) //outer incidence = inner inner incidence + _twist
611 i( _number_of_segments)
612 i( _rel_len_where_incidence_is_measured)
613 i( _rel_len_blade_start)
614 i( _diameter)
615 i( _torque_of_inertia)
616 i( _torque)
617 i (_alphaoutputbuf[0])
618 i (_alphaoutputbuf[1])
619 i( _alpha2type)
620 i(_rotor_correction_factor)
621 << endl;
622#undef i
623#undef iv
624 return out;
625}
626}; // namespace yasim
#define p(x)
#define _normal
#define i(x)
#define iv(x)
#define set3(x, a, b, c)
#define A
float _help
Definition Rotorpart.cpp:14
std::ostream & operator<<(std::ostream &out, Rotor &r)
Definition Rotor.cpp:1352
const float pi
Definition Rotor.cpp:29
static const double pi
Definition sview.cxx:59