]> git.mxchange.org Git - flightgear.git/commitdiff
Helicopter update from Maik:
authorandy <andy>
Thu, 14 Sep 2006 18:18:33 +0000 (18:18 +0000)
committerandy <andy>
Thu, 14 Sep 2006 18:18:33 +0000 (18:18 +0000)
 More realistic calculation of vortices at the blades and therefore
 real airfoil parameters can be used now (not to be mixed up with the
 vortex ring state which is still not simulated), ground effect is now
 continuous e. g. at buildings, calculating of the rotor in more than 4
 directions, better documentation of the airfoil parameters.

src/FDM/YASim/FGFDM.cpp
src/FDM/YASim/Math.cpp
src/FDM/YASim/Math.hpp
src/FDM/YASim/Model.cpp
src/FDM/YASim/Rotor.cpp
src/FDM/YASim/Rotor.hpp
src/FDM/YASim/Rotorpart.cpp
src/FDM/YASim/Rotorpart.hpp

index 761a863750f5e0764d3ae0f01396ba6dac8e065f..1d1074619a0f5e4962ba4365c8c319577dd94354 100644 (file)
@@ -180,13 +180,17 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
         Rotorgear* r = _airplane.getModel()->getRotorgear();
        _currObj = r;
         #define p(x) if (a->hasAttribute(#x)) r->setParameter((char *)#x,attrf(a,#x) );
+        #define p2(x,y) if (a->hasAttribute(#x)) {r->setParameter((char *)#y,attrf(a,#x) ); SG_LOG(SG_INPUT, SG_ALERT,"Warning: Aircraft defnition files uses outdated tag '" <<#x<<"', use '"<<#y<<"' instead (see README.YASim)" <<endl);}
         p(max_power_engine)
         p(engine_prop_factor)
         p(yasimdragfactor)
         p(yasimliftfactor)
         p(max_power_rotor_brake)
-        p(engine_accell_limit)
+        p(rotorgear_friction)
+        p(engine_accel_limit)
+        p2(engine_accell_limit,engine_accel_limit)
         #undef p
+        #undef p2
         r->setInUse();
     } else if(eq(name, "wing")) {
        _airplane.setWing(parseWing(a, name));
@@ -493,8 +497,10 @@ void FGFDM::setOutputProperties(float dt)
         char b[256];
         while((j = r->getValueforFGSet(j, b, &f)))
             if(b[0]) fgSetFloat(b,f);
-        
-        for(j=0; j < r->numRotorparts(); j++) {
+        j=0;
+        while((j = _airplane.getRotorgear()->getValueforFGSet(j, b, &f)))
+            if(b[0]) fgSetFloat(b,f);
+        for(j=0; j < r->numRotorparts(); j+=r->numRotorparts()>>2) {
             Rotorpart* s = (Rotorpart*)r->getRotorpart(j);
             char *b;
             int k;
@@ -692,6 +698,7 @@ Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type)
     p(vortex_state_e2)
     p(twist)
     p(number_of_segments)
+    p(number_of_parts)
     p(rel_len_where_incidence_is_measured)
     p(chord)
     p(taper)
@@ -705,7 +712,8 @@ Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type)
     p(airfoil_lift_coefficient)
     p(airfoil_drag_coefficient0)
     p(airfoil_drag_coefficient1)
-
+    p(cyclic_factor)
+    p(rotor_correction_factor)
 #undef p
     _currObj = w;
     return w;
index c7203941c95215a8450d139c7f5669f5f5204d7d..2c53c35590fdbbc30e1be9f180803d17acee0c76 100644 (file)
@@ -80,6 +80,11 @@ float Math::pow(double base, double exp)
     return (float)::pow(base, exp);
 }
 
+float Math::exp(float f)
+{
+    return (float)::exp(f);
+}
+
 double Math::ceil(double f)
 {
     return ::ceil(f);
index 66bd6cc80a76bc61bcff280d3f1dfcc60b5bdee9..e729f6d72dd0200f620906e432938a772c91a8bd 100644 (file)
@@ -20,6 +20,8 @@ public:
     static float atan2(float y, float x);
     static float asin(float f);
     static float acos(float f);
+    static float exp(float f);
+    static float sqr(float f) {return f*f;}
 
     // Takes two args and runs afoul of the Koenig rules.
     static float pow(double base, double exp);
index 2fcdd5ca0a53c134f9372177847be2966151a98d..42479f95e3104b3bfce843df94a20c944b4620c3 100644 (file)
@@ -312,21 +312,7 @@ void Model::updateGround(State* s)
     }
     for(i=0; i<_rotorgear.getRotors()->size(); i++) {
         Rotor* r = (Rotor*)_rotorgear.getRotors()->get(i);
-
-        // Get the point of the rotor center
-        float pos[3];
-        r->getPosition(pos);
-
-        // Transform the local coordinates to
-        // global coordinates.
-        double pt[3];
-        s->posLocalToGlobal(pos, pt);
-
-        // Ask for the ground plane in the global coordinate system
-        double global_ground[4];
-        float global_vel[3];
-        _ground_cb->getGroundPlane(pt, global_ground, global_vel);
-        r->setGlobalGround(global_ground, global_vel);
+        r->findGroundEffectAltitude(_ground_cb,s);
     }
 
     // The arrester hook
index 0094b23098adc746ee1cca632370f8fb671a9432..e4a8b2970c1a40a46cb230f5b0cdc6fdc6dd9a90 100644 (file)
@@ -3,6 +3,7 @@
 #include "Math.hpp"
 #include "Surface.hpp"
 #include "Rotorpart.hpp"
+#include "Ground.hpp"
 #include "Rotor.hpp"
 
 #include STL_IOSTREAM
 
 SG_USING_STD(setprecision);
 
+#ifdef TEST_DEBUG
 #include <stdio.h>
+#endif
+#include <string.h>
+#include <iostream>
+#include <sstream>
+
+
 
 namespace yasim {
 
@@ -50,6 +58,8 @@ Rotor::Rotor()
     _mincyclicail=-10./180*pi;
     _mincyclicele=-10./180*pi;
     _min_pitch=-.5/180*pi;
+    _cyclicele=0;
+    _cyclicail=0;
     _name[0] = 0;
     _normal[0] = _normal[1] = 0;
     _normal[2] = 1;
@@ -81,12 +91,14 @@ Rotor::Rotor()
     _vortex_state_e1=1;
     _vortex_state_e2=1;
     _vortex_state_e3=1;
+    _vortex_state=0;
     _lift_factor=1;
     _liftcoef=0.1;
     _dragcoef0=0.1;
     _dragcoef1=0.1;
     _twist=0; 
     _number_of_segments=1;
+    _number_of_parts=4;
     _rel_len_where_incidence_is_measured=0.7;
     _torque_of_inertia=1;
     _torque=0;
@@ -110,6 +122,13 @@ Rotor::Rotor()
     _stall_v2sum=1;
     _collective=0;
     _yaw=_roll=0;
+    for (int k=0;k<4;k++)
+        for (i=0;i<3;i++)
+            _groundeffectpos[k][i]=0;
+    _ground_effect_altitude=1;
+    _cyclic_factor=1;
+    _lift_factor=_f_ge=_f_vs=_f_tl=1;
+    _rotor_correction_factor=.65;
 }
 
 Rotor::~Rotor()
@@ -130,10 +149,13 @@ void Rotor::inititeration(float dt,float omegarel,float ddt_omegarel,float *rot)
     _ddt_omega=_omegan*ddt_omegarel;
     int i;
     for(i=0; i<_rotorparts.size(); i++) {
+        float s = Math::sin(2*pi*i/_number_of_parts);
+        float c = Math::cos(2*pi*i/_number_of_parts);
         Rotorpart* r = (Rotorpart*)_rotorparts.get(i);
         r->setOmega(_omega);
         r->setDdtOmega(_ddt_omega);
         r->inititeration(dt,rot);
+        r->setCyclic(_cyclicail*c+_cyclicele*s);
     }
 
     //calculate the normal of the rotor disc, for calcualtion of the downwash
