]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/PropEngine.cpp
Fix drag when engine is shut down, by avoiding negative RPM.
[flightgear.git] / src / FDM / YASim / PropEngine.cpp
1 #include "Math.hpp"
2 #include "Propeller.hpp"
3 #include "PistonEngine.hpp"
4 #include "PropEngine.hpp"
5 namespace yasim {
6
7 PropEngine::PropEngine(Propeller* prop, PistonEngine* eng, float moment)
8 {
9     // Start off at 500rpm, because the start code doesn't exist yet
10     _omega = 52.3f;
11     _dir[0] = 1; _dir[1] = 0; _dir[2] = 0;
12
13     _variable = false;
14
15     _prop = prop;
16     _eng = eng;
17     _moment = moment;
18     _fuel = true;
19 }
20
21 PropEngine::~PropEngine()
22 {
23     delete _prop;
24     delete _eng;
25 }
26
27 void PropEngine::setMagnetos(int pos)
28 {
29     _magnetos = pos;
30 }
31
32 void PropEngine::setAdvance(float advance)
33 {
34     _advance = Math::clamp(advance, 0, 1);
35 }
36
37 void PropEngine::setPropPitch(float proppitch)
38 {
39     // update Propeller property
40     _prop->setPropPitch(proppitch);
41 }
42
43 void PropEngine::setVariableProp(float min, float max)
44 {
45     _variable = true;
46     _minOmega = min;
47     _maxOmega = max;
48 }
49
50 bool PropEngine::isRunning()
51 {
52     return _eng->isRunning();
53 }
54
55 bool PropEngine::isCranking()
56 {
57     return _eng->isCranking();
58 }
59
60 float PropEngine::getOmega()
61 {
62     return _omega;
63 }
64
65 void PropEngine::getThrust(float* out)
66 {
67     int i;
68     for(i=0; i<3; i++) out[i] = _thrust[i];    
69 }
70
71 void PropEngine::getTorque(float* out)
72 {
73     int i;
74     for(i=0; i<3; i++) out[i] = _torque[i];
75 }
76
77 void PropEngine::getGyro(float* out)
78 {
79     int i;
80     for(i=0; i<3; i++) out[i] = _gyro[i];
81 }
82
83 float PropEngine::getFuelFlow()
84 {
85     return _fuelFlow;
86 }
87
88 void PropEngine::stabilize()
89 {
90     float speed = -Math::dot3(_wind, _dir);
91     _eng->setThrottle(_throttle);
92     _eng->setMixture(_mixture);
93
94     _eng->setMagnetos(3);
95     _eng->setRunning(true);
96
97     if(_variable) {
98         _omega = _minOmega + _advance * (_maxOmega - _minOmega);
99         _prop->modPitch(1e6); // Start at maximum pitch and move down
100     } else {
101         _omega = 52;
102     }
103
104     bool goingUp = false;
105     float step = 10;
106     while(true) {
107         float ptau, dummy;
108         _prop->calc(_rho, speed, _omega, &dummy, &ptau);
109         _eng->calc(_pressure, _temp, _omega);
110         float etau = _eng->getTorque();
111         float tdiff = etau - ptau;
112
113         if(Math::abs(tdiff/_moment) < 0.1)
114             break;
115
116         if(tdiff > 0) {
117             if(!goingUp) step *= 0.5f;
118             goingUp = true;
119             if(!_variable)  _omega += step;
120             else            _prop->modPitch(1+(step*0.005f));
121         } else {
122             if(goingUp) step *= 0.5f;
123             goingUp = false;
124             if(!_variable)  _omega -= step;
125             else            _prop->modPitch(1-(step*0.005f));
126         }
127     }
128
129     // ...and back off
130     _eng->setRunning(false);
131 }
132
133 void PropEngine::init()
134 {
135     _omega = 0.01f;
136     _eng->setStarter(false);
137     _eng->setMagnetos(0);
138 }
139
140 void PropEngine::integrate(float dt)
141 {
142     float speed = -Math::dot3(_wind, _dir);
143
144     float propTorque, engTorque, thrust;
145
146     _eng->setThrottle(_throttle);
147     _eng->setStarter(_starter);
148     _eng->setMagnetos(_magnetos);
149     _eng->setMixture(_mixture);
150     _eng->setFuelState(_fuel);
151     
152     _prop->calc(_rho, speed, _omega, &thrust, &propTorque);
153     _eng->calc(_pressure, _temp, _omega);
154     engTorque = _eng->getTorque();
155     _fuelFlow = _eng->getFuelFlow();
156
157     // Turn the thrust into a vector and save it
158     Math::mul3(thrust, _dir, _thrust);
159
160     // Euler-integrate the RPM.  This doesn't need the full-on
161     // Runge-Kutta stuff.
162     float rotacc = (engTorque-propTorque)/Math::abs(_moment);
163     _omega += dt * rotacc;
164     if (_omega < 0)
165         _omega = 0 - _omega;    // don't allow negative RPM
166                                 // FIXME: introduce proper windmilling
167
168     // Store the total angular momentum into _gyro
169     Math::mul3(_omega*_moment, _dir, _gyro);
170
171     // Accumulate the engine torque, it acts on the body as a whole.
172     // (Note: engine torque, not propeller torque.  They can be
173     // different, but the difference goes to accelerating the
174     // rotation.  It is the engine torque that is felt at the shaft
175     // and works on the body.)
176     float tau = _moment < 0 ? engTorque : -engTorque;
177     Math::mul3(tau, _dir, _torque);
178
179     // Iterate the propeller governor, if we have one.  Since engine
180     // torque is basically constant with RPM, we want to make the
181     // propeller torque at the target RPM equal to the engine by
182     // varying the pitch.  Assume the the torque goes as the square of
183     // the RPM (roughly correct) and compute a "target" torque for the
184     // _current_ RPM.  Seek to that.  This is sort of a continuous
185     // Newton-Raphson, basically.
186     if(_variable) {
187         float targetOmega = _minOmega + _advance*(_maxOmega-_minOmega);
188         float ratio2 = (_omega*_omega)/(targetOmega*targetOmega);
189         float targetTorque = engTorque * ratio2;
190
191         float mod = propTorque < targetTorque ? 1.04f : (1.0f/1.04f);
192
193         // Convert to an acceleration here, so that big propellers
194         // don't seek faster than small ones.
195         float diff = Math::abs((propTorque - targetTorque) / _moment);
196         if(diff < 10) mod = 1 + (mod-1)*(0.1f*diff);
197
198         _prop->modPitch(mod);
199     }
200 }
201
202 }; // namespace yasim