rusEFI
The most advanced open source ECU
Functions
fuel_math.h File Reference

Detailed Description

Date
May 27, 2013
Author
Andrey Belomutskiy, (c) 2012-2020

Definition in file fuel_math.h.

Functions

void initFuelMap ()
 Initialize fuel map data structure. More...
 
float getRunningFuel (float baseFuel)
 
float getBaroCorrection ()
 
percent_t getFuelALSCorrection (int rpm)
 
int getNumberOfInjections (injection_mode_e mode)
 
angle_t getInjectionOffset (float rpm, float load)
 
float getIatFuelCorrection ()
 
float getCltFuelCorrection ()
 Engine warm-up fuel correction. More...
 
angle_t getCltTimingCorrection ()
 
float getCrankingFuel (float baseFuel)
 
float getCrankingFuel3 (float baseFuel, uint32_t revolutionCounterSinceStart)
 
float getInjectionMass (int rpm)
 
percent_t getInjectorDutyCycle (int rpm)
 
percent_t getInjectorDutyCycleStage2 (int rpm)
 
float getStage2InjectionFraction (int rpm, float fuelLoad)
 
float getStandardAirCharge ()
 
float getCylinderFuelTrim (size_t cylinderNumber, int rpm, float fuelLoad)
 
AirmassModelBasegetAirmassModel (engine_load_mode_e mode)
 
float getMaxAirflowAtMap (float map)
 

Function Documentation

◆ getAirmassModel()

AirmassModelBase* getAirmassModel ( engine_load_mode_e  mode)

Definition at line 150 of file fuel_math.cpp.

150  {
151  switch (mode) {
152  case LM_SPEED_DENSITY: return &sdAirmass;
153  case LM_REAL_MAF: return &mafAirmass;
154  case LM_ALPHA_N: return &alphaNAirmass;
155 #if EFI_LUA
156  case LM_LUA: return &(getLuaAirmassModel());
157 #endif
158 #if EFI_UNIT_TEST
159  case LM_MOCK: return engine->mockAirmassModel;
160 #endif
161  default:
163  return nullptr;
164  }
165 }
AirmassModelBase * mockAirmassModel
Definition: engine.h:356
Engine * engine
void firmwareError(ObdCode code, const char *fmt,...)
static SpeedDensityAirmass sdAirmass(veMap, mapEstimationTable)
static MafAirmass mafAirmass(veMap)
static AlphaNAirmass alphaNAirmass(veMap)
AirmassModelBase & getLuaAirmassModel()
Definition: lua_hooks.cpp:243
@ CUSTOM_ERR_ASSERT
engine_configuration_s * engineConfiguration

Referenced by getBaseFuelMass(), and lua_getAirmass().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getBaroCorrection()

float getBaroCorrection ( )

Definition at line 380 of file fuel_math.cpp.

380  {
382  // Default to 1atm if failed
383  float pressure = Sensor::get(SensorType::BarometricPressure).value_or(101.325f);
384 
385  float correction = interpolate3d(
387  config->baroCorrPressureBins, pressure,
389  );
390 
391  if (cisnan(correction) || correction < 0.01) {
392  warning(ObdCode::OBD_Barometric_Press_Circ_Range_Perf, "Invalid baro correction %f", correction);
393  return 1;
394  }
395 
396  return correction;
397  } else {
398  return 1;
399  }
400 }
virtual bool hasSensor() const
Definition: sensor.h:155
virtual SensorResult get() const =0
static float getOrZero(SensorType type)
Definition: sensor.h:92
bool warning(ObdCode code, const char *fmt,...)
@ OBD_Barometric_Press_Circ_Range_Perf
persistent_config_s * config
@ BarometricPressure
float baroCorrTable[BARO_CORR_SIZE][BARO_CORR_SIZE]

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCltFuelCorrection()

float getCltFuelCorrection ( )

Engine warm-up fuel correction.

Definition at line 353 of file fuel_math.cpp.

353  {
354  const auto clt = Sensor::get(SensorType::Clt);
355 
356  if (!clt)
357  return 1; // this error should be already reported somewhere else, let's just handle it
358 
359  return interpolate2d(clt.Value, config->cltFuelCorrBins, config->cltFuelCorr);
360 }
static CCM_OPTIONAL FunctionalSensor clt(SensorType::Clt, MS2NT(10))

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCltTimingCorrection()