@@ -169,10 +191,28 @@ float Rotor::calcStall(float incidence,float speed)
 float Rotor::getLiftCoef(float incidence,float speed)
 {
     float stall=calcStall(incidence,speed);
+    /* the next shold look like this, but this is the inner loop of
+           the rotor simulation. For small angles (and we hav only small
+           angles) the first order approximation works well
     float c1=  Math::sin(incidence-_airfoil_incidence_no_lift)*_liftcoef;
+    for c2 we would need higher order, because in stall the angle can be large
+    */
+    float i2;
+    if (incidence > (pi/2))
+        i2 = incidence-pi;
+    else if (incidence <-(pi/2))
+        i2 = (incidence+pi);
+    else 
+        i2 = incidence;
+    float c1=  (i2-_airfoil_incidence_no_lift)*_liftcoef;
+    if (stall > 0)
+    {
     float c2=  Math::sin(2*(incidence-_airfoil_incidence_no_lift))
         *_liftcoef*_lift_factor_stall;
     return (1-stall)*c1 + stall *c2;
+    }
+    else
+        return c1;
 }
 
 float Rotor::getDragCoef(float incidence,float speed)
@@ -187,14 +227,14 @@ float Rotor::getDragCoef(float incidence,float speed)
 int Rotor::getValueforFGSet(int j,char *text,float *f)
 {
     if (_name[0]==0) return 0;
-    if (4!=numRotorparts()) return 0; //compile first!
+    if (4>numRotorparts()) return 0; //compile first!
     if (j==0)
     {
         sprintf(text,"/rotors/%s/cone", _name);
         *f=( ((Rotorpart*)getRotorpart(0))->getrealAlpha()
-            +((Rotorpart*)getRotorpart(1))->getrealAlpha()
-            +((Rotorpart*)getRotorpart(2))->getrealAlpha()
-            +((Rotorpart*)getRotorpart(3))->getrealAlpha()
+            +((Rotorpart*)getRotorpart(1*(_number_of_parts>>2)))->getrealAlpha()
+            +((Rotorpart*)getRotorpart(2*(_number_of_parts>>2)))->getrealAlpha()
+            +((Rotorpart*)getRotorpart(3*(_number_of_parts>>2)))->getrealAlpha()
             )/4*180/pi;
     }
     else
@@ -202,7 +242,7 @@ int Rotor::getValueforFGSet(int j,char *text,float *f)
         {
             sprintf(text,"/rotors/%s/roll", _name);
             _roll = ( ((Rotorpart*)getRotorpart(0))->getrealAlpha()
-                -((Rotorpart*)getRotorpart(2))->getrealAlpha()
+                -((Rotorpart*)getRotorpart(2*(_number_of_parts>>2)))->getrealAlpha()
                 )/2*(_ccw?-1:1);
             *f=_roll *180/pi;
         }
@@ -210,8 +250,8 @@ int Rotor::getValueforFGSet(int j,char *text,float *f)
             if (j==2)
             {
                 sprintf(text,"/rotors/%s/yaw", _name);
-                _yaw=( ((Rotorpart*)getRotorpart(1))->getrealAlpha()
-                    -((Rotorpart*)getRotorpart(3))->getrealAlpha()
+                _yaw=( ((Rotorpart*)getRotorpart(1*(_number_of_parts>>2)))->getrealAlpha()
+                    -((Rotorpart*)getRotorpart(3*(_number_of_parts>>2)))->getrealAlpha()
                     )/2;
                 *f=_yaw*180/pi;
             }
@@ -271,18 +311,19 @@ int Rotor::getValueforFGSet(int j,char *text,float *f)
                         float rk,rl,p;
                         p=(*f/90);
                         k=int(p);
-                        l=int(p+1);
+                        l=k+1;
                         rk=l-p;
+                        rk=Math::clamp(rk,0,1);//Delete this
                         rl=1-rk;
                         if(w==2) {k+=2;l+=2;}
                         else
                             if(w==1) {k+=1;l+=1;}
                             k%=4;
                             l%=4;
-                            if (w==1) *f=rk*((Rotorpart*) getRotorpart(k))->getrealAlpha()*180/pi
-                                +rl*((Rotorpart*) getRotorpart(l))->getrealAlpha()*180/pi;
-                            else if(w==2) *f=rk*((Rotorpart*)getRotorpart(k))->getIncidence()*180/pi
-                                +rl*((Rotorpart*)getRotorpart(l))->getIncidence()*180/pi;
+                            if (w==1) *f=rk*((Rotorpart*) getRotorpart(k*(_number_of_parts>>2)))->getrealAlpha()*180/pi
+                                +rl*((Rotorpart*) getRotorpart(l*(_number_of_parts>>2)))->getrealAlpha()*180/pi;
+                            else if(w==2) *f=rk*((Rotorpart*)getRotorpart(k*(_number_of_parts>>2)))->getIncidence()*180/pi
+                                +rl*((Rotorpart*)getRotorpart(l*(_number_of_parts>>2)))->getIncidence()*180/pi;
                     }
                     return j+1;
 }
@@ -557,6 +598,7 @@ void Rotor::setParameter(char *parametername, float value)
         p(vortex_state_e3,1)
         p(twist,pi/180.)
         p(number_of_segments,1)
+        p(number_of_parts,1)
         p(rel_len_where_incidence_is_measured,1)
         p(chord,1)
         p(taper,1)
@@ -570,8 +612,11 @@ void Rotor::setParameter(char *parametername, float value)
         p(airfoil_lift_coefficient,1)
         p(airfoil_drag_coefficient0,1)
         p(airfoil_drag_coefficient1,1)
-        cout << "internal error in parameter set up for rotor: '"
-            << parametername <<"'" << endl;
+        p(cyclic_factor,1)
+        p(rotor_correction_factor,1)
+        SG_LOG(SG_INPUT, SG_ALERT,
+            "internal error in parameter set up for rotor: '" << 
+            parametername <<"'" << endl);
 #undef p
 }
 
@@ -598,23 +643,15 @@ void Rotor::setCollective(float lval)
 
 void Rotor::setCyclicele(float lval,float rval)
 {
-    rval = Math::clamp(rval, -1, 1);
     lval = Math::clamp(lval, -1, 1);
-    float col=_mincyclicele+(lval+1)/2*(_maxcyclicele-_mincyclicele);
-    if (_rotorparts.size()!=4) return;
-    ((Rotorpart*)_rotorparts.get(1))->setCyclic(lval);
-    ((Rotorpart*)_rotorparts.get(3))->setCyclic(-lval);
+    _cyclicele=_mincyclicele+(lval+1)/2*(_maxcyclicele-_mincyclicele);
 }
 
 void Rotor::setCyclicail(float lval,float rval)
 {
     lval = Math::clamp(lval, -1, 1);
-    rval = Math::clamp(rval, -1, 1);
-    float col=_mincyclicail+(lval+1)/2*(_maxcyclicail-_mincyclicail);
-    if (_rotorparts.size()!=4) return;
     if (_ccw) lval *=-1;
-    ((Rotorpart*)_rotorparts.get(0))->setCyclic(-lval);
-    ((Rotorpart*)_rotorparts.get(2))->setCyclic( lval);
+    _cyclicail=-(_mincyclicail+(lval+1)/2*(_maxcyclicail-_mincyclicail));
 }
 
 void Rotor::getPosition(float* out)
@@ -634,16 +671,8 @@ void Rotor::calcLiftFactor(float* v, float rho, State *s)
     _f_tl=1;
     _f_vs=1;
 
-    // find h, the distance to the ground 
-    // The ground plane transformed to the local frame.
-    float ground[4];
-    s->planeGlobalToLocal(_global_ground, ground);
-
-    float h = ground[3] - Math::dot3(_base, ground);
-    // Now h is the distance from the rotor center to ground
-
     // Calculate ground effect
