2015-07-10 06:01:56 -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
|
2017-03-06 22:37:07 -08:00
|
|
|
* <BR>2) getCltFuelCorrection() for warm-up
|
2015-07-10 06:01:56 -07:00
|
|
|
* <BR>3) getIatCorrection() to account for cold weather
|
|
|
|
*
|
|
|
|
* getCrankingFuel() depents only on getCoolantTemperature()
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @date May 27, 2013
|
2018-01-20 17:55:31 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2018
|
2015-07-10 06:01:56 -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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#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"
|
|
|
|
|
|
|
|
EXTERN_ENGINE
|
|
|
|
;
|
|
|
|
|
2016-08-26 16:02:56 -07:00
|
|
|
fuel_Map3D_t fuelMap("fuel");
|
2015-12-27 09:01:53 -08:00
|
|
|
static fuel_Map3D_t fuelPhaseMap("fl ph");
|
2015-07-10 06:01:56 -07:00
|
|
|
extern fuel_Map3D_t ve2Map;
|
2016-07-01 16:01:44 -07:00
|
|
|
extern afr_Map3D_t afrMap;
|
2015-07-10 06:01:56 -07:00
|
|
|
extern baroCorr_Map3D_t baroCorrMap;
|
|
|
|
|
2019-01-31 08:57:15 -08:00
|
|
|
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @return total duration of fuel injection per engine cycle, in milliseconds
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
float getRealMafFuel(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (rpm == 0)
|
|
|
|
return 0;
|
|
|
|
// 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);
|
|
|
|
|
2016-03-11 12:01:58 -08:00
|
|
|
float afr = afrMap.getValue(rpm, airSpeed);
|
2015-07-10 06:01:56 -07:00
|
|
|
float fuelMassGramm = airMassKg / afr * 1000;
|
|
|
|
|
|
|
|
return 1000 * fuelMassGramm / injectorFlowRate;
|
|
|
|
}
|
|
|
|
|
2017-11-06 19:29:39 -08:00
|
|
|
/**
|
|
|
|
* per-cylinder fuel amount
|
|
|
|
* todo: rename this method since it's now base+TPSaccel
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
floatms_t tpsAccelEnrich = ENGINE(tpsAccelEnrichment.getTpsEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE));
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(tpsAccelEnrich), "NaN tpsAccelEnrich", 0);
|
2017-04-12 15:38:18 -07:00
|
|
|
ENGINE(engineState.tpsAccelEnrich) = tpsAccelEnrich;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-04-12 19:59:59 -07:00
|
|
|
floatms_t baseFuel;
|
2016-08-28 13:02:34 -07:00
|
|
|
if (CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) {
|
2019-01-27 22:25:23 -08:00
|
|
|
baseFuel = getSpeedDensityFuel(getMap() PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN sd baseFuel", 0);
|
2016-08-28 13:02:34 -07:00
|
|
|
} else if (engineConfiguration->fuelAlgorithm == LM_REAL_MAF) {
|
2017-05-15 20:28:49 -07:00
|
|
|
float maf = getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) + engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
|
|
baseFuel = getRealMafFuel(maf, rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN rm baseFuel", 0);
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
2017-04-12 19:59:59 -07:00
|
|
|
baseFuel = engine->engineState.baseTableFuel;
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN bt baseFuel", 0);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-04-12 19:59:59 -07:00
|
|
|
engine->engineState.baseFuel = baseFuel;
|
2015-12-02 17:10:06 -08:00
|
|
|
|
2017-04-12 19:59:59 -07:00
|
|
|
return tpsAccelEnrich + baseFuel;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-06-12 02:14:19 -07:00
|
|
|
angle_t getInjectionOffset(float rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2018-01-01 15:59:50 -08:00
|
|
|
if (cisnan(rpm)) {
|
|
|
|
return 0; // error already reported
|
|
|
|
}
|
2017-05-15 20:28:49 -07:00
|
|
|
float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2018-01-01 15:59:50 -08:00
|
|
|
if (cisnan(engineLoad)) {
|
2017-12-03 12:30:42 -08:00
|
|
|
return 0; // error already reported
|
|
|
|
}
|
2017-12-06 18:43:22 -08:00
|
|
|
angle_t value = fuelPhaseMap.getValue(rpm, engineLoad);
|
2018-01-01 15:59:50 -08:00
|
|
|
if (cisnan(value)) {
|
2018-09-01 06:12:33 -07:00
|
|
|
// we could be here while resetting configuration for example
|
|
|
|
warning(CUSTOM_ERR_6569, "phase map not ready");
|
2018-01-01 15:59:50 -08:00
|
|
|
return 0;
|
|
|
|
}
|
2017-12-06 18:43:22 -08:00
|
|
|
angle_t result = value + CONFIG(extraInjectionOffset);
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(result, "inj offset#2", CUSTOM_ERR_6553);
|
2016-08-28 14:02:14 -07:00
|
|
|
return result;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-11-06 19:29:39 -08:00
|
|
|
* Number of injections using each injector per engine cycle
|
2017-03-06 22:28:26 -08:00
|
|
|
* @see getNumberOfSparks
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
int getNumberOfInjections(injection_mode_e mode DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
switch (mode) {
|
|
|
|
case IM_SIMULTANEOUS:
|
2017-11-06 16:00:30 -08:00
|
|
|
case IM_SINGLE_POINT:
|
2017-11-06 19:29:39 -08:00
|
|
|
return engineConfiguration->specs.cylindersCount;
|
2015-07-10 06:01:56 -07:00
|
|
|
case IM_BATCH:
|
2016-07-23 18:04:30 -07:00
|
|
|
return 2;
|
2017-11-06 19:29:39 -08:00
|
|
|
case IM_SEQUENTIAL:
|
|
|
|
return 1;
|
2015-07-10 06:01:56 -07:00
|
|
|
default:
|
2016-10-10 13:02:39 -07:00
|
|
|
firmwareError(CUSTOM_ERR_INVALID_INJECTION_MODE, "Unexpected injection_mode_e %d", mode);
|
2015-07-10 06:01:56 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-06 22:28:26 -08:00
|
|
|
/**
|
2017-12-12 14:40:48 -08:00
|
|
|
* This is more like MOSFET duty cycle since durations include injector lag
|
2017-03-06 22:28:26 -08:00
|
|
|
* @see getCoilDutyCycle
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
percent_t getInjectorDutyCycle(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2017-11-06 19:29:39 -08:00
|
|
|
floatms_t totalInjectiorAmountPerCycle = getInjectionDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX) * getNumberOfInjections(engineConfiguration->injectionMode PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t engineCycleDuration = getEngineCycleDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-11-06 19:29:39 -08:00
|
|
|
return 100 * totalInjectiorAmountPerCycle / engineCycleDuration;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-08-23 19:01:55 -07:00
|
|
|
* @returns Length of each individual fuel injection, in milliseconds
|
2017-11-06 19:29:39 -08:00
|
|
|
* in case of single point injection mode the amount of fuel into all cylinders, otherwise the amount for one cylinder
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t getInjectionDuration(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2019-01-31 14:55:23 -08:00
|
|
|
#if (EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT) || defined(__DOXYGEN__)
|
2017-07-06 05:49:55 -07:00
|
|
|
bool isCranking = ENGINE(rpmCalculator).isCranking(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2017-11-06 19:29:39 -08:00
|
|
|
injection_mode_e mode = isCranking ?
|
2017-04-12 16:58:29 -07:00
|
|
|
engineConfiguration->crankingInjectionMode :
|
2017-11-06 19:29:39 -08:00
|
|
|
engineConfiguration->injectionMode;
|
|
|
|
int numberOfInjections = getNumberOfInjections(mode PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-11-06 15:46:37 -08:00
|
|
|
if (numberOfInjections == 0) {
|
2017-04-19 19:03:14 -07:00
|
|
|
warning(CUSTOM_CONFIG_NOT_READY, "config not ready");
|
2017-04-12 16:58:29 -07:00
|
|
|
return 0; // we can end up here during configuration reset
|
|
|
|
}
|
2017-11-06 19:29:39 -08:00
|
|
|
floatms_t fuelPerCycle;
|
2017-04-12 16:58:29 -07:00
|
|
|
if (isCranking) {
|
2017-11-06 19:29:39 -08:00
|
|
|
fuelPerCycle = getCrankingFuel(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelPerCycle), "NaN cranking fuelPerCycle", 0);
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t baseFuel = getBaseFuel(rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-11-06 19:29:39 -08:00
|
|
|
fuelPerCycle = getRunningFuel(baseFuel PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelPerCycle), "NaN fuelPerCycle", 0);
|
2016-09-25 21:03:15 -07:00
|
|
|
#if EFI_PRINTF_FUEL_DETAILS || defined(__DOXYGEN__)
|
2018-01-23 09:05:14 -08:00
|
|
|
printf("baseFuel=%.2f fuelPerCycle=%.2f \t\n",
|
2017-11-06 19:29:39 -08:00
|
|
|
baseFuel, fuelPerCycle);
|
2016-09-25 21:03:15 -07:00
|
|
|
#endif /*EFI_PRINTF_FUEL_DETAILS */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-11-06 19:29:39 -08:00
|
|
|
if (mode == IM_SINGLE_POINT) {
|
|
|
|
// here we convert per-cylinder fuel amount into total engine amount since the single injector serves all cylinders
|
|
|
|
fuelPerCycle *= engineConfiguration->specs.cylindersCount;
|
|
|
|
}
|
2018-03-22 10:37:34 -07:00
|
|
|
// Fuel cut-off isn't just 0 or 1, it can be tapered
|
|
|
|
fuelPerCycle *= ENGINE(engineState.fuelCutoffCorrection);
|
|
|
|
// If no fuel, don't add injector lag
|
|
|
|
if (fuelPerCycle == 0.0f)
|
|
|
|
return 0;
|
|
|
|
|
2017-11-06 19:29:39 -08:00
|
|
|
floatms_t theoreticalInjectionLength = fuelPerCycle / numberOfInjections;
|
2017-04-19 04:58:22 -07:00
|
|
|
floatms_t injectorLag = ENGINE(engineState.injectorLag);
|
|
|
|
if (cisnan(injectorLag)) {
|
2017-05-24 20:42:27 -07:00
|
|
|
warning(CUSTOM_ERR_INJECTOR_LAG, "injectorLag not ready");
|
2017-04-19 04:58:22 -07:00
|
|
|
return 0; // we can end up here during configuration reset
|
|
|
|
}
|
2017-05-24 20:48:03 -07:00
|
|
|
return theoreticalInjectionLength * engineConfiguration->globalFuelCorrection + injectorLag;
|
2019-01-31 14:55:23 -08:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
float iatCorrection = ENGINE(engineState.iatFuelCorrection);
|
|
|
|
float cltCorrection = ENGINE(engineState.cltFuelCorrection);
|
2017-11-02 15:10:42 -07:00
|
|
|
float postCrankingFuelCorrection = ENGINE(engineState.postCrankingFuelCorrection);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(iatCorrection), "NaN iatCorrection", 0);
|
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(cltCorrection), "NaN cltCorrection", 0);
|
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(postCrankingFuelCorrection), "NaN postCrankingFuelCorrection", 0);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-11-02 15:10:42 -07:00
|
|
|
floatms_t runningFuel = baseFuel * iatCorrection * cltCorrection * postCrankingFuelCorrection + ENGINE(engineState.fuelPidCorrection);
|
2018-07-25 20:30:00 -07:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(runningFuel), "NaN runningFuel", 0);
|
2017-04-12 17:38:53 -07:00
|
|
|
ENGINE(engineState.runningFuel) = runningFuel;
|
2015-09-02 19:01:17 -07:00
|
|
|
|
2017-04-12 17:38:53 -07:00
|
|
|
return runningFuel;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Injector lag correction
|
|
|
|
* @param vBatt Battery voltage.
|
|
|
|
* @return Time in ms for injection opening time based on current battery voltage
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t getInjectorLag(float vBatt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (cisnan(vBatt)) {
|
2018-01-23 09:05:14 -08:00
|
|
|
warning(OBD_System_Voltage_Malfunction, "vBatt=%.2f", vBatt);
|
2016-07-24 20:02:52 -07:00
|
|
|
return 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-06-11 12:27:23 -07:00
|
|
|
float vBattCorrection = interpolate2d("lag", vBatt, INJECTOR_LAG_CURVE);
|
2016-07-24 20:02:52 -07:00
|
|
|
return vBattCorrection;
|
2015-07-10 06:01:56 -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
|
|
|
|
*/
|
2019-01-10 20:48:05 -08:00
|
|
|
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2015-07-10 06:01:56 -07:00
|
|
|
fuelMap.init(config->fuelTable, config->fuelLoadBins, config->fuelRpmBins);
|
|
|
|
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Engine warm-up fuel correction.
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
float getCltFuelCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2017-03-06 23:24:57 -08:00
|
|
|
if (cisnan(engine->sensors.clt))
|
2015-07-10 06:01:56 -07:00
|
|
|
return 1; // this error should be already reported somewhere else, let's just handle it
|
2017-06-11 12:27:23 -07:00
|
|
|
return interpolate2d("cltf", engine->sensors.clt, WARMUP_CLT_EXTRA_FUEL_CURVE) / PERCENT_MULT;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
angle_t getCltTimingCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2017-03-06 23:24:57 -08:00
|
|
|
if (cisnan(engine->sensors.clt))
|
2017-01-05 18:12:06 -08:00
|
|
|
return 0; // this error should be already reported somewhere else, let's just handle it
|
2017-05-29 08:31:07 -07:00
|
|
|
return interpolate2d("timc", engine->sensors.clt, engineConfiguration->cltTimingBins, engineConfiguration->cltTimingExtra, CLT_TIMING_CURVE_SIZE);
|
2017-01-05 18:12:06 -08:00
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
float getIatFuelCorrection(float iat DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (cisnan(iat))
|
|
|
|
return 1; // this error should be already reported somewhere else, let's just handle it
|
2017-06-11 12:27:23 -07:00
|
|
|
return interpolate2d("iatc", iat, IAT_FUEL_CORRECTION_CURVE);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-03-22 10:37:34 -07:00
|
|
|
/**
|
|
|
|
* @brief Called from EngineState::periodicFastCallback to update the state.
|
|
|
|
* @note The returned value is float, not boolean - to implement taper (smoothed correction).
|
|
|
|
* @return Fuel duration correction for fuel cut-off control (ex. if coasting). No correction if 1.0
|
|
|
|
*/
|
|
|
|
float getFuelCutOffCorrection(efitick_t nowNt, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
// no corrections by default
|
|
|
|
float fuelCorr = 1.0f;
|
|
|
|
|
|
|
|
// coasting fuel cut-off correction
|
2019-01-09 19:16:30 -08:00
|
|
|
if (CONFIGB(coastingFuelCutEnabled)) {
|
2018-03-22 10:37:34 -07:00
|
|
|
percent_t tpsPos = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2018-06-23 06:32:41 -07:00
|
|
|
float map = getMap();
|
2018-03-22 10:37:34 -07:00
|
|
|
|
|
|
|
// gather events
|
2018-06-23 06:32:41 -07:00
|
|
|
bool mapDeactivate = (map >= CONFIG(coastingFuelCutMap));
|
2018-03-22 10:37:34 -07:00
|
|
|
bool tpsDeactivate = (tpsPos >= CONFIG(coastingFuelCutTps));
|
|
|
|
bool cltDeactivate = cisnan(engine->sensors.clt) ? false : (engine->sensors.clt < (float)CONFIG(coastingFuelCutClt));
|
|
|
|
bool rpmDeactivate = (rpm < CONFIG(coastingFuelCutRpmLow));
|
|
|
|
bool rpmActivate = (rpm > CONFIG(coastingFuelCutRpmHigh));
|
|
|
|
|
|
|
|
// state machine (coastingFuelCutStartTime is also used as a flag)
|
2018-06-23 06:32:41 -07:00
|
|
|
if (!mapDeactivate && !tpsDeactivate && !cltDeactivate && rpmActivate) {
|
2018-03-22 10:37:34 -07:00
|
|
|
ENGINE(engineState.coastingFuelCutStartTime) = nowNt;
|
2018-06-23 06:32:41 -07:00
|
|
|
} else if (mapDeactivate || tpsDeactivate || rpmDeactivate || cltDeactivate) {
|
2018-03-22 10:37:34 -07:00
|
|
|
ENGINE(engineState.coastingFuelCutStartTime) = 0;
|
|
|
|
}
|
|
|
|
// enable fuelcut?
|
|
|
|
if (ENGINE(engineState.coastingFuelCutStartTime) != 0) {
|
|
|
|
// todo: add taper - interpolate using (nowNt - coastingFuelCutStartTime)?
|
|
|
|
fuelCorr = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// todo: add other fuel cut-off checks here (possibly cutFuelOnHardLimit?)
|
|
|
|
return fuelCorr;
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @return Fuel injection duration injection as specified in the fuel map, in milliseconds
|
|
|
|
*/
|
2017-04-12 20:25:58 -07:00
|
|
|
floatms_t getBaseTableFuel(int rpm, float engineLoad) {
|
2019-01-31 14:55:23 -08:00
|
|
|
#if (EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT) || defined(__DOXYGEN__)
|
2015-07-10 06:01:56 -07:00
|
|
|
if (cisnan(engineLoad)) {
|
2016-11-02 20:01:48 -07:00
|
|
|
warning(CUSTOM_NAN_ENGINE_LOAD_2, "NaN engine load");
|
2017-04-13 07:43:27 -07:00
|
|
|
return 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-04-13 05:28:41 -07:00
|
|
|
floatms_t result = fuelMap.getValue(rpm, engineLoad);
|
|
|
|
if (cisnan(result)) {
|
|
|
|
// result could be NaN in case of invalid table, like during initialization
|
|
|
|
result = 0;
|
2017-04-13 07:43:27 -07:00
|
|
|
warning(CUSTOM_ERR_FUEL_TABLE_NOT_READY, "baseFuel table not ready");
|
2017-04-13 05:28:41 -07:00
|
|
|
}
|
|
|
|
return result;
|
2019-01-31 14:55:23 -08:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
float getBaroCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
|
|
if (hasBaroSensor(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
2019-01-21 18:48:58 -08:00
|
|
|
return baroCorrMap.getValue(GET_RPM(), getBaroPressure(PASS_ENGINE_PARAMETER_SIGNATURE));
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-02 19:01:17 -07:00
|
|
|
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @return Duration of fuel injection while craning
|
|
|
|
*/
|
2017-05-15 20:28:49 -07:00
|
|
|
floatms_t getCrankingFuel(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
|
|
return getCrankingFuel3(getCoolantTemperature(PASS_ENGINE_PARAMETER_SIGNATURE),
|
|
|
|
engine->rpmCalculator.getRevolutionCounterSinceStart() PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
floatms_t getCrankingFuel3(float coolantTemperature,
|
2017-05-15 20:28:49 -07:00
|
|
|
uint32_t revolutionCounterSinceStart DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
// these magic constants are in Celsius
|
|
|
|
float baseCrankingFuel = engineConfiguration->cranking.baseFuel;
|
2017-05-07 11:09:40 -07:00
|
|
|
if (cisnan(coolantTemperature)) // todo: move this check down, below duration correction?
|
2015-07-10 06:01:56 -07:00
|
|
|
return baseCrankingFuel;
|
2017-05-29 08:31:07 -07:00
|
|
|
float durationCoef = interpolate2d("crank", revolutionCounterSinceStart, config->crankingCycleBins,
|
2015-07-10 06:01:56 -07:00
|
|
|
config->crankingCycleCoef, CRANKING_CURVE_SIZE);
|
|
|
|
|
2017-05-29 08:31:07 -07:00
|
|
|
float coolantTempCoef = interpolate2d("crank", coolantTemperature, config->crankingFuelBins,
|
2015-08-18 22:01:23 -07:00
|
|
|
config->crankingFuelCoef, CRANKING_CURVE_SIZE);
|
|
|
|
|
2017-05-29 08:31:07 -07:00
|
|
|
float tpsCoef = interpolate2d("crank", getTPS(PASS_ENGINE_PARAMETER_SIGNATURE), engineConfiguration->crankingTpsBins,
|
2015-08-18 22:01:23 -07:00
|
|
|
engineConfiguration->crankingTpsCoef, CRANKING_CURVE_SIZE);
|
|
|
|
|
|
|
|
return baseCrankingFuel * durationCoef * coolantTempCoef * tpsCoef;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-12-17 18:10:02 -08:00
|
|
|
|
2017-12-31 16:25:59 -08:00
|
|
|
float getFuelRate(floatms_t totalInjDuration, efitick_t timePeriod DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
if (timePeriod <= 0.0f)
|
|
|
|
return 0.0f;
|
|
|
|
float timePeriodMs = (float)NT2US(timePeriod) / 1000.0f;
|
|
|
|
float fuelRate = totalInjDuration / timePeriodMs;
|
|
|
|
const float cc_min_to_L_h = 60.0f / 1000.0f;
|
|
|
|
return fuelRate * CONFIG(injector.flow) * cc_min_to_L_h;
|
2017-12-17 18:10:02 -08:00
|
|
|
}
|
2019-01-31 08:57:15 -08:00
|
|
|
|
|
|
|
#endif
|