angle_t getCltTimingCorrection ( )

Definition at line 362 of file fuel_math.cpp.

362  {
363  const auto clt = Sensor::get(SensorType::Clt);
364 
365  if (!clt)
366  return 0; // this error should be already reported somewhere else, let's just handle it
367 
368  return interpolate2d(clt.Value, config->cltTimingBins, config->cltTimingExtra);
369 }

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCrankingFuel()

float getCrankingFuel ( float  baseFuel)
Returns
Duration of fuel injection while craning

Definition at line 423 of file fuel_math.cpp.

423  {
425 }
RpmCalculator rpmCalculator
Definition: engine.h:273
uint32_t getRevolutionCounterSinceStart(void) const
float getCrankingFuel3(float baseFuel, uint32_t revolutionCounterSinceStart)
Definition: fuel_math.cpp:42

Referenced by getCycleFuelMass().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCrankingFuel3()

float getCrankingFuel3 ( float  baseFuel,
uint32_t  revolutionCounterSinceStart 
)

Cranking fuel is different depending on engine coolant temperature If the sensor is failed, use 20 deg C

Definition at line 42 of file fuel_math.cpp.

42  {
43 
44  float baseCrankingFuel;
46  baseCrankingFuel = baseFuel;
47  } else {
48  // parameter is in milligrams, convert to grams
49  baseCrankingFuel = engineConfiguration->cranking.baseFuel * 0.001f;
50  }
51 
52  // Cranking fuel changes over time
55 
56  /**
57  * Cranking fuel is different depending on engine coolant temperature
58  * If the sensor is failed, use 20 deg C
59  */
60  auto clt = Sensor::get(SensorType::Clt).value_or(20);
61  auto e0Mult = interpolate2d(clt, config->crankingFuelBins, config->crankingFuelCoef);
62 
63  bool alreadyWarned = false;
64  if (e0Mult <= 0.1f) {
65  warning(ObdCode::CUSTOM_ERR_ZERO_E0_MULT, "zero e0 multiplier");
66  alreadyWarned = true;
67  }
68 
70  auto e85Mult = interpolate2d(clt, config->crankingFuelBins, config->crankingFuelCoefE100);
71 
72  if (e85Mult <= 0.1f) {
73  warning(ObdCode::CUSTOM_ERR_ZERO_E85_MULT, "zero e85 multiplier");
74  alreadyWarned = true;
75  }
76 
77  // If failed flex sensor, default to 50% E
78  auto flex = Sensor::get(SensorType::FuelEthanolPercent).value_or(50);
79 
82  0, e0Mult,
83  85, e85Mult,
84  flex
85  );
86  } else {
88  }
89 
92  tps.Valid
93  ? interpolate2d(tps.Value, config->crankingTpsBins, config->crankingTpsCoef)
94  : 1; // in case of failed TPS, don't correct.
95 
96  floatms_t crankingFuel = baseCrankingFuel
100 
102 
103  // don't re-warn for zero fuel when we already warned for a more specific problem
104  if (!alreadyWarned && crankingFuel <= 0) {
105  warning(ObdCode::CUSTOM_ERR_ZERO_CRANKING_FUEL, "Cranking fuel value %f", crankingFuel);
106  }
107  return crankingFuel;
108 }
EngineState engineState
Definition: engine.h:315
float interpolateClamped(float x1, float y1, float x2, float y2, float x)
@ CUSTOM_ERR_ZERO_E85_MULT
@ CUSTOM_ERR_ZERO_CRANKING_FUEL
@ CUSTOM_ERR_ZERO_E0_MULT
float floatms_t
Definition: rusefi_types.h:67
@ FuelEthanolPercent
@ DriverThrottleIntent
revolutionCounterSinceStart("revolutionCounterSinceStart", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 54, 1.0, 0.0, 0.0, "")
crankingFuel("crankingFuel", SensorCategory.SENSOR_INPUTS, FieldType.INT, 1132, 1.0, -1.0, -1.0, "")
scaled_channel< uint16_t, 100, 1 > fuel
cranking_fuel_s crankingFuel
scaled_channel< uint16_t, 100, 1 > crankingFuelCoefE100[CRANKING_CURVE_SIZE]