-    _f_ge=1+_diameter/h*_ground_effect_constant;
+    _f_ge=1+_diameter/_ground_effect_altitude*_ground_effect_constant;
 
     // Now calculate translational lift
     float v_vert = Math::dot3(v,_normal);
@@ -656,9 +685,104 @@ void Rotor::calcLiftFactor(float* v, float rho, State *s)
     _lift_factor = _f_ge*_f_tl*_f_vs;
 }
 
-float Rotor::getGroundEffect(float* posOut)
-{
-    return _diameter*0; //ground effect for rotor is calcualted not here
+void Rotor::findGroundEffectAltitude(Ground * ground_cb,State *s)
+{
+    _ground_effect_altitude=findGroundEffectAltitude(ground_cb,s,
+        _groundeffectpos[0],_groundeffectpos[1],
+        _groundeffectpos[2],_groundeffectpos[3]);
+}
+
+float Rotor::findGroundEffectAltitude(Ground * ground_cb,State *s,
+        float *pos0,float *pos1,float *pos2,float *pos3,
+        int iteration,float a0,float a1,float a2,float a3)
+{
+    float a[5];
+    float *p[5],pos4[3];
+    a[0]=a0;
+    a[1]=a1;
+    a[2]=a2;
+    a[3]=a3;
+    a[4]=-1;
+    p[0]=pos0;
+    p[1]=pos1;
+    p[2]=pos2;
+    p[3]=pos3;
+    p[4]=pos4;
+    Math::add3(p[0],p[2],p[4]);
+    Math::mul3(0.5,p[4],p[4]);//the center
+    
+    float mina=100*_diameter;
+    float suma=0;
+    for (int i=0;i<5;i++)
+    {
+        if (a[i]==-1)//in the first iteration,(iteration==0) no height is
+                     //passed to this function, these missing values are 
+                     //marked by ==-1
+        {
+            double pt[3];
+            s->posLocalToGlobal(p[i], pt);
+
+            // Ask for the ground plane in the global coordinate system
+            double global_ground[4];
+            float global_vel[3];
+            ground_cb->getGroundPlane(pt, global_ground, global_vel);
+            // find h, the distance to the ground 
+            // The ground plane transformed to the local frame.
+            float ground[4];
+            s->planeGlobalToLocal(global_ground, ground);
+
+            a[i] = ground[3] - Math::dot3(p[i], ground);
+            // Now a[i] is the distance from p[i] to ground
+        }
+        suma+=a[i];
+        if (a[i]<mina)
+            mina=a[i];
+    }
+    if (mina>=10*_diameter)
+        return mina; //the ground effect will be zero
+    
+    //check if further recursion is neccessary
+    //if the height does not differ more than 20%, than 
+    //we can return then mean height, if not split
+    //zhe square to four parts and calcualte the height
+    //for each part
+    //suma * 0.2 is the mean 
+    //0.15 is the maximum allowed difference from the mean
+    //to the height at the center
+    if ((iteration>2)
+       ||(Math::abs(suma*0.2-a[4])<(0.15*0.2*suma*(1<<iteration))))
+        return suma*0.2;
+    suma=0;
+    float pc[4][3],ac[4]; //pc[i]=center of pos[i] and pos[(i+1)&3] 
+    for (int i=0;i<4;i++)
+    {
+        Math::add3(p[i],p[(i+1)&3],pc[i]);
+        Math::mul3(0.5,pc[i],pc[i]);
+        double pt[3];
+        s->posLocalToGlobal(pc[i], pt);
+
+        // Ask for the ground plane in the global coordinate system
+        double global_ground[4];
+        float global_vel[3];
+        ground_cb->getGroundPlane(pt, global_ground, global_vel);
+        // find h, the distance to the ground 
+        // The ground plane transformed to the local frame.
+        float ground[4];
+        s->planeGlobalToLocal(global_ground, ground);
+
+        ac[i] = ground[3] - Math::dot3(p[i], ground);
+        // Now ac[i] is the distance from pc[i] to ground
+    }
+    return 0.25*
+        (findGroundEffectAltitude(ground_cb,s,p[0],pc[1],p[4],pc[3],
+            iteration+1,a[0],ac[0],a[4],ac[3])
+        +findGroundEffectAltitude(ground_cb,s,p[1],pc[0],p[4],pc[1],
+            iteration+1,a[1],ac[0],a[4],ac[1])
+        +findGroundEffectAltitude(ground_cb,s,p[2],pc[1],p[4],pc[2],
+            iteration+1,a[2],ac[1],a[4],ac[2])
+        +findGroundEffectAltitude(ground_cb,s,p[3],pc[2],p[4],pc[3],
+            iteration+1,a[3],ac[2],a[4],ac[3])
+        );
 }
 
 void Rotor::getDownWash(float *pos, float *v_heli, float *downwash)
@@ -743,12 +867,12 @@ void Rotor::compile()
     // Have we already been compiled?
     if(_rotorparts.size() != 0) return;
 
-    //rotor is divided into 4 pointlike parts
+    //rotor is divided into _number_of_parts parts
+    //each part is calcualted at _number_of_segments points
 
-    SG_LOG(SG_FLIGHT, SG_DEBUG, "debug: e "
-        << _mincyclicele << "..." <<_maxcyclicele << ' '
-        << _mincyclicail << "..." << _maxcyclicail << ' '
-        << _min_pitch << "..." << _max_pitch);
+    //clamp to 4..256
+    //and make it a factor of 4
+    _number_of_parts=(int(Math::clamp(_number_of_parts,4,256))>>2)<<2;
 
     _dynamic=_dynamic*(1/                          //inverse of the time
         ( (60/_rotor_rpm)/4         //for rotating 90 deg
@@ -761,7 +885,6 @@ void Rotor::compile()
     directions[0][1]=_forward[1];
     directions[0][2]=_forward[2];
     int i;
-    SG_LOG(SG_FLIGHT, SG_DEBUG, "Rotor rotating ccw? " << _ccw);
     for (i=1;i<5;i++)
     {
         if (!_ccw)
@@ -771,17 +894,23 @@ void Rotor::compile()
         Math::unit3(directions[i],directions[i]);
     }
     Math::set3(directions[4],directions[0]);
-    float rotorpartmass = _weight_per_blade*_number_of_blades/4*.453;
+    for (i=0;i<4;i++)
+    {
+        Math::mul3(_diameter*0.7,directions[i],_groundeffectpos[i]);
+        Math::add3(_base,_groundeffectpos[i],_groundeffectpos[i]);
+    }
+    float rotorpartmass = _weight_per_blade*_number_of_blades/_number_of_parts*.453;
     //was pounds -> now kg
 
-    _torque_of_inertia = 1/12. * ( 4 * rotorpartmass) * _diameter 
+    _torque_of_inertia = 1/12. * ( _number_of_parts * rotorpartmass) * _diameter 
         * _diameter * _rel_blade_center * _rel_blade_center /(0.5*0.5);
     float speed=_rotor_rpm/60*_diameter*_rel_blade_center*pi;
     float lentocenter=_diameter*_rel_blade_center*0.5;
     float lentoforceattac=_diameter*_rel_len_hinge*0.5;
     float zentforce=rotorpartmass*speed*speed/lentocenter;
-    float pitchaforce=_force_at_pitch_a/4*.453*9.81;
-    //was pounds of force, now N, devided by 4 (so its now per rotorpart)
+    float pitchaforce=_force_at_pitch_a/_number_of_parts*.453*9.81;
+    // was pounds of force, now N, devided by _number_of_parts
+    //(so its now per rotorpart)
 
     float torque0=0,torquemax=0,torqueb=0;
     float omega=_rotor_rpm/60*2*pi;
@@ -790,14 +919,14 @@ void Rotor::compile()
     _delta*=pitchaforce/(_pitch_a*omega*lentocenter*2*rotorpartmass);
 
     float phi=Math::atan2(2*omega*_delta,omega0*omega0-omega*omega);
-    float relamp=omega*omega/(2*_delta*Math::sqrt(sqr(omega0*omega0-omega*omega)
-        +4*_delta*_delta*omega*omega));
+    float relamp=(omega*omega/(2*_delta*Math::sqrt(sqr(omega0*omega0-omega*omega)
+        +4*_delta*_delta*omega*omega)))*_cyclic_factor;
     if (!_no_torque)
     {
-        torque0=_power_at_pitch_0/4*1000/omega;  
+        torque0=_power_at_pitch_0/_number_of_parts*1000/omega;  
         // f*r=p/w ; p=f*s/t;  r=s/t/w ; r*w*t = s
-        torqueb=_power_at_pitch_b/4*1000/omega;
-        torquemax=_power_at_pitch_b/4*1000/omega/_pitch_b*_max_pitch;
+        torqueb=_power_at_pitch_b/_number_of_parts*1000/omega;
+        torquemax=_power_at_pitch_b/_number_of_parts*1000/omega/_pitch_b*_max_pitch;
 
         if(_ccw)
         {
@@ -807,36 +936,30 @@ void Rotor::compile()
         }
     }
 
-    SG_LOG(SG_FLIGHT, SG_DEBUG,
-        "spd: " << setprecision(8) << speed
-        << " lentoc: " << lentocenter
-        << " dia: " << _diameter
-        << " rbl: " << _rel_blade_center
-        << " hing: " << _rel_len_hinge
-        << " lfa: " << lentoforceattac);
-
-    SG_LOG(SG_FLIGHT, SG_DEBUG,
-        "tq: " << setprecision(8) << torque0 << ".." << torquemax
-        << " d3: " << _delta3);
-    SG_LOG(SG_FLIGHT, SG_DEBUG,
-        "o/o0: " << setprecision(8) << omega/omega0
-        << " phi: " << phi*180/pi
-        << " relamp: " << relamp
-        << " delta: " <<_delta);
-
-    Rotorpart* rps[4];
-    for (i=0;i<4;i++)
+    Rotorpart* rps[256];
+    for (i=0;i<_number_of_parts;i++)
     {
         float lpos[3],lforceattac[3],lspeed[3],dirzentforce[3];
-
-        Math::mul3(lentocenter,directions[i],lpos);
+        float s = Math::sin(2*pi*i/_number_of_parts);
+        float c = Math::cos(2*pi*i/_number_of_parts);
+        float direction[3],nextdirection[3],help[3];
+        Math::mul3(c ,directions[0],help);
+        Math::mul3(s ,directions[1],direction);
+        Math::add3(help,direction,direction);
+
+        Math::mul3(c ,directions[1],help);
+        Math::mul3(s ,directions[2],nextdirection);
+        Math::add3(help,nextdirection,nextdirection);
+
+        Math::mul3(lentocenter,direction,lpos);
         Math::add3(lpos,_base,lpos);
-        Math::mul3(lentoforceattac,directions[i+1],lforceattac);
-        //i+1: +90deg (gyro)!!!
+        Math::mul3(lentoforceattac,nextdirection,lforceattac);
+        //nextdirection: +90deg (gyro)!!!
 
         Math::add3(lforceattac,_base,lforceattac);
-        Math::mul3(speed,directions[i+1],lspeed);
-        Math::mul3(1,directions[i+1],dirzentforce);
+        Math::mul3(speed,nextdirection,lspeed);
+        Math::mul3(1,nextdirection,dirzentforce);
+
 
         float maxcyclic=(i&1)?_maxcyclicele:_maxcyclicail;
         float mincyclic=(i&1)?_mincyclicele:_mincyclicail;
@@ -845,19 +968,24 @@ void Rotor::compile()
             lspeed,dirzentforce,zentforce,pitchaforce, _max_pitch,_min_pitch,
             mincyclic,maxcyclic,_delta3,rotorpartmass,_translift,
             _rel_len_hinge,lentocenter);
-        rp->setAlphaoutput(_alphaoutput[i&1?i:(_ccw?i^2:i)],0);
-        rp->setAlphaoutput(_alphaoutput[4+(i&1?i:(_ccw?i^2:i))],1+(i>1));
+        int k = i*4/_number_of_parts;
+        rp->setAlphaoutput(_alphaoutput[k&1?k:(_ccw?k^2:k)],0);
+        rp->setAlphaoutput(_alphaoutput[4+(k&1?k:(_ccw?k^2:k))],1+(k>1));
         _rotorparts.add(rp);
         rp->setTorque(torquemax,torque0);
         rp->setRelamp(relamp);
-        rp->setDirectionofRotorPart(directions[i]);
-        rp->setTorqueOfInertia(_torque_of_inertia/4.);
+        rp->setDirectionofRotorPart(direction);
+        rp->setTorqueOfInertia(_torque_of_inertia/_number_of_parts);
     }
-    for (i=0;i<4;i++)
+    for (i=0;i<_number_of_parts;i++)
     {
-        rps[i]->setlastnextrp(rps[(i+3)%4],rps[(i+1)%4],rps[(i+2)%4]);
+        rps[i]->setlastnextrp(rps[(i-1+_number_of_parts)%_number_of_parts],
+            rps[(i+1)%_number_of_parts],
+            rps[(i+_number_of_parts/2)%_number_of_parts],
+            rps[(i-_number_of_parts/4+_number_of_parts)%_number_of_parts],
+            rps[(i+_number_of_parts/4)%_number_of_parts]);
     }
-    for (i=0;i<4;i++)
+    for (i=0;i<_number_of_parts;i++)
     {
         rps[i]->setCompiled();
     }
@@ -868,25 +996,27 @@ void Rotor::compile()
     if (_airfoil_lift_coefficient==0)
     {
         //calculate the lift and drag coefficients now
-        _liftcoef=0;
+        _dragcoef0=1;
+        _dragcoef1=1;
+        _liftcoef=1;
+        rps[0]->calculateAlpha(v_wind,rho_null,_pitch_a,0,0,
+            &(torque[0]),&(lift[0])); //max_pitch a
+        _liftcoef = pitchaforce/lift[0];
         _dragcoef0=1;
         _dragcoef1=0;
         rps[0]->calculateAlpha(v_wind,rho_null,0,0,0,&(torque[0]),&(lift[0])); 
         //0 degree, c0
 
-        _liftcoef=0;
         _dragcoef0=0;
         _dragcoef1=1;
         rps[0]->calculateAlpha(v_wind,rho_null,0,0,0,&(torque[1]),&(lift[1]));
         //0 degree, c1
 
-        _liftcoef=0;
         _dragcoef0=1;
         _dragcoef1=0;
         rps[0]->calculateAlpha(v_wind,rho_null,_pitch_b,0,0,&(torque[2]),&(lift[2])); 
         //picth b, c0
 
-        _liftcoef=0;
         _dragcoef0=0;
         _dragcoef1=1;
         rps[0]->calculateAlpha(v_wind,rho_null,_pitch_b,0,0,&(torque[3]),&(lift[3])); 
@@ -903,17 +1033,12 @@ void Rotor::compile()
                 /(torque[1]/torque[0]-torque[3]/torque[2]);
             _dragcoef0=(torqueb-_dragcoef1*torque[3])/torque[2];
         }
-
-        _liftcoef=1;
-        rps[0]->calculateAlpha(v_wind,rho_null,_pitch_a,0,0,
-            &(torque[0]),&(lift[0])); //max_pitch a
-        _liftcoef = pitchaforce/lift[0];
     }
     else
     {
-        _liftcoef=_airfoil_lift_coefficient/4*_number_of_blades;
-        _dragcoef0=_airfoil_drag_coefficient0/4*_number_of_blades;
-        _dragcoef1=_airfoil_drag_coefficient1/4*_number_of_blades;
+        _liftcoef=_airfoil_lift_coefficient/_number_of_parts*_number_of_blades;
+        _dragcoef0=_airfoil_drag_coefficient0/_number_of_parts*_number_of_blades*_c2;
+        _dragcoef1=_airfoil_drag_coefficient1/_number_of_parts*_number_of_blades*_c2;
     }
 
     //Check
@@ -923,28 +1048,145 @@ void Rotor::compile()
         &(torque[1]),&(lift[1])); //pitch b
     rps[0]->calculateAlpha(v_wind,rho_null,0,0,0,
         &(torque[3]),&(lift[3])); //pitch 0
