]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/Rotorpart.cpp
FGPUIDialog: fix reading from already free'd memory.
[flightgear.git] / src / FDM / YASim / Rotorpart.cpp
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>
10 namespace yasim {
11 using std::endl;
12
13 const float pi=3.14159;
14 float _help = 0;
15 Rotorpart::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
74 void 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
109 void Rotorpart::setRotor(Rotor *rotor)
110 {
111     _rotor=rotor;
112 }
113
114 void 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
129 void 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
135 void Rotorpart::setTorqueOfInertia(float toi)
136 {
137     _torque_of_inertia=toi;
138 }
139
140 void Rotorpart::setWeight(float value)
141 {
142     _mass=value;
143 }
144
145 float Rotorpart::getWeight(void)
146 {
147     return(_mass/.453); //_mass is in kg, returns pounds 
148 }
149
150 void Rotorpart::setPosition(float* p)
151 {
152     for(int i=0; i<3; i++) _pos[i] = p[i];
153 }
154
155 float Rotorpart::getIncidence()
156 {
157     return(_incidence);
158 }
159
160 void Rotorpart::getPosition(float* out)
161 {
162     for(int i=0; i<3; i++) out[i] = _pos[i];
163 }
164
165 void Rotorpart::setPositionForceAttac(float* p)
166 {
167     for(int i=0; i<3; i++) _posforceattac[i] = p[i];
168 }
169
170 void Rotorpart::getPositionForceAttac(float* out)
171 {
172     for(int i=0; i<3; i++) out[i] = _posforceattac[i];
173 }
174
175 void 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
181 void Rotorpart::setDirectionofZentipetalforce(float* p)
182 {
183     for(int i=0; i<3; i++) _directionofcentripetalforce[i] = p[i];
184 }
185
186 void Rotorpart::setDirectionofRotorPart(float* p)
187 {
188     for(int i=0; i<3; i++) _directionofrotorpart[i] = p[i];
189 }
190
191 void Rotorpart::setDirection(float direction)
192 {
193     _direction=direction;
194 }
195
196 void Rotorpart::setOmega(float value)
197 {
198     _omega=value;
199 }
200
201 void Rotorpart::setPhi(float value)
202 {
203     _phi=value;
204 }
205
206 void Rotorpart::setOmegaN(float value)
207 {
208     _omegan=value;
209 }
210
211 void Rotorpart::setDdtOmega(float value)
212 {
213     _ddt_omega=value;
214 }
215
216 void Rotorpart::setZentipetalForce(float f)
217 {
218     _centripetalforce=f;
219
220
221
222 void Rotorpart::setDelta3(float f)
223 {
224     _delta3=f;
225
226
227 void Rotorpart::setRelamp(float f)
228 {
229     _relamp=f;
230
231
232 void Rotorpart::setTranslift(float f)
233 {
234     _translift=f;
235 }
236
237 void Rotorpart::setDynamic(float f)
238 {
239     _dynamic=f;
240 }
241
242 void Rotorpart::setRelLenHinge(float f)
243 {
244     _rellenhinge=f;
245 }
246
247 void Rotorpart::setSharedFlapHinge(bool s)
248 {
249     _shared_flap_hinge=s;
250 }
251
252 void Rotorpart::setC2(float f)
253 {
254     _c2=f;
255 }
256
257 void Rotorpart::setAlpha0(float f)
258 {
259     if (f>-0.01) f=-0.01; //half a degree bending 
260     _alpha0=f;
261 }
262
263 void Rotorpart::setAlphamin(float f)
264 {
265     _alphamin=f;
266 }
267
268 void Rotorpart::setAlphamax(float f)
269 {
270     _alphamax=f;
271 }
272
273 void Rotorpart::setAlpha0factor(float f)
274 {
275     _alpha0factor=f;
276 }
277
278 void Rotorpart::setDiameter(float f)
279 {
280     _diameter=f;
281 }
282
283 float Rotorpart::getPhi()
284 {
285     return(_phi);
286 }
287
288 float 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 }
303 float Rotorpart::getrealAlpha(void)
304 {
305     return _alpha;
306 }
307
308 void Rotorpart::setAlphaoutput(char *text,int i)
309 {
310     strncpy(_alphaoutputbuf[i>0],text,255);
311     if (i>0) _alpha2type=i;
312 }
313
314 char* Rotorpart::getAlphaoutput(int i)
315 {
316     return _alphaoutputbuf[i&1];
317 }
318
319 void Rotorpart::setLen(float value)
320 {
321     _len=value;
322 }
323
324 void Rotorpart::setNormal(float* p)
325 {
326     for(int i=0; i<3; i++) _normal[i] = p[i];
327 }
328
329 void Rotorpart::getNormal(float* out)
330 {
331     for(int i=0; i<3; i++) out[i] = _normal[i];
332 }
333
334 void Rotorpart::setCollective(float pos)
335 {
336     _collective = pos;
337 }
338
339 void Rotorpart::setCyclic(float pos)
340 {
341     _cyclic = pos;
342 }
343
344 void 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
354 void 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
367 float 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.
495 void 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
567 void 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
576 std::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