Referenced by getCrankingFuel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getCylinderFuelTrim()

float getCylinderFuelTrim ( size_t  cylinderNumber,
int  rpm,
float  fuelLoad 
)

Definition at line 441 of file fuel_math.cpp.

441  {
442  auto trimPercent = interpolate3d(
443  config->fuelTrims[cylinderNumber].table,
444  config->fuelTrimLoadBins, fuelLoad,
445  config->fuelTrimRpmBins, rpm
446  );
447 
448  // Convert from percent +- to multiplier
449  // 5% -> 1.05
450  return (100 + trimPercent) / 100;
451 }
scaled_channel< int8_t, 5, 1 > table[TRIM_SIZE][TRIM_SIZE]

Referenced by EngineState::periodicFastCallback().

Here is the caller graph for this function:

◆ getFuelALSCorrection()

percent_t getFuelALSCorrection ( int  rpm)

Definition at line 402 of file fuel_math.cpp.

402  {
403 #if EFI_ANTILAG_SYSTEM
405  float throttleIntent = Sensor::getOrZero(SensorType::DriverThrottleIntent);
406  auto AlsFuelAdd = interpolate3d(
408  config->alsFuelAdjustmentLoadBins, throttleIntent,
410  );
411  return AlsFuelAdd;
412  } else
413 #endif /* EFI_ANTILAG_SYSTEM */
414  {
415  return 0;
416  }
417 }
AntilagSystemBase antilagController
Definition: engine.h:199
scaled_channel< int16_t, 10, 1 > ALSFuelAdjustment[4][4]

Referenced by AntilagSystemBase::update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getIatFuelCorrection()

float getIatFuelCorrection ( )

Definition at line 371 of file fuel_math.cpp.

371  {
372  const auto iat = Sensor::get(SensorType::Iat);
373 
374  if (!iat)
375  return 1; // this error should be already reported somewhere else, let's just handle it
376 
377  return interpolate2d(iat.Value, config->iatFuelCorrBins, config->iatFuelCorr);
378 }
static CCM_OPTIONAL FunctionalSensor iat(SensorType::Iat, MS2NT(10))

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getInjectionMass()

float getInjectionMass ( int  rpm)
Returns
Mass of each individual fuel injection, in grams in case of single point injection mode the amount of fuel into all cylinders, otherwise the amount for one cylinder

Definition at line 303 of file fuel_math.cpp.

303  {
305 
306  // Always update base fuel - some cranking modes use it
307  float baseFuelMass = getBaseFuelMass(rpm);
308 
309  bool isCranking = engine->rpmCalculator.isCranking();
310  float cycleFuelMass = getCycleFuelMass(isCranking, baseFuelMass);
311  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(cycleFuelMass), "NaN cycleFuelMass", 0);
312 
313  if (engine->module<DfcoController>()->cutFuel()) {
314  // If decel fuel cut, zero out fuel
315  cycleFuelMass = 0;
316  }
317 
318  float durationMultiplier = getInjectionModeDurationMultiplier();
319  float injectionFuelMass = cycleFuelMass * durationMultiplier;
320 
321  // Prepare injector flow rate & deadtime
322  engine->module<InjectorModelPrimary>()->prepare();
323 
325  engine->module<InjectorModelSecondary>()->prepare();
326  }
327 
329  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(tpsAccelEnrich), "NaN tpsAccelEnrich", 0);
330  engine->engineState.tpsAccelEnrich = tpsAccelEnrich;
331 
332  // For legacy reasons, the TPS accel table is in units of milliseconds, so we have to convert BACK to mass
333  float tpsAccelPerInjection = durationMultiplier * tpsAccelEnrich;
334 
335  float tpsFuelMass = engine->module<InjectorModelPrimary>()->getFuelMassForDuration(tpsAccelPerInjection);
336 
337  return injectionFuelMass + tpsFuelMass;
338 }
bool cutFuel() const
Definition: dfco.cpp:66
constexpr auto & module()
Definition: engine.h:177
TpsAccelEnrichment tpsAccelEnrichment
Definition: engine.h:283
floatms_t tpsAccelEnrich
Definition: engine_state.h:75
bool isCranking() const override
floatms_t getTpsEnrichment()
static float getCycleFuelMass(bool isCranking, float baseFuelMass)
Definition: fuel_math.cpp:291
static float getBaseFuelMass(int rpm)
Definition: fuel_math.cpp:174
float getInjectionModeDurationMultiplier()
Definition: fuel_math.cpp:254
@ GetInjectionDuration

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getInjectionOffset()