-    SG_LOG(SG_FLIGHT, SG_DEBUG,
+    SG_LOG(SG_GENERAL, SG_DEBUG,
         "Rotor: coefficients for airfoil:" << endl << setprecision(6)
-        << " drag0: " << _dragcoef0*4/_number_of_blades
-        << " drag1: " << _dragcoef1*4/_number_of_blades
-        << " lift: " << _liftcoef*4/_number_of_blades
+        << " drag0: " << _dragcoef0*_number_of_parts/_number_of_blades/_c2
+        << " drag1: " << _dragcoef1*_number_of_parts/_number_of_blades/_c2
+        << " lift: " << _liftcoef*_number_of_parts/_number_of_blades
         << endl
         << "at 10 deg:" << endl
         << "drag: " << (Math::sin(10./180*pi)*_dragcoef1+_dragcoef0)
-            *4/_number_of_blades
-        << "lift: " << Math::sin(10./180*pi)*_liftcoef*4/_number_of_blades
+            *_number_of_parts/_number_of_blades/_c2
+        << " lift: " << Math::sin(10./180*pi)*_liftcoef*_number_of_parts/_number_of_blades
         << endl
-        << "Some results (Pitch [degree], Power [kW], Lift [N]" << endl
-        << 0.0f << "deg " << Math::abs(torque[3]*4*_omegan/1000) << "kW "
-            << lift[3] << endl
-        << _pitch_a*180/pi << "deg " << Math::abs(torque[0]*4*_omegan/1000) 
-            << "kW " << lift[0] << endl
-        << _pitch_b*180/pi << "deg " << Math::abs(torque[1]*4*_omegan/1000) 
-            << "kW " << lift[1] << endl << endl);
-
+        << "Some results (Pitch [degree], Power [kW], Lift [N])" << endl
+        << 0.0f << "deg " << Math::abs(torque[3]*_number_of_parts*_omegan/1000) << "kW "
+            << lift[3]*_number_of_parts << endl
+        << _pitch_a*180/pi << "deg " << Math::abs(torque[0]*_number_of_parts*_omegan/1000) 
+            << "kW " << lift[0]*_number_of_parts << endl
+        << _pitch_b*180/pi << "deg " << Math::abs(torque[1]*_number_of_parts*_omegan/1000) 
+            << "kW " << lift[1]*_number_of_parts << endl << endl );
+
+    //first calculation of relamp is wrong
+    //it used pitchaforce, but this was unknown and
+    //on the default value
+    _delta*=lift[0]/pitchaforce;
+    relamp=(omega*omega/(2*_delta*Math::sqrt(sqr(omega0*omega0-omega*omega)
+        +4*_delta*_delta*omega*omega)))*_cyclic_factor;
+    for (i=0;i<_number_of_parts;i++)
+    {
+        rps[i]->setRelamp(relamp);
+    }
     rps[0]->setOmega(0);
