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