fome-fw/firmware/controllers/algo/fuel_math.cpp

213 lines
7.5 KiB
C++
Raw Normal View History

2014-08-29 07:52:33 -07:00
/**
* @file fuel_math.cpp
* @brief Fuel amount calculation logic
*
* While engine running, fuel amount is an interpolated value from the fuel map by getRpm() and getEngineLoad()
* On top of the value from the fuel map we also apply
* <BR>1) getInjectorLag() correction to account for fuel injector lag
* <BR>2) getCltCorrection() for warm-up
* <BR>3) getIatCorrection() to account for cold weather
*
* getCrankingFuel() depents only on getCoolantTemperature()
*
*
* @date May 27, 2013
2015-01-12 15:04:10 -08:00
* @author Andrey Belomutskiy, (c) 2012-2015
2014-08-29 07:52:33 -07:00
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "main.h"
#include "fuel_math.h"
#include "interpolation.h"
#include "engine_configuration.h"
#include "allsensors.h"
#include "engine_math.h"
#include "rpm_calculator.h"
#include "speed_density.h"
#if EFI_ACCEL_ENRICHMENT
#include "accel_enrichment.h"
#endif /* EFI_ACCEL_ENRICHMENT */
2015-02-26 15:09:02 -08:00
EXTERN_ENGINE
;
2014-11-07 20:03:53 -08:00
2015-03-06 10:04:53 -08:00
static fuel_Map3D_t fuelMap;
static fuel_Map3D_t fuelPhaseMap;
extern fuel_Map3D_t ve2Map;
extern fuel_Map3D_t afrMap;
2015-02-13 18:04:20 -08:00
/**
* @return total duration of fuel injection per engine cycle, in milliseconds
*/
float getRealMafFuel(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_S) {
2015-02-26 15:09:02 -08:00
if (rpm == 0)
return 0;
2015-02-13 18:04:20 -08:00
// duration of engine cycle, in hours
float engineCycleDurationHr = 1.0 / 60 / rpm;
float airMassKg = airSpeed * engineCycleDurationHr;
/**
* todo: pre-calculate gramm/second injector flow to save one multiplication
* open question if that's needed since that's just a multiplication
*/
float injectorFlowRate = cc_minute_to_gramm_second(engineConfiguration->injector.flow);
float afr = afrMap.getValue(airSpeed, rpm);
float fuelMassGramm = airMassKg / afr * 1000;
return 1000 * fuelMassGramm / injectorFlowRate;
}
2015-01-01 15:04:13 -08:00
2015-04-12 11:05:29 -07:00
floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_S) {
floatms_t tpsAccelEnrich = engine->tpsAccelEnrichment.getTpsEnrichment(PASS_ENGINE_PARAMETER_F);
2015-02-27 14:07:50 -08:00
if (engineConfiguration->algorithm == LM_SPEED_DENSITY) {
2015-04-12 11:05:29 -07:00
return tpsAccelEnrich + getSpeedDensityFuel(rpm PASS_ENGINE_PARAMETER);
2015-02-27 14:07:50 -08:00
} else if (engineConfiguration->algorithm == LM_REAL_MAF) {
2015-04-10 22:04:25 -07:00
float maf = getRealMaf(PASS_ENGINE_PARAMETER_F) + engine->mapAccelEnrichment.getMapEnrichment(PASS_ENGINE_PARAMETER_F);
2015-04-12 11:05:29 -07:00
return tpsAccelEnrich + getRealMafFuel(maf, rpm PASS_ENGINE_PARAMETER);
2014-08-29 07:52:33 -07:00
} else {
2014-11-24 18:03:34 -08:00
float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_F);
2015-04-12 11:05:29 -07:00
return tpsAccelEnrich + getBaseTableFuel(engineConfiguration, rpm, engineLoad);
2014-08-29 07:52:33 -07:00
}
}
2015-02-12 19:04:12 -08:00
float getInjectionAngle(int rpm DECLARE_ENGINE_PARAMETER_S) {
float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_F);
return fuelPhaseMap.getValue(engineLoad, rpm);
}
2014-09-06 17:02:54 -07:00
/**
* Number of injections into each cylinder per engine cycle
*/
static int getNumberOfInjections(engine_configuration_s const *engineConfiguration, injection_mode_e mode) {
switch (mode) {
case IM_SIMULTANEOUS:
2015-02-09 08:07:00 -08:00
return engineConfiguration->specs.cylindersCount;
2014-09-06 17:02:54 -07:00
case IM_SEQUENTIAL:
return 1;
case IM_BATCH:
2015-02-09 08:07:00 -08:00
return engineConfiguration->specs.cylindersCount / 2;
2014-09-06 17:02:54 -07:00
default:
firmwareError("Unexpected getFuelMultiplier %d", mode);
return 1;
}
}
2014-08-29 07:52:33 -07:00
/**
* @returns Length of fuel injection, in milliseconds
*/
2015-04-12 11:05:29 -07:00
floatms_t getFuelMs(int rpm DECLARE_ENGINE_PARAMETER_S) {
2014-10-02 12:02:57 -07:00
float theoreticalInjectionLength;
2014-10-02 20:03:25 -07:00
if (isCrankingR(rpm)) {
2015-02-27 14:07:50 -08:00
theoreticalInjectionLength = getCrankingFuel(PASS_ENGINE_PARAMETER_F)
2015-02-26 15:09:02 -08:00
/ getNumberOfInjections(engineConfiguration, engineConfiguration->crankingInjectionMode);
2014-08-29 07:52:33 -07:00
} else {
2014-11-24 18:03:34 -08:00
float baseFuel = getBaseFuel(rpm PASS_ENGINE_PARAMETER);
2014-11-07 21:07:22 -08:00
float fuelPerCycle = getRunningFuel(baseFuel, rpm PASS_ENGINE_PARAMETER);
2015-02-26 15:09:02 -08:00
theoreticalInjectionLength = fuelPerCycle
2015-02-27 15:08:55 -08:00
/ getNumberOfInjections(engineConfiguration, engineConfiguration->injectionMode);
2014-08-29 07:52:33 -07:00
}
2015-02-10 10:07:06 -08:00
return theoreticalInjectionLength + ENGINE(injectorLagMs);
2014-08-29 07:52:33 -07:00
}
2015-04-12 11:05:29 -07:00
floatms_t getRunningFuel(floatms_t baseFuel, int rpm DECLARE_ENGINE_PARAMETER_S) {
2015-02-10 07:09:58 -08:00
float iatCorrection = getIatCorrection(engine->engineState.iat PASS_ENGINE_PARAMETER);
float cltCorrection = getCltCorrection(engine->engineState.clt PASS_ENGINE_PARAMETER);
2014-08-29 07:52:33 -07:00
#if EFI_ACCEL_ENRICHMENT
float accelEnrichment = getAccelEnrichment();
// todo: accelEnrichment
#endif /* EFI_ACCEL_ENRICHMENT */
2015-04-12 11:05:29 -07:00
return baseFuel * cltCorrection * iatCorrection;
2014-08-29 07:52:33 -07:00
}
/**
* @brief Injector lag correction
* @param vBatt Battery voltage.
* @return Time in ms for injection opening time based on current battery voltage
*/
2015-04-12 11:05:29 -07:00
floatms_t getInjectorLag(float vBatt DECLARE_ENGINE_PARAMETER_S) {
2014-08-29 07:52:33 -07:00
if (cisnan(vBatt)) {
warning(OBD_System_Voltage_Malfunction, "vBatt=%f", vBatt);
2015-02-02 09:05:12 -08:00
return engineConfiguration->injector.lag;
2014-08-29 07:52:33 -07:00
}
2015-02-02 11:04:09 -08:00
float vBattCorrection = interpolate2d(vBatt, engineConfiguration->injector.battLagCorrBins,
engineConfiguration->injector.battLagCorr, VBAT_INJECTOR_CURVE_SIZE);
2015-02-02 09:05:12 -08:00
return engineConfiguration->injector.lag + vBattCorrection;
2014-08-29 07:52:33 -07:00
}
/**
* @brief Initialize fuel map data structure
* @note this method has nothing to do with fuel map VALUES - it's job
* is to prepare the fuel map data structure for 3d interpolation
*/
2015-02-27 22:04:17 -08:00
void prepareFuelMap(DECLARE_ENGINE_PARAMETER_F) {
2015-04-05 14:04:54 -07:00
fuelMap.init(config->fuelTable, config->fuelLoadBins, config->fuelRpmBins);
2015-04-04 21:06:25 -07:00
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
2014-08-29 07:52:33 -07:00
}
/**
* @brief Engine warm-up fuel correction.
*/
2014-11-12 13:05:43 -08:00
float getCltCorrection(float clt DECLARE_ENGINE_PARAMETER_S) {
2014-08-29 07:52:33 -07:00
if (cisnan(clt))
return 1; // this error should be already reported somewhere else, let's just handle it
2015-04-05 14:04:54 -07:00
return interpolate2d(clt, config->cltFuelCorrBins, config->cltFuelCorr, CLT_CURVE_SIZE);
2014-08-29 07:52:33 -07:00
}
2014-11-12 13:05:43 -08:00
float getIatCorrection(float iat DECLARE_ENGINE_PARAMETER_S) {
2014-08-29 07:52:33 -07:00
if (cisnan(iat))
return 1; // this error should be already reported somewhere else, let's just handle it
2015-04-05 14:04:54 -07:00
return interpolate2d(iat, config->iatFuelCorrBins, config->iatFuelCorr, IAT_CURVE_SIZE);
2014-08-29 07:52:33 -07:00
}
2014-09-06 15:02:55 -07:00
/**
* @return Fuel injection duration injection as specified in the fuel map, in milliseconds
*/
2015-04-12 11:05:29 -07:00
floatms_t getBaseTableFuel(engine_configuration_s *engineConfiguration, int rpm, float engineLoad) {
2014-09-13 13:04:13 -07:00
if (cisnan(engineLoad)) {
warning(OBD_PCM_Processor_Fault, "NaN engine load");
return NAN;
}
2015-02-12 18:06:16 -08:00
return fuelMap.getValue(engineLoad, rpm);
2014-08-29 07:52:33 -07:00
}
2015-01-20 15:04:01 -08:00
#if EFI_ENGINE_CONTROL
2014-09-06 15:02:55 -07:00
/**
2015-04-12 11:05:29 -07:00
* @return Duration of fuel injection while craning
2014-09-06 15:02:55 -07:00
*/
2015-04-12 11:05:29 -07:00
floatms_t getCrankingFuel(DECLARE_ENGINE_PARAMETER_F) {
2015-04-05 09:11:54 -07:00
return getCrankingFuel3(getCoolantTemperature(PASS_ENGINE_PARAMETER_F),
engine->rpmCalculator.getRevolutionCounterSinceStart() PASS_ENGINE_PARAMETER);
2014-08-29 07:52:33 -07:00
}
2015-01-20 15:04:01 -08:00
#endif
2014-08-29 07:52:33 -07:00
2015-04-12 11:05:29 -07:00
floatms_t getCrankingFuel3(float coolantTemperature,
2015-04-05 09:11:54 -07:00
uint32_t revolutionCounterSinceStart DECLARE_ENGINE_PARAMETER_S) {
2014-08-29 07:52:33 -07:00
// these magic constants are in Celsius
2015-01-22 17:05:54 -08:00
float baseCrankingFuel = engineConfiguration->cranking.baseFuel;
2014-11-03 07:04:35 -08:00
if (cisnan(coolantTemperature))
return baseCrankingFuel;
2015-04-05 14:04:54 -07:00
float durationCoef = interpolate2d(revolutionCounterSinceStart, config->crankingCycleBins,
config->crankingCycleCoef, CRANKING_CURVE_SIZE);
2014-11-03 10:03:03 -08:00
2015-04-05 14:04:54 -07:00
return interpolate2d(coolantTemperature, config->crankingFuelBins,
config->crankingFuelCoef, CRANKING_CURVE_SIZE) * baseCrankingFuel * durationCoef;
2014-08-29 07:52:33 -07:00
}