+    writeInfo();
+}
+std::ostream &  operator<<(std::ostream & out, /*const*/ Rotor& r)
+{
+#define i(x) << #x << ":" << r.x << endl
+#define iv(x) << #x << ":" << r.x[0] << ";" << r.x[1] << ";" <<r.x[2] << ";" << endl
+    out << "Writing Info on Rotor " 
+    i(_name)
+    i(_torque)
+    i(_omega) i(_omegan) i(_omegarel) i(_ddt_omega) i(_omegarelneu)
+    i (_chord)
+    i( _taper)
+    i( _airfoil_incidence_no_lift)
+    i( _collective)
+    i( _airfoil_lift_coefficient)
+    i( _airfoil_drag_coefficient0)
+    i( _airfoil_drag_coefficient1)
+    i( _ccw)
+    i( _number_of_segments)
+    i( _number_of_parts)
+    iv( _base)
+    iv( _groundeffectpos[0])iv( _groundeffectpos[1])iv( _groundeffectpos[2])iv( _groundeffectpos[3])
+    i( _ground_effect_altitude)
+    iv( _normal)
+    iv( _normal_with_yaw_roll)
+    iv( _forward)
+    i( _diameter)
+    i( _number_of_blades)
+    i( _weight_per_blade)
+    i( _rel_blade_center)
+    i( _min_pitch)
+    i( _max_pitch)
+    i( _force_at_pitch_a)
+    i( _pitch_a)
+    i( _power_at_pitch_0)
+    i( _power_at_pitch_b)
+    i( _no_torque)
+    i( _sim_blades)
+    i( _pitch_b)
+    i( _rotor_rpm)
+    i( _rel_len_hinge)
+    i( _maxcyclicail)
+    i( _maxcyclicele)
+    i( _mincyclicail)
+    i( _mincyclicele)
+    i( _delta3)
+    i( _delta)
+    i( _dynamic)
+    i( _translift)
+    i( _c2)
+    i( _stepspersecond)
+    i( _engineon)
+    i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
+    i( _teeterdamp) i(_maxteeterdamp)
+    i( _rellenteeterhinge)
+    i( _translift_ve)
+    i( _translift_maxfactor)
+    i( _ground_effect_constant)
+    i( _vortex_state_lift_factor)
+    i( _vortex_state_c1)
+    i( _vortex_state_c2)
+    i( _vortex_state_c3)
+    i( _vortex_state_e1)
+    i( _vortex_state_e2)
+    i( _vortex_state_e3)
+    i( _lift_factor) i(_f_ge) i(_f_vs) i(_f_tl)
+    i( _vortex_state)
+    i( _liftcoef)
+    i( _dragcoef0)
+    i( _dragcoef1)
+    i( _twist) //outer incidence = inner inner incidence + _twist
+    i( _rel_len_where_incidence_is_measured)
+    i( _torque_of_inertia)
+    i( _rel_len_blade_start)
+    i( _incidence_stall_zero_speed)
+    i( _incidence_stall_half_sonic_speed)
+    i( _lift_factor_stall)
+    i( _stall_change_over)
+    i( _drag_factor_stall)
+    i( _stall_sum)
+    i( _stall_v2sum)
+    i( _yaw)
+    i( _roll)
+    i( _cyclicail)
+    i( _cyclicele)
+    i( _cyclic_factor) <<endl;
+    int j;
+    for(j=0; j<r._rotorparts.size(); j++) {
+        out << *((Rotorpart*)r._rotorparts.get(j));
+    }
+    out <<endl << endl;
+#undef i
+#undef iv
+    return out;
+}
+void Rotor:: writeInfo()
+{
+#ifdef TEST_DEBUG
+    std::ostringstream buffer;
+    buffer << *this;
+    FILE*f=fopen("c:\\fgmsvc\\bat\\log.txt","at");
+    if (!f) f=fopen("c:\\fgmsvc\\bat\\log.txt","wt");
+    if (f)
+    {
+        fprintf(f,"%s",(const char *)buffer.str().c_str());
+        fclose (f);
+    }
+#endif
 }
