X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=inline;f=src%2FFDM%2FJSBSim%2Fmodels%2Fpropulsion%2FFGPiston.cpp;h=cd24bfbabdf0c16af61ef5348cbc3fbe7a410ab1;hb=4aff7b279db80407d82d0a5556738cf111501457;hp=2297ebaeffa3492ec4aee4296e3f582c185ae353;hpb=3b3f6719746e3877a3aeedbd6b944a55960ae792;p=flightgear.git diff --git a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp index 2297ebaef..cd24bfbab 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp @@ -71,8 +71,9 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number) dt = State->Getdt(); // These items are read from the configuration file + // Defaults are from a Lycoming O-360, more or less - Cycles = 2; + Cycles = 4; IdleRPM = 600; MaxRPM = 2800; Displacement = 360; @@ -80,7 +81,12 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number) MaxHP = 200; MinManifoldPressure_inHg = 6.5; MaxManifoldPressure_inHg = 28.5; - BSFC = 0.45; + ISFC = -1; + volumetric_efficiency = -0.1; + Bore = 5.125; + Stroke = 4.375; + Cylinders = 4; + CompressionRatio = 8.5; // These are internal program variables @@ -113,8 +119,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number) BoostSwitchAltitude[i] = 0.0; BoostSwitchPressure[i] = 0.0; } - // Initialisation - volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running // First column is thi, second is neta (combustion efficiency) Lookup_Combustion_Efficiency = new FGTable(12); @@ -131,21 +135,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number) *Lookup_Combustion_Efficiency << 1.60 << 0.525; *Lookup_Combustion_Efficiency << 2.00 << 0.345; - Power_Mixture_Correlation = new FGTable(13); - *Power_Mixture_Correlation << (14.7/1.6) << 0.780; - *Power_Mixture_Correlation << 10 << 0.860; - *Power_Mixture_Correlation << 11 << 0.935; - *Power_Mixture_Correlation << 12 << 0.980; - *Power_Mixture_Correlation << 13 << 1.000; - *Power_Mixture_Correlation << 14 << 0.990; - *Power_Mixture_Correlation << 15 << 0.964; - *Power_Mixture_Correlation << 16 << 0.925; - *Power_Mixture_Correlation << 17 << 0.880; - *Power_Mixture_Correlation << 18 << 0.830; - *Power_Mixture_Correlation << 19 << 0.785; - *Power_Mixture_Correlation << 20 << 0.740; - *Power_Mixture_Correlation << (14.7/0.6) << 0.58; - Mixture_Efficiency_Correlation = new FGTable(15); *Mixture_Efficiency_Correlation << 0.05000 << 0.00000; *Mixture_Efficiency_Correlation << 0.05137 << 0.00862; @@ -164,21 +153,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number) *Mixture_Efficiency_Correlation << 0.12500 << 0.00000; -/* -Manifold_Pressure_Lookup = new - - 0 0.2 0.4 0.6 0.8 1 -0 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 -1000 0.7778 0.8212 0.8647 0.9081 0.9516 0.9950 -2000 0.5556 0.6424 0.7293 0.8162 0.9031 0.9900 -3000 0.3333 0.4637 0.5940 0.7243 0.8547 0.9850 -4000 0.2000 0.2849 0.4587 0.6324 0.8062 0.9800 -5000 0.2000 0.2000 0.3233 0.5406 0.7578 0.9750 -6000 0.2000 0.2000 0.2000 0.4487 0.7093 0.9700 -7000 0.2000 0.2000 0.2000 0.2000 0.4570 0.7611 -8000 0.2000 0.2000 0.2000 0.2000 0.2047 0.5522 -*/ - // Read inputs from engine data file where present. if (el->FindElement("minmp")) // Should have ELSE statement telling default value used? @@ -202,7 +176,17 @@ Manifold_Pressure_Lookup = new if (el->FindElement("minthrottle")) MinThrottle = el->FindElementValueAsNumber("minthrottle"); if (el->FindElement("bsfc")) - BSFC = el->FindElementValueAsNumber("bsfc"); + ISFC = el->FindElementValueAsNumberConvertTo("bsfc", "LBS/HP*HR"); + if (el->FindElement("volumetric-efficiency")) + volumetric_efficiency = el->FindElementValueAsNumber("volumetric-efficiency"); + if (el->FindElement("compression-ratio")) + CompressionRatio = el->FindElementValueAsNumber("compression-ratio"); + if (el->FindElement("bore")) + Bore = el->FindElementValueAsNumberConvertTo("bore","IN"); + if (el->FindElement("stroke")) + Stroke = el->FindElementValueAsNumberConvertTo("stroke","IN"); + if (el->FindElement("stroke")) + Cylinders = el->FindElementValueAsNumber("cylinders"); if (el->FindElement("numboostspeeds")) { // Turbo- and super-charging parameters BoostSpeeds = (int)el->FindElementValueAsNumber("numboostspeeds"); if (el->FindElement("boostoverride")) @@ -234,15 +218,43 @@ Manifold_Pressure_Lookup = new if (el->FindElement("ratedaltitude3")) RatedAltitude[2] = el->FindElementValueAsNumberConvertTo("ratedaltitude3", "FT"); } - char property_name[80]; - snprintf(property_name, 80, "/engines/engine[%d]/power_hp", engine_number); - PropertyManager->Tie(property_name, &HP); - snprintf(property_name, 80, "/engines/engine[%d]/bsfc", engine_number); - PropertyManager->Tie(property_name, &BSFC); + StarterHP = sqrt(MaxHP) * 0.4; + displacement_SI = Displacement * in3tom3; + + // Create IFSC and VE to match the engine if not provided + int calculated_ve=0; + if (volumetric_efficiency < 0) { + volumetric_efficiency = MaxManifoldPressure_inHg / 29.92; + calculated_ve=1; + } + if (ISFC < 0) { + double pmep = MaxManifoldPressure_inHg > 29.92 ? 0 : 29.92 - MaxManifoldPressure_inHg; + pmep *= inhgtopa; + double fmep = (18400 * (2*(Stroke/12)*(MaxRPM/60)) * fttom + 46500)/2; + double hp_loss = ((pmep + fmep) * displacement_SI * MaxRPM)/(Cycles*22371); + ISFC = ( Displacement * MaxRPM * volumetric_efficiency ) / (9411 * (MaxHP+hp_loss)); +// cout <<"FMEP: "<< fmep <<" PMEP: "<< pmep << " hp_loss: " < 29.9 ) { // Don't allow boosting with a bogus number + MaxManifoldPressure_inHg = 29.9; + if (calculated_ve) volumetric_efficiency = 1.0; + } minMAP = MinManifoldPressure_inHg * inhgtopa; // inHg to Pa maxMAP = MaxManifoldPressure_inHg * inhgtopa; - StarterHP = sqrt(MaxHP) * 0.4; + + string property_name, base_property_name; + base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber); + property_name = base_property_name + "/power-hp"; + PropertyManager->Tie(property_name, &HP); + property_name = base_property_name + "/bsfc-lbs_hphr"; + PropertyManager->Tie(property_name, &ISFC); + property_name = base_property_name + "/volumetric-efficiency"; + PropertyManager->Tie(property_name, &volumetric_efficiency); + property_name = base_property_name + "/map-pa"; + PropertyManager->Tie(property_name, &MAP); + property_name = base_property_name + "/map-inhg"; + PropertyManager->Tie(property_name, &ManifoldPressure_inHg); // Set up and sanity-check the turbo/supercharging configuration based on the input values. if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true; @@ -290,7 +302,6 @@ Manifold_Pressure_Lookup = new BoostSpeed = 0; } bBoostOverride = (BoostOverride == 1 ? true : false); - if (MinThrottle < 0.001) MinThrottle = 0.001; //MinThrottle is a denominator in a power equation so it can't be zero Debug(0); // Call Debug() routine from constructor if needed } @@ -298,14 +309,7 @@ Manifold_Pressure_Lookup = new FGPiston::~FGPiston() { - char property_name[80]; - snprintf(property_name, 80, "/engines/engine[%d]/power_hp", EngineNumber); - PropertyManager->Untie(property_name); - snprintf(property_name, 80, "/engines/engine[%d]/bsfc", EngineNumber); - PropertyManager->Untie(property_name); - delete Lookup_Combustion_Efficiency; - delete Power_Mixture_Correlation; delete Mixture_Efficiency_Correlation; Debug(1); // Call Debug() routine from constructor if needed } @@ -315,9 +319,10 @@ FGPiston::~FGPiston() void FGPiston::ResetToIC(void) { FGEngine::ResetToIC(); - + ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg MAP = Atmosphere->GetPressure() * psftopa; + TMAP = MAP; double airTemperature_degK = RankineToKelvin(Atmosphere->GetTemperature()); OilTemp_degK = airTemperature_degK; CylinderHeadTemp_degK = airTemperature_degK; @@ -325,6 +330,7 @@ void FGPiston::ResetToIC(void) EGT_degC = ExhaustGasTemp_degK - 273; Thruster->SetRPM(0.0); RPM = 0.0; + OilPressure_psi = 0.0; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -334,7 +340,8 @@ double FGPiston::Calculate(void) if (FuelFlow_gph > 0.0) ConsumeFuel(); Throttle = FCS->GetThrottlePos(EngineNumber); - ThrottlePos = MinThrottle+((MaxThrottle-MinThrottle)*Throttle ); + // calculate the throttle plate angle. 1 unit is approx pi/2 radians. + ThrottleAngle = MinThrottle+((MaxThrottle-MinThrottle)*Throttle ); Mixture = FCS->GetMixturePos(EngineNumber); // @@ -342,10 +349,10 @@ double FGPiston::Calculate(void) // p_amb = Atmosphere->GetPressure() * psftopa; - p_amb_sea_level = Atmosphere->GetPressureSL() * psftopa; T_amb = RankineToKelvin(Atmosphere->GetTemperature()); RPM = Thruster->GetRPM() * Thruster->GetGearRatio(); + MeanPistonSpeed_fps = ( RPM * Stroke) / (360); // AKA 2 * (RPM/60) * ( Stroke / 12) or 2NS IAS = Auxiliary->GetVcalibratedKTS(); @@ -363,8 +370,7 @@ double FGPiston::Calculate(void) // Running = false; doEnginePower(); -if(HP<0.1250) - Running = false; + if (IndicatedHorsePower < 0.1250) Running = false; doEGT(); doCHT(); @@ -385,7 +391,9 @@ if(HP<0.1250) double FGPiston::CalcFuelNeed(void) { - return FuelFlow_gph / 3600 * 6 * State->Getdt() * Propulsion->GetRate(); + double dT = State->Getdt() * Propulsion->GetRate(); + FuelExpended = FuelFlowRate * dT; + return FuelExpended; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -502,56 +510,56 @@ void FGPiston::doBoostControl(void) * from the throttle position, turbo/supercharger boost control * system, engine speed and local ambient air density. * - * TODO: changes in MP should not be instantaneous -- introduce - * a lag between throttle changes and MP changes, to allow pressure - * to build up or disperse. + * Inputs: p_amb, Throttle, ThrottleAngle, + * MeanPistonSpeed_fps, dt * - * Inputs: minMAP, maxMAP, p_amb, Throttle - * - * Outputs: MAP, ManifoldPressure_inHg + * Outputs: MAP, ManifoldPressure_inHg, TMAP */ void FGPiston::doMAP(void) { - suction_loss = pow( ThrottlePos*0.98, RPM/MaxRPM ); - MAP = p_amb * suction_loss; - - if(Boosted) { - // If takeoff boost is fitted, we currently assume the following throttle map: - // (In throttle % - actual input is 0 -> 1) - // 99 / 100 - Takeoff boost - // 96 / 97 / 98 - Rated boost - // 0 - 95 - Idle to Rated boost (MinManifoldPressure to MaxManifoldPressure) - // In real life, most planes would be fitted with a mechanical 'gate' between - // the rated boost and takeoff boost positions. - double T = Throttle; // processed throttle value. - bool bTakeoffPos = false; - if(bTakeoffBoost) { - if(Throttle > 0.98) { - //cout << "Takeoff Boost!!!!\n"; - bTakeoffPos = true; - } else if(Throttle <= 0.95) { - bTakeoffPos = false; - T *= 1.0 / 0.95; - } else { - bTakeoffPos = false; - //cout << "Rated Boost!!\n"; - T = 1.0; - } - } - // Boost the manifold pressure. - MAP += MAP * BoostMul[BoostSpeed] * RPM/MaxRPM; - // Now clip the manifold pressure to BCV or Wastegate setting. - if(bTakeoffPos) { - if(MAP > TakeoffMAP[BoostSpeed]) { - MAP = TakeoffMAP[BoostSpeed]; - } - } else { - if(MAP > RatedMAP[BoostSpeed]) { - MAP = RatedMAP[BoostSpeed]; - } + // estimate throttle plate area. + double throttle_area = ThrottleAngle*ThrottleAngle; + // Internal Combustion Engine in Theory and Practice, Volume 2. Charles Fayette Taylor. Revised Edition, 1985 fig 6-13 + double map_coefficient = 1-((MeanPistonSpeed_fps*MeanPistonSpeed_fps)/(24978*throttle_area)); + + if ( map_coefficient < 0.1 ) map_coefficient = 0.1; + + // Add a one second lag to manifold pressure changes + double dMAP = (TMAP - p_amb * map_coefficient) * dt; + TMAP -=dMAP; + + // Find the mean effective pressure required to achieve this manifold pressure + // Fixme: determine the HP consumed by the supercharger + + PMEP = TMAP - p_amb; // Fixme: p_amb should be exhaust manifold pressure + + if (Boosted) { + // If takeoff boost is fitted, we currently assume the following throttle map: + // (In throttle % - actual input is 0 -> 1) + // 99 / 100 - Takeoff boost + // In real life, most planes would be fitted with a mechanical 'gate' between + // the rated boost and takeoff boost positions. + + bool bTakeoffPos = false; + if (bTakeoffBoost) { + if (Throttle > 0.98) { + bTakeoffPos = true; } } + // Boost the manifold pressure. + double boost_factor = BoostMul[BoostSpeed] * RPM/RatedRPM[BoostSpeed]; + if (boost_factor < 1.0) boost_factor = 1.0; // boost will never reduce the MAP + MAP = TMAP * boost_factor; + // Now clip the manifold pressure to BCV or Wastegate setting. + if (bTakeoffPos) { + if (MAP > TakeoffMAP[BoostSpeed]) MAP = TakeoffMAP[BoostSpeed]; + } else { + if (MAP > RatedMAP[BoostSpeed]) MAP = RatedMAP[BoostSpeed]; + } + } else { + MAP = TMAP; + } // And set the value in American units as well ManifoldPressure_inHg = MAP / inhgtopa; @@ -564,7 +572,7 @@ void FGPiston::doMAP(void) * (used in CHT calculation for air-cooled engines). * * Inputs: p_amb, R_air, T_amb, MAP, Displacement, - * RPM, volumetric_efficiency, ThrottlePos + * RPM, volumetric_efficiency, ThrottleAngle * * TODO: Model inlet manifold air temperature. * @@ -573,21 +581,24 @@ void FGPiston::doMAP(void) void FGPiston::doAirFlow(void) { + double gamma = 1.4; // specific heat constants +// loss of volumentric efficiency due to difference between MAP and exhaust pressure + double ve =((gamma-1)/gamma)+( CompressionRatio -(p_amb/MAP))/(gamma*( CompressionRatio - 1)); -rho_air = p_amb / (R_air * T_amb); - double displacement_SI = Displacement * in3tom3; + rho_air = p_amb / (R_air * T_amb); double swept_volume = (displacement_SI * (RPM/60)) / 2; - double v_dot_air = swept_volume * volumetric_efficiency; + double v_dot_air = swept_volume * volumetric_efficiency *ve; double rho_air_manifold = MAP / (R_air * T_amb); m_dot_air = v_dot_air * rho_air_manifold; + } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /** * Calculate the fuel flow into the engine. * - * Inputs: Mixture, thi_sea_level, p_amb_sea_level, p_amb, m_dot_air + * Inputs: Mixture, thi_sea_level, p_amb, m_dot_air * * Outputs: equivalence_ratio, m_dot_fuel */ @@ -595,14 +606,13 @@ rho_air = p_amb / (R_air * T_amb); void FGPiston::doFuelFlow(void) { double thi_sea_level = 1.3 * Mixture; // Allows an AFR of infinity:1 to 11.3075:1 - equivalence_ratio = thi_sea_level; // * p_amb_sea_level / p_amb; - double AFR = 10+(12*(1-Mixture));// mixture 10:1 to 22:1 - m_dot_fuel = m_dot_air / AFR; - FuelFlow_gph = m_dot_fuel - * 3600 // seconds to hours - * 2.2046 // kg to lb - / 6.0; // lb to gal_us of gasoline -// / 6.6; // lb to gal_us of kerosene + equivalence_ratio = thi_sea_level * 101325.0 / p_amb; +// double AFR = 10+(12*(1-Mixture));// mixture 10:1 to 22:1 +// m_dot_fuel = m_dot_air / AFR; + m_dot_fuel = (m_dot_air * equivalence_ratio) / 14.7; + FuelFlowRate = m_dot_fuel * 2.2046; // kg to lb + FuelFlow_pph = FuelFlowRate * 3600; // seconds to hours + FuelFlow_gph = FuelFlow_pph / 6.0; // Assumes 6 lbs / gallon } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -615,47 +625,53 @@ void FGPiston::doFuelFlow(void) * 200HP. * * Inputs: ManifoldPressure_inHg, p_amb, RPM, T_amb, - * Mixture_Efficiency_Correlation, Cycles, MaxHP + * Mixture_Efficiency_Correlation, Cycles, MaxHP, PMEP, * - * Outputs: Percentage_Power, HP + * Outputs: PctPower, HP */ void FGPiston::doEnginePower(void) { + IndicatedHorsePower = 0; + FMEP = 0; if (Running) { - double T_amb_degF = KelvinToFahrenheit(T_amb); - double T_amb_sea_lev_degF = KelvinToFahrenheit(288); - // FIXME: this needs to be generalized - double ME, Adjusted_BSFC; // Convienience term for use in the calculations + double ME, percent_RPM, power; // Convienience term for use in the calculations ME = Mixture_Efficiency_Correlation->GetValue(m_dot_fuel/m_dot_air); - Adjusted_BSFC = (1/ThrottlePos) * BSFC; - Percentage_Power = 1.000; - if ( Magnetos != 3 ) Percentage_Power *= SparkFailDrop; + percent_RPM = RPM/MaxRPM; +// Guestimate engine friction as a percentage of rated HP + a percentage of rpm + a percentage of Indicted HP +// friction = 1 - (percent_RPM * percent_RPM * percent_RPM/10); + FMEP = (-18400 * MeanPistonSpeed_fps * fttom - 46500); - HP = (FuelFlow_gph * 6.0 / Adjusted_BSFC )* ME * suction_loss * Percentage_Power; + power = 1; - } else { + if ( Magnetos != 3 ) power *= SparkFailDrop; + + + IndicatedHorsePower = (FuelFlow_pph / ISFC )* ME * power; + } else { // Power output when the engine is not running if (Cranking) { if (RPM < 10) { - HP = StarterHP; + IndicatedHorsePower = StarterHP; } else if (RPM < IdleRPM*0.8) { - HP = StarterHP + ((IdleRPM*0.8 - RPM) / 8.0); + IndicatedHorsePower = StarterHP + ((IdleRPM*0.8 - RPM) / 8.0); // This is a guess - would be nice to find a proper starter moter torque curve } else { - HP = StarterHP; + IndicatedHorsePower = StarterHP; } - } else { - // Quick hack until we port the FMEP stuff - if (RPM > 0.0) - HP = -1.5; - else - HP = 0.0; } } + + // Constant is (1/2) * 60 * 745.7 + // (1/2) convert cycles, 60 minutes to seconds, 745.7 watts to hp. + double pumping_hp = ((PMEP + FMEP) * displacement_SI * RPM)/(Cycles*22371); + + HP = IndicatedHorsePower + pumping_hp - 1.5; //FIXME 1.5 static friction should depend on oil temp and configuration +// cout << "pumping_hp " <GetThrusterLabels(EngineNumber, delimeter); return buf.str(); @@ -808,7 +826,7 @@ string FGPiston::GetEngineValues(string delimeter) std::ostringstream buf; buf << PowerAvailable << delimeter << HP << delimeter - << equivalence_ratio << delimeter << MAP << delimeter + << equivalence_ratio << delimeter << ManifoldPressure_inHg << delimeter << Thruster->GetThrusterValues(EngineNumber, delimeter); return buf.str(); @@ -845,24 +863,25 @@ void FGPiston::Debug(int from) cout << " MinManifoldPressure: " << MinManifoldPressure_inHg << endl; cout << " MaxManifoldPressure: " << MaxManifoldPressure_inHg << endl; cout << " MinMaP (Pa): " << minMAP << endl; - cout << " MaxMaP (Pa): " << maxMAP << endl; + cout << " MaxMaP (Pa): " << maxMAP << endl; cout << " Displacement: " << Displacement << endl; + cout << " Bore: " << Bore << endl; + cout << " Stroke: " << Stroke << endl; + cout << " Cylinders: " << Cylinders << endl; + cout << " Compression Ratio: " << CompressionRatio << endl; cout << " MaxHP: " << MaxHP << endl; cout << " Cycles: " << Cycles << endl; cout << " IdleRPM: " << IdleRPM << endl; cout << " MaxThrottle: " << MaxThrottle << endl; cout << " MinThrottle: " << MinThrottle << endl; + cout << " ISFC: " << ISFC << endl; + cout << " Volumentric Efficiency: " << volumetric_efficiency << endl; cout << endl; cout << " Combustion Efficiency table:" << endl; Lookup_Combustion_Efficiency->Print(); cout << endl; - cout << endl; - cout << " Power Mixture Correlation table:" << endl; - Power_Mixture_Correlation->Print(); - cout << endl; - cout << endl; cout << " Mixture Efficiency Correlation table:" << endl; Mixture_Efficiency_Correlation->Print();