]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/PistonEngine.cpp
Latest YASim changes.
[flightgear.git] / src / FDM / YASim / PistonEngine.cpp
1 #include "Atmosphere.hpp"
2 #include "Math.hpp"
3 #include "PistonEngine.hpp"
4 namespace yasim {
5
6 const static float HP2W = 745.7;
7 const static float CIN2CM = 1.6387064e-5;
8
9 PistonEngine::PistonEngine(float power, float speed)
10 {
11     _boost = 1;
12
13     // Presume a BSFC (in lb/hour per HP) of 0.45.  In SI that becomes
14     // (2.2 lb/kg, 745.7 W/hp, 3600 sec/hour) 7.62e-08 kg/Ws.
15     _f0 = power * 7.62e-08;
16
17     _power0 = power;
18     _omega0 = speed;
19
20     // We must be at sea level under standard conditions
21     _rho0 = Atmosphere::getStdDensity(0);
22
23     // Further presume that takeoff is (duh) full throttle and
24     // peak-power, that means that by our efficiency function, we are
25     // at 11/8 of "ideal" fuel flow.
26     float realFlow = _f0 * (11.0/8.0);
27     _mixCoeff = realFlow * 1.1 / _omega0;
28
29     _turbo = 1;
30     _maxMP = 1e6; // No waste gate on non-turbo engines.
31
32     // Guess at reasonable values for these guys.  Displacements run
33     // at about 2 cubic inches per horsepower or so, at least for
34     // non-turbocharged engines.
35     _compression = 8;
36     _displacement = power * (2*CIN2CM/HP2W);
37 }
38
39 void PistonEngine::setTurboParams(float turbo, float maxMP)
40 {
41     _turbo = turbo;
42     _maxMP = maxMP;
43
44     // This changes the "sea level" manifold air density
45     float P0 = Atmosphere::getStdPressure(0);
46     float P = P0 * (1 + _boost * (_turbo - 1));
47     if(P > _maxMP) P = _maxMP;
48     float T = Atmosphere::getStdTemperature(0) * Math::pow(P/P0, 2./7.);
49     _rho0 = P / (287.1 * T);
50 }
51
52 void PistonEngine::setDisplacement(float d)
53 {
54     _displacement = d;
55 }
56
57 void PistonEngine::setCompression(float c)
58 {
59     _compression = c;
60 }
61
62 float PistonEngine::getMaxPower()
63 {
64     return _power0;
65 }
66
67 void PistonEngine::setThrottle(float t)
68 {
69     _throttle = t;
70 }
71
72 void PistonEngine::setMixture(float m)
73 {
74     _mixture = m;
75 }
76
77 void PistonEngine::setBoost(float boost)
78 {
79     _boost = boost;
80 }
81
82 float PistonEngine::getTorque()
83 {
84     return _torque;
85 }
86
87 float PistonEngine::getFuelFlow()
88 {
89     return _fuelFlow;
90 }
91
92 float PistonEngine::getMP()
93 {
94     return _mp;
95 }
96
97 float PistonEngine::getEGT()
98 {
99     return _egt;
100 }
101
102 void PistonEngine::calc(float pressure, float temp, float speed)
103 {
104     // Calculate manifold pressure as ambient pressure modified for
105     // turbocharging and reduced by the throttle setting.  According
106     // to Dave Luff, minimum throttle at sea level corresponds to 6"
107     // manifold pressure.  Assume that this means that minimum MP is
108     // always 20% of ambient pressure.
109     _mp = pressure * (1 + _boost*(_turbo-1)); // turbocharger
110     _mp *= (0.2 + 0.8 * _throttle);            // throttle
111     if(_mp > _maxMP) _mp = _maxMP;             // wastegate
112
113     // Air entering the manifold does so rapidly, and thus the
114     // pressure change can be assumed to be adiabatic.  Calculate a
115     // temperature change, and use that to get the density.
116     float T = temp * Math::pow(_mp/pressure, 2.0/7.0);
117     float rho = _mp / (287.1 * T);
118
119     // The actual fuel flow is determined only by engine RPM and the
120     // mixture setting.  Not all of this will burn with the same
121     // efficiency.
122     _fuelFlow = _mixture * speed * _mixCoeff;
123
124     // How much fuel could be burned with ideal (i.e. uncorrected!)
125     // combustion.
126     float burnable = _f0 * (rho/_rho0) * (speed/_omega0);
127
128     // Calculate the fuel that actually burns to produce work.  The
129     // idea is that less than 5/8 of ideal, we get complete
130     // combustion.  We use up all the oxygen at 1 3/8 of ideal (that
131     // is, you need to waste fuel to use all your O2).  In between,
132     // interpolate.  This vaguely matches a curve I copied out of a
133     // book for a single engine.  Shrug.
134     float burned;
135     float r = _fuelFlow/burnable;
136     if     (burnable == 0) burned = 0;
137     else if(r < .625)      burned = _fuelFlow;
138     else if(r > 1.375)     burned = burnable;
139     else
140         burned = _fuelFlow + (burnable-_fuelFlow)*(r-.625)*(4.0/3.0);
141
142     // And finally the power is just the reference power scaled by the
143     // amount of fuel burned, and torque is that divided by RPM.
144     float power = _power0 * burned/_f0;
145     _torque = power/speed;
146
147     // Now EGT.  This one gets a little goofy.  We can calculate the
148     // work done by an isentropically expanding exhaust gas as the
149     // mass of the gas times the specific heat times the change in
150     // temperature.  The mass is just the engine displacement times
151     // the manifold density, plus the mass of the fuel, which we know.
152     // The change in temperature can be calculated adiabatically as a
153     // function of the exhaust gas temperature and the compression
154     // ratio (which we know).  So just rearrange the equation to get
155     // EGT as a function of engine power.  Cool.  I'm using a value of
156     // 1300 J/(kg*K) for the exhaust gas specific heat.  I found this
157     // on a web page somewhere; no idea if it's accurate.  Also,
158     // remember that four stroke engines do one combustion cycle every
159     // TWO revolutions, so the displacement per revolution is half of
160     // what we'd expect.  And diddle the work done by the gas a bit to
161     // account for non-thermodynamic losses like internal friction;
162     // 10% should do it.
163
164     float massFlow = _fuelFlow + (rho * 0.5 * _displacement * speed);
165     float specHeat = 1300;
166     float corr = 1.0/(Math::pow(_compression, 0.4) - 1);
167     _egt = corr * (power * 1.1) / (massFlow * specHeat);
168 }
169
170 }; // namespace yasim