-
 Rotorpart* Rotor::newRotorpart(float* pos, float *posforceattac, float *normal,
     float* speed,float *dirzentforce, float zentforce,float maxpitchforce,
     float maxpitch, float minpitch, float mincyclic,float maxcyclic,
@@ -980,27 +1222,8 @@ Rotorpart* Rotor::newRotorpart(float* pos, float *posforceattac, float *normal,
     p(number_of_segments)
     p(rel_len_where_incidence_is_measured)
     p(rel_len_blade_start)
+    p(rotor_correction_factor)
 #undef p
-
-    SG_LOG(SG_FLIGHT, SG_DEBUG, setprecision(8)
-        << "newrp: pos("
-        << pos[0] << ' ' << pos[1] << ' ' << pos[2]
-        << ") pfa ("
-        << posforceattac[0] << ' ' << posforceattac[1] << ' ' 
-        << posforceattac[2] << ')');
-    SG_LOG(SG_FLIGHT, SG_DEBUG, setprecision(8)
-        << "       nor("
-        << normal[0] << ' ' << normal[1] << ' ' << normal[2]
-        << ") spd ("
-        << speed[0] << ' ' << speed[1] << ' ' << speed[2] << ')');
-    SG_LOG(SG_FLIGHT, SG_DEBUG, setprecision(8)
-        << "       dzf("
-        << dirzentforce[0] << ' ' << dirzentforce[1] << dirzentforce[2]
-        << ") zf  (" << zentforce << ") mpf (" << maxpitchforce << ')');
-        SG_LOG(SG_FLIGHT, SG_DEBUG, setprecision(8)
-        << "       pit(" << minpitch << ".." << maxpitch
-        << ") mcy (" << mincyclic << ".." << maxcyclic
-        << ") d3 (" << delta3 << ')');
     return r;
 }
 
@@ -1067,13 +1290,14 @@ void Rotorgear::calcForces(float* torqueOut)
             else
                 rel_torque_engine=0;
 
-        //add the rotor brake
+        //add the rotor brake and the gear fritcion
         float dt=0.1f;
         if (r0->_rotorparts.size()) dt=((Rotorpart*)r0->_rotorparts.get(0))->getDt();
 
         float rotor_brake_torque;
-        rotor_brake_torque=_rotorbrake*_max_power_rotor_brake;
+        rotor_brake_torque=_rotorbrake*_max_power_rotor_brake+_rotorgear_friction;
         //clamp it to the value you need to stop the rotor
+        //to avod accelerate the rotor to neagtive rpm:
         rotor_brake_torque=Math::clamp(rotor_brake_torque,0,
             total_torque_of_inertia/dt*omegarel);
         max_torque_of_engine-=rotor_brake_torque;
@@ -1092,7 +1316,7 @@ void Rotorgear::calcForces(float* torqueOut)
                 float lim1=-total_torque/total_torque_of_inertia; 
                 //accel. by autorotation
                 
-                if (lim1<_engine_accell_limit) lim1=_engine_accell_limit; 
+                if (lim1<_engine_accel_limit) lim1=_engine_accel_limit; 
                 //if the accel by autorotation greater than the max. engine
                 //accel, then this is the limit, if not: the engine is the limit
                 if (_ddt_omegarel>lim1) _ddt_omegarel=lim1;
@@ -1125,6 +1349,7 @@ void Rotorgear::calcForces(float* torqueOut)
                 }
             }
         }
+        _total_torque_on_engine=total_torque+_ddt_omegarel*total_torque_of_inertia;
     }
 }
 
@@ -1173,24 +1398,36 @@ void Rotorgear::setParameter(char *parametername, float value)
         p(yasimdragfactor,1)
         p(yasimliftfactor,1)
         p(max_power_rotor_brake,1000)
-        p(engine_accell_limit,0.01)
-        cout << "internal error in parameter set up for rotorgear: '"
-            << parametername <<"'" << endl;
+        p(rotorgear_friction,1000)
+        p(engine_accel_limit,0.01)
+        SG_LOG(SG_INPUT, SG_ALERT,
+            "internal error in parameter set up for rotorgear: '"
+            << parametername <<"'" << endl);
 #undef p
 }
-
+int Rotorgear::getValueforFGSet(int j,char *text,float *f)
+{
+    if (j==0)
+    {
+        sprintf(text,"/rotors/gear/total_torque");
+        *f=_total_torque_on_engine;
+    } else return 0;
+    return j+1;
+}
 Rotorgear::Rotorgear()
 {
     _in_use=0;
     _engineon=0;
     _rotorbrake=0;
     _max_power_rotor_brake=1;
+    _rotorgear_friction=1;
     _max_power_engine=1000*450;
     _engine_prop_factor=0.05f;
     _yasimdragfactor=1;
     _yasimliftfactor=1;
     _ddt_omegarel=0;
-    _engine_accell_limit=0.05f;
+    _engine_accel_limit=0.05f;
+    _total_torque_on_engine=0;
 }
 
 Rotorgear::~Rotorgear()
index df8bdae87744c22d38dd1b015080de6999a58f90..0f7953e8b1bc60c5bcd47257447c7028304a03a4 100644 (file)
@@ -11,9 +11,11 @@ namespace yasim {
 
 class Surface;
 class Rotorpart;
+class Ground;
 const float rho_null=1.184f; //25DegC, 101325Pa
 
 class Rotor {
+    friend std::ostream &  operator<<(std::ostream & out, /*const*/ Rotor& r);
 private:
     float _torque;
     float _omega,_omegan,_omegarel,_ddt_omega,_omegarelneu;
@@ -25,6 +27,9 @@ private:
     float _airfoil_drag_coefficient0;
     float _airfoil_drag_coefficient1;
     int _ccw;
+    int _number_of_blades;
+    int _number_of_segments;
+    int _number_of_parts;
 
 public:
     Rotor();
@@ -78,7 +83,7 @@ public:
     void getTip(float* tip);
     void calcLiftFactor(float* v, float rho, State *s);
     void getDownWash(float *pos, float * v_heli, float *downwash);
-    float getGroundEffect(float* posOut);
+    int getNumberOfBlades(){return _number_of_blades;}
 
     // Query the list of Rotorpart objects
     int numRotorparts();
@@ -102,24 +107,36 @@ public:
     float getOmegan() {return _omegan;}
     float getTaper() { return _taper;}
     float getChord() { return _chord;}
+    int getNumberOfParts() { return _number_of_parts;}
     float getOverallStall() 
         {if (_stall_v2sum !=0 ) return _stall_sum/_stall_v2sum; else return 0;}
+    float getAirfoilIncidenceNoLift() {return _airfoil_incidence_no_lift;}
+    
+    
     Vector _rotorparts;
+    void findGroundEffectAltitude(Ground * ground_cb,State *s);
+    void writeInfo();
+
 
 private:
     void strncpy(char *dest,const char *src,int maxlen);
     void interp(float* v1, float* v2, float frac, float* out);
     float calcStall(float incidence,float speed);
+    float findGroundEffectAltitude(Ground * ground_cb,State *s,
+        float *pos0,float *pos1,float *pos2,float *pos3,
+        int iteration=0,float a0=-1,float a1=-1,float a2=-1,float a3=-1);
     Rotorpart* newRotorpart(float* pos, float *posforceattac, float *normal,
         float* speed,float *dirzentforce, float zentforce,float maxpitchforce,
         float maxpitch, float minpitch, float mincyclic,float maxcyclic,
         float delta3,float mass,float translift,float rellenhinge,float len);
     float _base[3];
+    float _groundeffectpos[4][3];
+    float _ground_effect_altitude;
+    //some postions, where to calcualte the ground effect
     float _normal[3];//the normal vector (direction of rotormast, pointing up)
     float _normal_with_yaw_roll[3];//the normal vector (perpendicular to rotordisc)
     float _forward[3];
     float _diameter;
-    int _number_of_blades;
     float _weight_per_blade;
     float _rel_blade_center;
     float _min_pitch;
@@ -166,7 +183,6 @@ private:
     float _dragcoef0;
     float _dragcoef1;
     float _twist; //outer incidence = inner inner incidence + _twist
-    int _number_of_segments;
     float _rel_len_where_incidence_is_measured;
     float _torque_of_inertia;
     float _rel_len_blade_start;
@@ -179,7 +195,12 @@ private:
     float _stall_v2sum;
     float _yaw;
     float _roll;
+    float _cyclicail;
+    float _cyclicele;
+    float _cyclic_factor;
+    float _rotor_correction_factor;
 };
+std::ostream &  operator<<(std::ostream & out, /*const*/ Rotor& r);
 
 class Rotorgear {
 private:
@@ -191,8 +212,10 @@ private:
     float _yasimliftfactor;
     float _rotorbrake;
     float _max_power_rotor_brake;
+    float _rotorgear_friction;
     float _ddt_omegarel;
-    float _engine_accell_limit;
+    float _engine_accel_limit;
+    float _total_torque_on_engine;
     Vector _rotors;
 
 public:
@@ -218,6 +241,7 @@ public:
     Vector* getRotors() { return &_rotors;}
     void initRotorIteration(float *lrot,float dt);
     void getDownWash(float *pos, float * v_heli, float *downwash);
+    int getValueforFGSet(int j,char *b,float *f);
 };
 
 }; // namespace yasim
index 708065d68d9a3d7c0b8a380d9e43fa66d4130bab..23c0fb6136aa60df6b4024c9ac17db205f260c98 100644 (file)
@@ -45,6 +45,8 @@ Rotorpart::Rotorpart()
     _lastrp=0;
     _nextrp=0;
     _oppositerp=0;
+    _last90rp=0;
+    _next90rp=0;
     _translift=0;
     _dynamic=100;
     _c2=0;
@@ -62,6 +64,8 @@ Rotorpart::Rotorpart()
     _diameter=10;
     _torque_of_inertia=0;
     _rel_len_blade_start=0;
+    _torque=0;
+    _rotor_correction_factor=0.6;
 }
 
 void Rotorpart::inititeration(float dt,float *rot)
@@ -73,10 +77,10 @@ void Rotorpart::inititeration(float dt,float *rot)
     float a=Math::dot3(rot,_normal);
     if(a>0)
         _alphaalt=_alpha*Math::cos(a)
-        +_nextrp->getrealAlpha()*Math::sin(a);
+        +_next90rp->getrealAlpha()*Math::sin(a);
     else
         _alphaalt=_alpha*Math::cos(a)
-        +_lastrp->getrealAlpha()*Math::sin(-a);
+        +_last90rp->getrealAlpha()*Math::sin(-a);
     //calculate the rotation of the fuselage, determine
     //the part in the same direction as alpha
     //and add it ro _alphaalt
@@ -102,8 +106,10 @@ void Rotorpart::setParameter(char *parametername, float value)
         p(number_of_segments)
         p(rel_len_where_incidence_is_measured)
         p(rel_len_blade_start)
-        cout << "internal error in parameter set up for rotorpart: '"
-            << parametername <<"'" << endl;
+        p(rotor_correction_factor)
+        SG_LOG(SG_INPUT, SG_ALERT,
+            "internal error in parameter set up for rotorpart: '"
+            << parametername <<"'" << endl);
 #undef p
 }
 
@@ -281,14 +287,14 @@ float Rotorpart::getAlpha(int i)
     i=i&1;
 
     if (i==0)
-        return _alpha*180/3.14;//in Grad = 1
+        return _alpha*180/pi;//in Grad = 1
     else
     {
         if (_alpha2type==1) //yaw or roll
             return (getAlpha(0)-_oppositerp->getAlpha(0))/2;
         else //collective
             return (getAlpha(0)+_oppositerp->getAlpha(0)+
-            _nextrp->getAlpha(0)+_lastrp->getAlpha(0))/4;
+            _next90rp->getAlpha(0)+_last90rp->getAlpha(0))/4;
     }
 }
 float Rotorpart::getrealAlpha(void)
@@ -298,11 +304,7 @@ float Rotorpart::getrealAlpha(void)
 
 void Rotorpart::setAlphaoutput(char *text,int i)
 {
-    SG_LOG(SG_FLIGHT, SG_DEBUG, "setAlphaoutput rotorpart ["
-        << text << "] typ" << i);
-
     strncpy(_alphaoutputbuf[i>0],text,255);
-
     if (i>0) _alpha2type=i;
 }
 
@@ -339,11 +341,13 @@ void Rotorpart::setCyclic(float pos)
 }
 
 void Rotorpart::setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
-    Rotorpart *oppositerp)
+    Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp)
 {
     _lastrp=lastrp;
     _nextrp=nextrp;
     _oppositerp=oppositerp;
+    _last90rp=last90rp;
+    _next90rp=next90rp;
 }
 
 void Rotorpart::strncpy(char *dest,const char *src,int maxlen)
@@ -373,7 +377,10 @@ float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
     if((_nextrp==NULL)||(_lastrp==NULL)||(_rotor==NULL)) 
         return 0.0;//not initialized. Can happen during startupt of flightgear
     if (returnlift!=NULL) *returnlift=0;
-    float flap_omega=(_nextrp->getrealAlpha()-_lastrp->getrealAlpha())
+    /*float flap_omega=(_nextrp->getrealAlpha()-_lastrp->getrealAlpha())
+        *_omega / pi*_rotor->getNumberOfParts()/4; hier mal die alte version probieren?
+        */
+    float flap_omega=(_next90rp->getrealAlpha()-_last90rp->getrealAlpha())
         *_omega / pi;
     float local_width=_diameter*(1-_rel_len_blade_start)/2.
         /(float (_number_of_segments));
@@ -382,8 +389,8 @@ float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
         float rel = (n+.5)/(float (_number_of_segments));
         float r= _diameter *0.5 *(rel*(1-_rel_len_blade_start)
             +_rel_len_blade_start);
-        float local_incidence=incidence+_twist *rel - _twist
-            *_rel_len_where_incidence_is_measured;
+        float local_incidence=incidence+_twist *rel -
+            _twist *_rel_len_where_incidence_is_measured;
         float local_chord = _rotor->getChord()*rel+_rotor->getChord()
             *_rotor->getTaper()*(1-rel);
         float A = local_chord * local_width;
@@ -401,19 +408,30 @@ float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
 
         //substract now the component of the air speed parallel to 
         //the blade;
-       Math::mul3(Math::dot3(v_local,_directionofrotorpart),
+        Math::mul3(Math::dot3(v_local,_directionofrotorpart),
            _directionofrotorpart,v_help);
         Math::sub3(v_local,v_help,v_local);
 
         //split into direction and magnitude
         v_local_scalar=Math::mag3(v_local);
         if (v_local_scalar!=0)
-            Math::unit3(v_local,v_local);
+            //Math::unit3(v_local,v_help);
+            Math::mul3(1/v_local_scalar,v_local,v_help);
         float incidence_of_airspeed = Math::asin(Math::clamp(
-            Math::dot3(v_local,_normal),-1,1)) + local_incidence;
+            Math::dot3(v_help,_normal),-1,1)) + local_incidence;
+        ias = incidence_of_airspeed;
+
+        //reduce the ias (Prantl factor)
+        float prantl_factor=2/pi*Math::acos(Math::exp(
+            -_rotor->getNumberOfBlades()/2.*(1-rel)
+             *Math::sqrt(1+1/Math::sqr(Math::tan(
+               pi/2-Math::abs(incidence_of_airspeed-local_incidence))))));
+        incidence_of_airspeed = (incidence_of_airspeed+
+            _rotor->getAirfoilIncidenceNoLift())*prantl_factor
+            *_rotor_correction_factor-_rotor->getAirfoilIncidenceNoLift();
         ias = incidence_of_airspeed;
-        float lift_wo_cyc = 
-            _rotor->getLiftCoef(incidence_of_airspeed-cyc,v_local_scalar)
+        float lift_wo_cyc = _rotor->getLiftCoef(incidence_of_airspeed
+            -cyc*_rotor_correction_factor,v_local_scalar)
             * v_local_scalar * v_local_scalar * A *rho *0.5;
         float lift_with_cyc = 
             _rotor->getLiftCoef(incidence_of_airspeed,v_local_scalar)
@@ -427,15 +445,28 @@ float Rotorpart::calculateAlpha(float* v_rel_air, float rho,
         //angle between blade movement caused by rotor-rotation and the
         //total movement of the blade
 
+        /* the next shold look like this, but this is the inner loop of
+           the rotor simulation. For small angles (and we hav only small
+           angles) the first order approximation works well
         lift_moment += r*(lift * Math::cos(angle) 
             - drag * Math::sin(angle));
         *torque     += r*(drag * Math::cos(angle) 
             + lift * Math::sin(angle));
-
+            */
+        lift_moment += r*(lift * (1-angle*angle) 
+            - drag * angle);
+        *torque     += r*(drag * (1-angle*angle) 
+            + lift * angle);
+        
         if (returnlift!=NULL) *returnlift+=lift;
     }
-    float alpha=Math::atan2(lift_moment,_zentipetalforce * _len); 
-
+    //as above, use 1st order approximation
+    //float alpha=Math::atan2(lift_moment,_zentipetalforce * _len); 
+    float alpha;
+    if ((_zentipetalforce >1e-8) || (_zentipetalforce <-1e-8))
+        alpha=lift_moment/(_zentipetalforce * _len); 
+    else 
+        alpha=0;
     return (alpha);
 }
 
@@ -461,12 +492,13 @@ void Rotorpart::calcForce(float* v, float rho,  float* out, float* torque,
     //Angle of blade which would produce no vertical force (where the 
     //effective incidence is zero)
 
-    float cyc=_mincyclic+(_cyclic+1)/2*(_maxcyclic-_mincyclic);
+    //float cyc=_mincyclic+(_cyclic+1)/2*(_maxcyclic-_mincyclic);
+    float cyc=_cyclic;
     float col=_minpitch+(_collective+1)/2*(_maxpitch-_minpitch);
     _incidence=(col+cyc)-_delta3*_alphaalt;
     //the incidence of the rotorblade due to control input reduced by the
     //delta3 effect, see README.YASIM
-    float beta=_relamp*cyc+col; 
+    //float beta=_relamp*cyc+col; 
     //the incidence of the rotorblade which is used for the calculation
 
     float alpha,factor; //alpha is the flapping angle
@@ -490,7 +522,7 @@ void Rotorpart::calcForce(float* v, float rho,  float* out, float* torque,
             &scalar_torque);
         //calculate drag etc., e. g. for deccelrating the rotor if engine
         //is off and omega <10%
-
+        alpha = Math::clamp(alpha,_alphamin,_alphamax);
         float rel =_omega*10 / _omegan;
         alpha=rel * alpha + (1-rel)* _alpha0;
         factor=_dt*_dynamic/10;
@@ -505,11 +537,11 @@ void Rotorpart::calcForce(float* v, float rho,  float* out, float* torque,
 
     alpha=_alphaalt+(alpha-_alphaalt)*factor;
     _alpha=alpha;
-    float meancosalpha=(1*Math::cos(_lastrp->getrealAlpha())
-        +1*Math::cos(_nextrp->getrealAlpha())
+    float meancosalpha=(1*Math::cos(_last90rp->getrealAlpha())
+        +1*Math::cos(_next90rp->getrealAlpha())
         +1*Math::cos(_oppositerp->getrealAlpha())
         +1*Math::cos(alpha))/4;
-    float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha);
+    float schwenkfactor=1-(Math::cos(_lastrp->getrealAlpha())-meancosalpha)*_rotor->getNumberOfParts()/4;
 
     //missing: consideration of rellenhinge
     float xforce = Math::cos(alpha)*_zentipetalforce;
@@ -531,8 +563,62 @@ void Rotorpart::getAccelTorque(float relaccel,float *t)
     int i;
     float f=_rotor->getCcw()?1:-1;
     for(i=0; i<3; i++) {
-        t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;
+        t[i]=f*-1* _normal[i]*relaccel*_omegan* _torque_of_inertia;// *_omeagan ?
         _rotor->addTorque(-relaccel*_omegan* _torque_of_inertia);
     }
 }
+std::ostream &  operator<<(std::ostream & out, const Rotorpart& rp)
+{
+#define i(x) << #x << ":" << rp.x << endl
+#define iv(x) << #x << ":" << rp.x[0] << ";" << rp.x[1] << ";" <<rp.x[2] << ";" << endl
+    out << "Writing Info on Rotorpart " << endl
+        i( _dt)
+        iv( _last_torque)
+        i( _compiled)
+        iv( _pos)    // position in local coords
+        iv( _posforceattac)    // position in local coords
+        iv( _normal) //direcetion of the rotation axis
+        i( _torque_max_force)
+        i( _torque_no_force)
+        iv( _speed)
+        iv( _direction_of_movement)
+        iv( _directionofzentipetalforce)
+        iv( _directionofrotorpart)
+        i( _zentipetalforce)
+        i( _maxpitch)
+        i( _minpitch)
+        i( _maxcyclic)
+        i( _mincyclic)
+        i( _cyclic)
+        i( _collective)
+        i( _delta3)
+        i( _dynamic)
+        i( _translift)
+        i( _c2)
+        i( _mass)
+        i( _alpha)
+        i( _alphaalt)
+        i( _alphamin) i(_alphamax) i(_alpha0) i(_alpha0factor)
+        i( _rellenhinge)
+        i( _relamp)
+        i( _omega) i(_omegan) i(_ddt_omega)
+        i( _phi)
+        i( _len)
+        i( _incidence)
+        i( _twist) //outer incidence = inner inner incidence + _twist
+        i( _number_of_segments)
+        i( _rel_len_where_incidence_is_measured)
+        i( _rel_len_blade_start)
+        i( _diameter)
+        i( _torque_of_inertia)
+        i( _torque) 
+        i (_alphaoutputbuf[0])
+        i (_alphaoutputbuf[1])
+        i( _alpha2type)
+        i(_rotor_correction_factor)
+    << endl;
+#undef i
+#undef iv
+    return out;  
+}
 }; // namespace yasim
index 87dee27c5a721de5d05f0b1053d494b2fa13ffb4..59960ef6864796d398b35dee20c59e88b4195ff9 100644 (file)
@@ -1,10 +1,12 @@
 #ifndef _ROTORPART_HPP
 #define _ROTORPART_HPP
-
+#include <sstream>
+#include <iostream>
 namespace yasim {
     class Rotor;
     class Rotorpart
     {
+        friend std::ostream &  operator<<(std::ostream & out, const Rotorpart& rp);
     private:
         float _dt;
         float _last_torque[3];
@@ -54,7 +56,7 @@ namespace yasim {
         float calculateAlpha(float* v, float rho, float incidence, float cyc,
             float alphaalt, float *torque,float *returnlift=0);
         void setlastnextrp(Rotorpart*lastrp,Rotorpart*nextrp,
-            Rotorpart *oppositerp);
+            Rotorpart *oppositerp,Rotorpart*last90rp,Rotorpart*next90rp);
         void setTorque(float torque_max_force,float torque_no_force);
         void setOmega(float value);
         void setOmegaN(float value);
@@ -69,10 +71,11 @@ namespace yasim {
         void setParameter(char *parametername, float value);
         void setRotor(Rotor *rotor);
         void setTorqueOfInertia(float toi);
+        void writeInfo(std::ostringstream &buffer);
 
     private:
         void strncpy(char *dest,const char *src,int maxlen);
-        Rotorpart *_lastrp,*_nextrp,*_oppositerp;
+        Rotorpart *_lastrp,*_nextrp,*_oppositerp,*_last90rp,*_next90rp;
         Rotor *_rotor;
 
         float _pos[3];    // position in local coords
@@ -109,14 +112,14 @@ namespace yasim {
         int _number_of_segments;
         float _rel_len_where_incidence_is_measured;
         float _rel_len_blade_start;
-        float _rel_len_blade_measured;
         float _diameter;
         float _torque_of_inertia;
         float _torque; 
         // total torque of rotor (scalar) for calculating new rotor rpm
         char _alphaoutputbuf[2][256];
         int _alpha2type;
+        float _rotor_correction_factor;
     };
-
+    std::ostream &  operator<<(std::ostream & out, const Rotorpart& rp);
 }; // namespace yasim
 #endif // _ROTORPART_HPP