angle_t getInjectionOffset ( float  rpm,
float  load 
)

Definition at line 208 of file fuel_math.cpp.

208  {
209  if (cisnan(rpm)) {
210  return 0; // error already reported
211  }
212 
213  if (cisnan(load)) {
214  return 0; // error already reported
215  }
216 
217  angle_t value = interpolate3d(
219  config->injPhaseLoadBins, load,
220  config->injPhaseRpmBins, rpm
221  );
222 
223  if (cisnan(value)) {
224  // we could be here while resetting configuration for example
225  // huh? what? when do we have RPM while resetting configuration? is that CI edge case? shall we fix CI?
226  warning(ObdCode::CUSTOM_ERR_6569, "phase map not ready");
227  return 0;
228  }
229 
230  angle_t result = value;
231  wrapAngle(result, "inj offset#2", ObdCode::CUSTOM_ERR_6553);
232  return result;
233 }
@ CUSTOM_ERR_6553
@ CUSTOM_ERR_6569
float angle_t
Definition: rusefi_types.h:58
int16_t injectionPhase[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getInjectorDutyCycle()

percent_t getInjectorDutyCycle ( int  rpm)

Definition at line 279 of file fuel_math.cpp.

279  {
281  floatms_t engineCycleDuration = getEngineCycleDuration(rpm);
282  return 100 * totalInjectiorAmountPerCycle / engineCycleDuration;
283 }
floatms_t injectionDuration
Definition: engine_state.h:82
floatms_t getEngineCycleDuration(int rpm)
Definition: engine_math.cpp:33
int getNumberOfInjections(injection_mode_e mode)
Definition: fuel_math.cpp:239

Referenced by canDashboardHaltech(), EngineState::periodicFastCallback(), populateFrame(), LimpManager::updateState(), and updateTunerStudioState().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getInjectorDutyCycleStage2()

percent_t getInjectorDutyCycleStage2 ( int  rpm)

Definition at line 285 of file fuel_math.cpp.

285  {
287  floatms_t engineCycleDuration = getEngineCycleDuration(rpm);
288  return 100 * totalInjectiorAmountPerCycle / engineCycleDuration;
289 }
floatms_t injectionDurationStage2
Definition: engine_state.h:83

Referenced by updateTunerStudioState().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getMaxAirflowAtMap()

float getMaxAirflowAtMap ( float  map)

Definition at line 167 of file fuel_math.cpp.

167  {
169 }
float getAirflow(float rpm, float map, bool postState)

Referenced by ThrottleModel::maxEngineFlow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNumberOfInjections()

int getNumberOfInjections ( injection_mode_e  mode)

Number of injections using each injector per engine cycle

See also
getNumberOfSparks

Definition at line 239 of file fuel_math.cpp.

239  {
240  switch (mode) {
241  case IM_SIMULTANEOUS:
242  case IM_SINGLE_POINT:
244  case IM_BATCH:
245  return 2;
246  case IM_SEQUENTIAL:
247  return 1;
248  default:
249  firmwareError(ObdCode::CUSTOM_ERR_INVALID_INJECTION_MODE, "Unexpected injection_mode_e %d", mode);
250  return 1;
251  }
252 }
@ CUSTOM_ERR_INVALID_INJECTION_MODE

Referenced by getInjectorDutyCycle(), getInjectorDutyCycleStage2(), and InjectionEvent::onTriggerTooth().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getRunningFuel()

float getRunningFuel ( float  baseFuel)
Returns
baseFuel with CLT and IAT corrections

Definition at line 110 of file fuel_math.cpp.

110  {
112 
115  float postCrankingFuelCorrection = engine->fuelComputer.running.postCrankingFuelCorrection;
117 
118  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(iatCorrection), "NaN iatCorrection", 0);
119  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(cltCorrection), "NaN cltCorrection", 0);
120  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(postCrankingFuelCorrection), "NaN postCrankingFuelCorrection", 0);
121 
122  float correction = baroCorrection * iatCorrection * cltCorrection * postCrankingFuelCorrection;
123 
124 #if EFI_ANTILAG_SYSTEM
125  correction *= (1 + engine->antilagController.fuelALSCorrection / 100);
126 #endif /* EFI_ANTILAG_SYSTEM */
127 
128 #if EFI_LAUNCH_CONTROL
129  correction *= engine->launchController.getFuelCoefficient();
130 #endif
131 
132  correction *= getLimpManager()->getLimitingFuelCorrection();
133 
134  float runningFuel = baseFuel * correction;
135 
136  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !cisnan(runningFuel), "NaN runningFuel", 0);
137 
138  // Publish output state
139  engine->fuelComputer.running.baseFuel = baseFuel * 1000;
141  engine->fuelComputer.running.fuel = runningFuel * 1000;
142 
143  return runningFuel;
144 }
FuelComputer fuelComputer
Definition: engine.h:121
LaunchControlBase launchController
Definition: engine.h:192
float getFuelCoefficient() const
float getLimitingFuelCorrection() const
LimpManager * getLimpManager()
Definition: engine.cpp:595
@ GetRunningFuel
baroCorrection("Fuel: Barometric pressure mult", SensorCategory.SENSOR_INPUTS, FieldType.INT, 1148, 1.0, -1.0, -1.0, "")
scaled_channel< uint16_t, 100, 1 > baseFuel
scaled_channel< uint16_t, 100, 1 > fuel

Referenced by getCycleFuelMass().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getStage2InjectionFraction()

float getStage2InjectionFraction ( int  rpm,
float  fuelLoad 
)

Definition at line 455 of file fuel_math.cpp.

455  {
457  return 0;
458  }
459 
460  float frac = 0.01f * interpolate3d(
464  );
465 
466  // don't allow very small fraction, with some hysteresis
467  if (!stage2Hysteresis.test(frac, 0.1, 0.03)) {
468  return 0;
469  }
470 
471  // Clamp to 90%
472  if (frac > 0.9) {
473  frac = 0.9;
474  }
475 
476  return frac;
477 }
bool test(float value, float rising, float falling)
Definition: limp_manager.h:88
static Hysteresis stage2Hysteresis
Definition: fuel_math.cpp:453
uint8_t injectorStagingTable[INJ_STAGING_COUNT][INJ_STAGING_COUNT]

Referenced by EngineState::periodicFastCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getStandardAirCharge()

float getStandardAirCharge ( )

Standard cylinder air charge - 100% VE at standard temperature, grams per cylinder

Should we bother caching 'getStandardAirCharge' result or can we afford to run the math every time we calculate fuel?

Definition at line 432 of file fuel_math.cpp.

432  {
433  float totalDisplacement = engineConfiguration->displacement;
434  float cylDisplacement = totalDisplacement / engineConfiguration->cylindersCount;
435 
436  // Calculation of 100% VE air mass in g/cyl - 1 cylinder filling at 1.204/L
437  // 101.325kpa, 20C
438  return idealGasLaw(cylDisplacement, 101.325f, 273.15f + 20.0f);
439 }
mass_t idealGasLaw(float volume, float pressure, float temperature)

Referenced by MafAirmass::getAirmassImpl(), and getBaseFuelMass().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ initFuelMap()

void initFuelMap ( )

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

Definition at line 346 of file fuel_math.cpp.

346  {
348 }
void initTable(TValueInit(&table)[TRowNum][TColNum], const TXColumnInit(&columnBins)[TColNum], const TRowInit(&rowBins)[TRowNum])
Definition: table_helper.h:40
static mapEstimate_Map3D_t mapEstimationTable
Definition: fuel_math.cpp:38
scaled_channel< uint16_t, 100, 1 > mapEstimateTpsBins[FUEL_LOAD_COUNT]
scaled_channel< uint16_t, 100, 1 > mapEstimateTable[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]

Referenced by initDataStructures().

Here is the call graph for this function:
Here is the caller graph for this function:

Go to the source code of this file.