hook up fuel trims (#3715)
* hook up fuel trims * pass all the params * store per-cylinder fuel mass directly * main trigger callback only touches per-cylinder, no banks! * test test test test * move UI to happy land * changelog
This commit is contained in:
parent
049dd5b22a
commit
ab3e3ac83f
|
@ -27,9 +27,12 @@ All notable user-facing or behavior-altering changes will be documented in this
|
|||
|
||||
## Month 202x Release - "Release Name"
|
||||
|
||||
### Added
|
||||
- Per-cylinder fuel trim tables
|
||||
|
||||
## December 2021 Release - "Cookie Exchange"
|
||||
|
||||
## Added
|
||||
### Added
|
||||
- Improved vehicle speed sensor configuration: now uses real physical constants about tires, gear ratio, sensor, etc.
|
||||
- Improved priming logic. Now includes a table of priming fuel mass vs. engine temperature, in addition to a delay before priming to allow fuel pressure to build. #3674
|
||||
- ISO-TP connector in firmware & ISO-TP to TCP/IP bridge in rusEFI console #3667
|
||||
|
|
|
@ -332,14 +332,12 @@ public:
|
|||
floatms_t injectionDuration = 0;
|
||||
|
||||
// Per-injection fuel mass, including TPS accel enrich
|
||||
float injectionMass[STFT_BANK_COUNT] = {0};
|
||||
float injectionMass[MAX_CYLINDER_COUNT] = {0};
|
||||
|
||||
float stftCorrection[STFT_BANK_COUNT] = {0};
|
||||
|
||||
/**
|
||||
* This one with wall wetting accounted for, used for logging.
|
||||
*/
|
||||
floatms_t actualLastInjection[STFT_BANK_COUNT] = {0};
|
||||
// Stores the actual pulse duration of the last injection for every cylinder
|
||||
floatms_t actualLastInjection[MAX_CYLINDER_COUNT] = {0};
|
||||
|
||||
// Standard cylinder air charge - 100% VE at standard temperature, grams per cylinder
|
||||
float standardAirCharge = 0;
|
||||
|
|
|
@ -151,13 +151,6 @@ void EngineState::periodicFastCallback() {
|
|||
float injectionMass = getInjectionMass(rpm);
|
||||
auto clResult = fuelClosedLoopCorrection();
|
||||
|
||||
// compute per-bank fueling
|
||||
for (size_t i = 0; i < STFT_BANK_COUNT; i++) {
|
||||
float corr = clResult.banks[i];
|
||||
engine->injectionMass[i] = injectionMass * corr;
|
||||
engine->stftCorrection[i] = corr;
|
||||
}
|
||||
|
||||
// Store the pre-wall wetting injection duration for scheduling purposes only, not the actual injection duration
|
||||
engine->injectionDuration = engine->module<InjectorModel>()->getInjectionDuration(injectionMass);
|
||||
|
||||
|
@ -167,7 +160,21 @@ void EngineState::periodicFastCallback() {
|
|||
float ignitionLoad = getIgnitionLoad();
|
||||
float advance = getAdvance(rpm, ignitionLoad) * luaAdjustments.ignitionTimingMult + luaAdjustments.ignitionTimingAdd;
|
||||
|
||||
// compute per-bank fueling
|
||||
for (size_t i = 0; i < STFT_BANK_COUNT; i++) {
|
||||
float corr = clResult.banks[i];
|
||||
engine->stftCorrection[i] = corr;
|
||||
}
|
||||
|
||||
// Now apply that to per-cylinder fueling and timing
|
||||
for (size_t i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
||||
uint8_t bankIndex = engineConfiguration->cylinderBankSelect[i];
|
||||
auto bankTrim =engine->stftCorrection[bankIndex];
|
||||
auto cylinderTrim = getCylinderFuelTrim(i, rpm, fuelLoad);
|
||||
|
||||
// Apply both per-bank and per-cylinder trims
|
||||
engine->injectionMass[i] = injectionMass * bankTrim * cylinderTrim;
|
||||
|
||||
timingAdvance[i] = advance;
|
||||
}
|
||||
|
||||
|
|
|
@ -431,5 +431,17 @@ float getStandardAirCharge() {
|
|||
return idealGasLaw(cylDisplacement, 101.325f, 273.15f + 20.0f);
|
||||
}
|
||||
|
||||
float getCylinderFuelTrim(size_t cylinderNumber, int rpm, float fuelLoad) {
|
||||
auto trimPercent = interpolate3d(
|
||||
config->fuelTrims[cylinderNumber].table,
|
||||
config->fuelTrimLoadBins, fuelLoad,
|
||||
config->fuelTrimRpmBins, rpm
|
||||
);
|
||||
|
||||
// Convert from percent +- to multiplier
|
||||
// 5% -> 1.05
|
||||
return (100 + trimPercent) / 100;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@ float getInjectionMass(int rpm);
|
|||
percent_t getInjectorDutyCycle(int rpm);
|
||||
|
||||
float getStandardAirCharge();
|
||||
float getCylinderFuelTrim(size_t cylinderNumber, int rpm, float fuelLoad);
|
||||
|
||||
struct AirmassModelBase;
|
||||
AirmassModelBase* getAirmassModel(engine_load_mode_e mode);
|
||||
|
|
|
@ -165,9 +165,8 @@ void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t now
|
|||
return;
|
||||
}
|
||||
|
||||
// Select fuel mass from the correct bank
|
||||
uint8_t bankIndex = engineConfiguration->cylinderBankSelect[this->cylinderNumber];
|
||||
float injectionMassGrams = engine->injectionMass[bankIndex];
|
||||
// Select fuel mass from the correct cylinder
|
||||
auto injectionMassGrams = engine->injectionMass[this->cylinderNumber];
|
||||
|
||||
// Perform wall wetting adjustment on fuel mass, not duration, so that
|
||||
// it's correct during fuel pressure (injector flow) or battery voltage (deadtime) transients
|
||||
|
@ -195,7 +194,7 @@ void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t now
|
|||
|
||||
engine->engineState.fuelConsumption.consumeFuel(injectionMassGrams * numberOfInjections, nowNt);
|
||||
|
||||
engine->actualLastInjection[bankIndex] = injectionDuration;
|
||||
engine->actualLastInjection[this->cylinderNumber] = injectionDuration;
|
||||
|
||||
if (cisnan(injectionDuration)) {
|
||||
warning(CUSTOM_OBD_NAN_INJECTION, "NaN injection pulse");
|
||||
|
|
|
@ -1286,6 +1286,21 @@ menuDialog = main
|
|||
subMenu = cylinderBankSelect, "Cylinder bank selection", 0, {isInjectionEnabled == 1}
|
||||
subMenu = injectorNonlinear, "Injector small-pulse correction", 0, {isInjectionEnabled == 1}
|
||||
; subMenu = fuelTrimSettings, "Fuel Trim", 0, {isInjectionEnabled == 1}
|
||||
|
||||
groupMenu = "Cylinder fuel trims"
|
||||
groupChildMenu = fuelTrimTbl1, "Fuel trim cyl 1"
|
||||
groupChildMenu = fuelTrimTbl2, "Fuel trim cyl 2"
|
||||
groupChildMenu = fuelTrimTbl3, "Fuel trim cyl 3"
|
||||
groupChildMenu = fuelTrimTbl4, "Fuel trim cyl 4"
|
||||
groupChildMenu = fuelTrimTbl5, "Fuel trim cyl 5"
|
||||
groupChildMenu = fuelTrimTbl6, "Fuel trim cyl 6"
|
||||
groupChildMenu = fuelTrimTbl7, "Fuel trim cyl 7"
|
||||
groupChildMenu = fuelTrimTbl8, "Fuel trim cyl 8"
|
||||
groupChildMenu = fuelTrimTbl9, "Fuel trim cyl 9"
|
||||
groupChildMenu = fuelTrimTbl10, "Fuel trim cyl 10"
|
||||
groupChildMenu = fuelTrimTbl11, "Fuel trim cyl 11"
|
||||
groupChildMenu = fuelTrimTbl12, "Fuel trim cyl 12"
|
||||
|
||||
subMenu = std_separator
|
||||
|
||||
# Air mass model
|
||||
|
@ -1500,20 +1515,6 @@ menuDialog = main
|
|||
# subMenu = antiLag, "Antilag Setup"
|
||||
# subMenu = std_separator
|
||||
|
||||
groupMenu = "Cylinder fuel trims"
|
||||
groupChildMenu = fuelTrimTbl1, "Fuel trim cyl 1"
|
||||
groupChildMenu = fuelTrimTbl2, "Fuel trim cyl 2"
|
||||
groupChildMenu = fuelTrimTbl3, "Fuel trim cyl 3"
|
||||
groupChildMenu = fuelTrimTbl4, "Fuel trim cyl 4"
|
||||
groupChildMenu = fuelTrimTbl5, "Fuel trim cyl 5"
|
||||
groupChildMenu = fuelTrimTbl6, "Fuel trim cyl 6"
|
||||
groupChildMenu = fuelTrimTbl7, "Fuel trim cyl 7"
|
||||
groupChildMenu = fuelTrimTbl8, "Fuel trim cyl 8"
|
||||
groupChildMenu = fuelTrimTbl9, "Fuel trim cyl 9"
|
||||
groupChildMenu = fuelTrimTbl10, "Fuel trim cyl 10"
|
||||
groupChildMenu = fuelTrimTbl11, "Fuel trim cyl 11"
|
||||
groupChildMenu = fuelTrimTbl12, "Fuel trim cyl 12"
|
||||
|
||||
groupMenu = "Cylinder ign trims"
|
||||
groupChildMenu = ignTrimTbl1, "Ignition trim cyl 1"
|
||||
groupChildMenu = ignTrimTbl2, "Ignition trim cyl 2"
|
||||
|
|
|
@ -178,3 +178,25 @@ TEST(FuelMath, deadtime) {
|
|||
engine->periodicFastCallback();
|
||||
EXPECT_FLOAT_EQ( 20 + 2, engine->injectionDuration);
|
||||
}
|
||||
|
||||
TEST(FuelMath, CylinderFuelTrim) {
|
||||
EngineTestHelper eth(TEST_ENGINE);
|
||||
|
||||
EXPECT_CALL(eth.mockAirmass, getAirmass(_))
|
||||
.WillRepeatedly(Return(AirmassResult{1, 50.0f}));
|
||||
|
||||
setTable(config->fuelTrims[0].table, -4);
|
||||
setTable(config->fuelTrims[1].table, -2);
|
||||
setTable(config->fuelTrims[2].table, 2);
|
||||
setTable(config->fuelTrims[3].table, 4);
|
||||
|
||||
// run the fuel math
|
||||
engine->periodicFastCallback();
|
||||
|
||||
// Check that each cylinder gets the expected amount of fuel
|
||||
float unadjusted = 0.072142f;
|
||||
EXPECT_NEAR(engine->injectionMass[0], unadjusted * 0.96, EPS4D);
|
||||
EXPECT_NEAR(engine->injectionMass[1], unadjusted * 0.98, EPS4D);
|
||||
EXPECT_NEAR(engine->injectionMass[2], unadjusted * 1.02, EPS4D);
|
||||
EXPECT_NEAR(engine->injectionMass[3], unadjusted * 1.04, EPS4D);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue