Merge remote-tracking branch 'origin/master'

This commit is contained in:
rusefi 2020-06-06 10:21:16 -04:00
commit f1566343a0
8 changed files with 64 additions and 26 deletions

View File

@ -0,0 +1,6 @@
#pragma once
struct AirmassResult {
float CylinderAirmass = 0;
float EngineLoadPercent = 100;
};

View File

@ -202,7 +202,6 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
currentRawVE = interpolateClamped(0.0f, idleVe, CONFIG(idlePidDeactivationTpsThreshold), currentRawVE, tps.Value);
}
currentBaroCorrectedVE = baroCorrection * currentRawVE * PERCENT_DIV;
targetAFR = afrMap.getValue(rpm, map);
} else {
baseTableFuel = getBaseTableFuel(rpm, engineLoad);
}

View File

@ -22,6 +22,7 @@
*/
#include "global.h"
#include "airmass.h"
#include "fuel_math.h"
#include "interpolation.h"
#include "engine_configuration.h"
@ -145,10 +146,10 @@ floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
* Function block now works to create a standardised load from the cylinder filling as well as tune fuel via VE table.
* @return total duration of fuel injection per engine cycle, in milliseconds
*/
float getRealMafFuel(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
AirmassResult getRealMafAirmass(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
// If the engine is stopped, MAF is meaningless
if (rpm == 0) {
return 0;
return {};
}
// kg/hr -> g/s
@ -167,13 +168,13 @@ float getRealMafFuel(float airSpeed, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
//Create % load for fuel table using relative naturally aspiratedcylinder filling
float airChargeLoad = 100 * cylinderAirmass / ENGINE(standardAirCharge);
//Correct air mass by VE table
float corrCylAirmass = cylinderAirmass * veMap.getValue(rpm, airChargeLoad) / 100;
float afr = afrMap.getValue(rpm, airChargeLoad);
float pulseWidthSeconds = getInjectionDurationForAirmass(corrCylAirmass, afr PASS_ENGINE_PARAMETER_SUFFIX);
//Correct air mass by VE table
float correctedAirmass = cylinderAirmass * veMap.getValue(rpm, airChargeLoad) / 100;
// Convert to ms
return 1000 * pulseWidthSeconds;
return {
correctedAirmass,
airChargeLoad, // AFR/VE table Y axis
};
}
constexpr float convertToGramsPerSecond(float ccPerMinute) {
@ -190,6 +191,19 @@ float getInjectionDurationForAirmass(float airMass, float afr DECLARE_ENGINE_PAR
return airMass / (afr * gPerSec);
}
AirmassResult getAirmass(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
switch (CONFIG(fuelAlgorithm)) {
case LM_SPEED_DENSITY:
return getSpeedDensityAirmass(getMap(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
case LM_REAL_MAF: {
float maf = getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) + engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
return getRealMafAirmass(maf, rpm PASS_ENGINE_PARAMETER_SUFFIX);
} default:
firmwareError(CUSTOM_ERR_ASSERT, "Fuel mode %d is not airmass mode", CONFIG(fuelAlgorithm));
return {};
}
}
/**
* per-cylinder fuel amount
* todo: rename this method since it's now base+TPSaccel
@ -202,17 +216,27 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
ENGINE(engineState.tpsAccelEnrich) = tpsAccelEnrich;
floatms_t baseFuel;
if (CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) {
baseFuel = getSpeedDensityFuel(getMap(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN sd baseFuel", 0);
} else if (engineConfiguration->fuelAlgorithm == LM_REAL_MAF) {
float maf = getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) + engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
baseFuel = getRealMafFuel(maf, rpm PASS_ENGINE_PARAMETER_SUFFIX);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN rm baseFuel", 0);
if ((CONFIG(fuelAlgorithm) == LM_SPEED_DENSITY) || (engineConfiguration->fuelAlgorithm == LM_REAL_MAF)) {
// airmass modes - get airmass first, then convert to fuel
auto airmass = getAirmass(rpm PASS_ENGINE_PARAMETER_SUFFIX);
// The airmass mode will tell us how to look up AFR - use the provided Y axis value
float targetAfr = afrMap.getValue(rpm, airmass.EngineLoadPercent);
// TODO: surface airmass.EngineLoadPercent to tunerstudio for proper display
// Plop some state for others to read
ENGINE(engineState.targetAFR) = targetAfr;
ENGINE(engineState.sd.airMassInOneCylinder) = airmass.CylinderAirmass;
baseFuel = getInjectionDurationForAirmass(airmass.CylinderAirmass, targetAfr PASS_ENGINE_PARAMETER_SUFFIX) * 1000;
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN baseFuel", 0);
} else {
baseFuel = engine->engineState.baseTableFuel;
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN bt baseFuel", 0);
}
engine->engineState.baseFuel = baseFuel;
return tpsAccelEnrich + baseFuel;

View File

@ -8,6 +8,7 @@
#pragma once
#include "engine.h"
#include "airmass.h"
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE);
@ -21,7 +22,7 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
*/
floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX);
floatms_t getRealMafFuel(float airMass, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
AirmassResult getRealMafAirmass(float airMass, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
floatms_t getBaseTableFuel(int rpm, float engineLoad);
float getBaroCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);

View File

@ -54,6 +54,7 @@ CONTROLLERS_INC=\
$(CONTROLLERS_DIR)/system \
$(CONTROLLERS_DIR)/system/timer \
$(CONTROLLERS_DIR)/algo \
$(CONTROLLERS_DIR)/algo/airmass \
$(CONTROLLERS_DIR)/engine_cycle \
$(CONTROLLERS_DIR)/trigger/decoders \
$(CONTROLLERS_DIR)/trigger \

View File

@ -131,7 +131,7 @@ float getCylinderAirMass(float volumetricEfficiency, float MAP, float tempK DECL
/**
* @return per cylinder injection time, in Milliseconds
*/
floatms_t getSpeedDensityFuel(float map DECLARE_ENGINE_PARAMETER_SUFFIX) {
AirmassResult getSpeedDensityAirmass(float map DECLARE_ENGINE_PARAMETER_SUFFIX) {
ScopePerf perf(PE::GetSpeedDensityFuel);
/**
@ -140,27 +140,29 @@ floatms_t getSpeedDensityFuel(float map DECLARE_ENGINE_PARAMETER_SUFFIX) {
float tChargeK = ENGINE(engineState.sd.tChargeK);
if (cisnan(tChargeK)) {
warning(CUSTOM_ERR_TCHARGE_NOT_READY2, "tChargeK not ready"); // this would happen before we have CLT reading for example
return 0;
return {};
}
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(map), "NaN map", 0);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(map), "NaN map", {});
engine->engineState.sd.manifoldAirPressureAccelerationAdjustment = engine->engineLoadAccelEnrichment.getEngineLoadEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
float adjustedMap = engine->engineState.sd.adjustedManifoldAirPressure = map + engine->engineState.sd.manifoldAirPressureAccelerationAdjustment;
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(adjustedMap), "NaN adjustedMap", 0);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(adjustedMap), "NaN adjustedMap", {});
float airMass = getCylinderAirMass(ENGINE(engineState.currentBaroCorrectedVE), adjustedMap, tChargeK PASS_ENGINE_PARAMETER_SUFFIX);
if (cisnan(airMass)) {
warning(CUSTOM_ERR_6685, "NaN airMass");
return 0;
return {};
}
#if EFI_PRINTF_FUEL_DETAILS
printf("map=%.2f adjustedMap=%.2f airMass=%.2f\t\n",
map, adjustedMap, engine->engineState.sd.adjustedManifoldAirPressure);
#endif /*EFI_PRINTF_FUEL_DETAILS */
engine->engineState.sd.airMassInOneCylinder = airMass;
return getInjectionDurationForAirmass(airMass, ENGINE(engineState.targetAFR) PASS_ENGINE_PARAMETER_SUFFIX) * 1000;
return {
airMass,
map, // AFR/VE table Y axis
};
}
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE) {

View File

@ -8,6 +8,7 @@
#pragma once
#include "engine.h"
#include "airmass.h"
#define gramm_second_to_cc_minute(gs) ((gs) / 0.0119997981)
#define cc_minute_to_gramm_second(ccm) ((ccm) * 0.0119997981)
@ -17,4 +18,4 @@ float getCylinderAirMass(float volumetricEfficiency, float MAP, float tempK DECL
void setDefaultVETable(DECLARE_ENGINE_PARAMETER_SIGNATURE);
void initSpeedDensity(DECLARE_ENGINE_PARAMETER_SIGNATURE);
floatms_t getSpeedDensityFuel(float map DECLARE_ENGINE_PARAMETER_SUFFIX);
AirmassResult getSpeedDensityAirmass(float map DECLARE_ENGINE_PARAMETER_SUFFIX);

View File

@ -25,7 +25,11 @@ TEST(misc, testMafFuelMath) {
setAfrMap(config->afrTable, 13);
EXPECT_NEAR(0.75 * 13.3547, getRealMafFuel(300, 6000 PASS_ENGINE_PARAMETER_SUFFIX), EPS4D);
auto airmass = getRealMafAirmass(200, 6000 PASS_ENGINE_PARAMETER_SUFFIX);
// Check results
EXPECT_NEAR(0.277777f * 0.75f, airmass.CylinderAirmass, EPS4D);
EXPECT_NEAR(70.9884, airmass.EngineLoadPercent, EPS4D);
}
TEST(misc, testFuelMap) {