diff --git a/firmware/CHANGELOG.md b/firmware/CHANGELOG.md index 40e7a27afe..a050c8659d 100644 --- a/firmware/CHANGELOG.md +++ b/firmware/CHANGELOG.md @@ -30,7 +30,7 @@ Release template (copy/paste this for new release): ### Added - VVT minimum RPM setting #4545 - - Flexible ignition adder/trim tables #4586 + - Flexible ignition and VE adder/trim tables #4586 #4640 - Enforce board configuration overrides more strictly #4614 - rusEFI console Startup Frame should scan for available hardware #4633 - Don't fire the engine without the ignition on (avoids USB keeping engine alive after ignition off) #4474 diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index 95ace2fc1f..cdc89dfd58 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -335,7 +335,10 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 5, 2 uint8_t extiOverflowCount;;"", 1, 0, 0, 255, 0 uint8_t[IGN_BLEND_COUNT iterate] autoscale ignBlendBias;;"%", 0.5, 0, 0, 100, 1 - uint16_t[IGN_BLEND_COUNT iterate] autoscale ignBlendOutput;;"deg", 0.01, 0, -300, 300, 2 + int16_t[IGN_BLEND_COUNT iterate] autoscale ignBlendOutput;;"deg", 0.01, 0, -300, 300, 2 + + uint8_t[VE_BLEND_COUNT iterate] autoscale veBlendBias;;"%", 0.5, 0, 0, 100, 1 + int16_t[VE_BLEND_COUNT iterate] autoscale veBlendOutput;;"%", 0.01, 0, -50, 50, 2 bit coilState1 bit coilState2 diff --git a/firmware/controllers/algo/advance_map.cpp b/firmware/controllers/algo/advance_map.cpp index e018350611..a1326f06ca 100644 --- a/firmware/controllers/algo/advance_map.cpp +++ b/firmware/controllers/algo/advance_map.cpp @@ -30,32 +30,6 @@ // todo: reset this between cranking attempts?! #2735 int minCrankingRpm = 0; -struct BlendResult { - // Bias in percent (0-100%) - float Bias; - - // Result value (bias * table value) - float Value; -}; - -BlendResult calculateBlend(blend_table_s& cfg, float rpm, float load) { - auto value = readGppwmChannel(cfg.blendParameter); - - if (!value) { - return { 0, 0 }; - } - - float tableValue = interpolate3d( - cfg.table, - cfg.loadBins, load, - cfg.rpmBins, rpm - ); - - float blendFactor = interpolate2d(value.Value, cfg.blendBins, cfg.blendValues); - - return { blendFactor, 0.01f * blendFactor * tableValue }; -} - /** * @return ignition timing angle advance before TDC */ diff --git a/firmware/controllers/algo/airmass/airmass.cpp b/firmware/controllers/algo/airmass/airmass.cpp index c7f64a0bf5..4dec3151b3 100644 --- a/firmware/controllers/algo/airmass/airmass.cpp +++ b/firmware/controllers/algo/airmass/airmass.cpp @@ -35,6 +35,22 @@ float AirmassVeModelBase::getVe(int rpm, float load) const { ve = interpolateClamped(0.0f, idleVe, engineConfiguration->idlePidDeactivationTpsThreshold, ve, tps.Value); } + // Add any adjustments if configured + for (size_t i = 0; i < efi::size(config->veBlends); i++) { + auto result = calculateBlend(config->veBlends[i], rpm, load); + + engine->outputChannels.veBlendBias[i] = result.Bias; + engine->outputChannels.veBlendOutput[i] = result.Value; + + if (result.Value == 0) { + continue; + } + + // Apply as a multiplier, not as an adder + // Value of +5 means add 5%, aka multiply by 1.05 + ve *= ((100 + result.Value) * 0.01f); + } + engine->engineState.currentVe = ve; engine->engineState.currentVeLoad = load; return ve * PERCENT_DIV; diff --git a/firmware/controllers/math/engine_math.cpp b/firmware/controllers/math/engine_math.cpp index a7ccf0d05a..e18790fea9 100644 --- a/firmware/controllers/math/engine_math.cpp +++ b/firmware/controllers/math/engine_math.cpp @@ -24,6 +24,7 @@ #include "event_registry.h" #include "fuel_math.h" #include "advance_map.h" +#include "gppwm_channel.h" #if EFI_UNIT_TEST extern bool verboseMode; @@ -450,4 +451,27 @@ void setFlatInjectorLag(float value) { setArrayValues(engineConfiguration->injector.battLagCorr, value); } +BlendResult calculateBlend(blend_table_s& cfg, float rpm, float load) { + // If set to 0, skip the math as its disabled + if (cfg.blendParameter == GPPWM_Zero) { + return { 0, 0 }; + } + + auto value = readGppwmChannel(cfg.blendParameter); + + if (!value) { + return { 0, 0 }; + } + + float tableValue = interpolate3d( + cfg.table, + cfg.loadBins, load, + cfg.rpmBins, rpm + ); + + float blendFactor = interpolate2d(value.Value, cfg.blendBins, cfg.blendValues); + + return { blendFactor, 0.01f * blendFactor * tableValue }; +} + #endif /* EFI_ENGINE_CONTROL */ diff --git a/firmware/controllers/math/engine_math.h b/firmware/controllers/math/engine_math.h index 70e1e3d7f7..3fb9aa0384 100644 --- a/firmware/controllers/math/engine_math.h +++ b/firmware/controllers/math/engine_math.h @@ -67,3 +67,14 @@ void setSingleCoilDwell(); * an odd-fire engine (v-twin, V10, some v6, etc) */ angle_t getCylinderAngle(uint8_t cylinderIndex, uint8_t cylinderNumber); + +// Table blending helpers +struct BlendResult { + // Bias in percent (0-100%) + float Bias; + + // Result value (bias * table value) + float Value; +}; + +BlendResult calculateBlend(blend_table_s& cfg, float rpm, float load); diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 621802c6f2..86f37a4a30 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1751,6 +1751,9 @@ end_struct #define IGN_BLEND_COUNT 4 blend_table_s[IGN_BLEND_COUNT iterate] ignBlends +#define VE_BLEND_COUNT 4 +blend_table_s[VE_BLEND_COUNT iterate] veBlends + end_struct ! Pedal Position Sensor diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index b5dc755977..f7e52e9281 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -199,6 +199,11 @@ enable2ndByteCanID = false ignBlends3_blendVal = {(ignBlends3_blendParameter == 0) ? 0 : (ignBlends3_blendParameter == 1) ? TPSValue : (ignBlends3_blendParameter == 2) ? MAPValue : (ignBlends3_blendParameter == 3) ? coolant : (ignBlends3_blendParameter == 4) ? intake : (ignBlends3_blendParameter == 5) ? fuelingLoad : (ignBlends3_blendParameter == 6) ? ignitionLoad : (ignBlends3_blendParameter == 7) ? auxTemp1 : (ignBlends3_blendParameter == 8) ? auxTemp2 : (ignBlends3_blendParameter == 9) ? throttlePedalPosition : (ignBlends3_blendParameter == 10) ? VBatt : (ignBlends3_blendParameter == 11) ? vvtPositionB1I : (ignBlends3_blendParameter == 12) ? vvtPositionB1E : (ignBlends3_blendParameter == 13) ? vvtPositionB2I : (ignBlends3_blendParameter == 14) ? vvtPositionB2E : (ignBlends3_blendParameter == 15) ? flexPercent : (ignBlends3_blendParameter == 16) ? auxLinear1 : (ignBlends3_blendParameter == 17) ? auxLinear2 : 0} ignBlends4_blendVal = {(ignBlends4_blendParameter == 0) ? 0 : (ignBlends4_blendParameter == 1) ? TPSValue : (ignBlends4_blendParameter == 2) ? MAPValue : (ignBlends4_blendParameter == 3) ? coolant : (ignBlends4_blendParameter == 4) ? intake : (ignBlends4_blendParameter == 5) ? fuelingLoad : (ignBlends4_blendParameter == 6) ? ignitionLoad : (ignBlends4_blendParameter == 7) ? auxTemp1 : (ignBlends4_blendParameter == 8) ? auxTemp2 : (ignBlends4_blendParameter == 9) ? throttlePedalPosition : (ignBlends4_blendParameter == 10) ? VBatt : (ignBlends4_blendParameter == 11) ? vvtPositionB1I : (ignBlends4_blendParameter == 12) ? vvtPositionB1E : (ignBlends4_blendParameter == 13) ? vvtPositionB2I : (ignBlends4_blendParameter == 14) ? vvtPositionB2E : (ignBlends4_blendParameter == 15) ? flexPercent : (ignBlends4_blendParameter == 16) ? auxLinear1 : (ignBlends4_blendParameter == 17) ? auxLinear2 : 0} + veBlends1_blendVal = {(veBlends1_blendParameter == 0) ? 0 : (veBlends1_blendParameter == 1) ? TPSValue : (veBlends1_blendParameter == 2) ? MAPValue : (veBlends1_blendParameter == 3) ? coolant : (veBlends1_blendParameter == 4) ? intake : (veBlends1_blendParameter == 5) ? fuelingLoad : (veBlends1_blendParameter == 6) ? ignitionLoad : (veBlends1_blendParameter == 7) ? auxTemp1 : (veBlends1_blendParameter == 8) ? auxTemp2 : (veBlends1_blendParameter == 9) ? throttlePedalPosition : (veBlends1_blendParameter == 10) ? VBatt : (veBlends1_blendParameter == 11) ? vvtPositionB1I : (veBlends1_blendParameter == 12) ? vvtPositionB1E : (veBlends1_blendParameter == 13) ? vvtPositionB2I : (veBlends1_blendParameter == 14) ? vvtPositionB2E : (veBlends1_blendParameter == 15) ? flexPercent : (veBlends1_blendParameter == 16) ? auxLinear1 : (veBlends1_blendParameter == 17) ? auxLinear2 : 0} + veBlends2_blendVal = {(veBlends2_blendParameter == 0) ? 0 : (veBlends2_blendParameter == 1) ? TPSValue : (veBlends2_blendParameter == 2) ? MAPValue : (veBlends2_blendParameter == 3) ? coolant : (veBlends2_blendParameter == 4) ? intake : (veBlends2_blendParameter == 5) ? fuelingLoad : (veBlends2_blendParameter == 6) ? ignitionLoad : (veBlends2_blendParameter == 7) ? auxTemp1 : (veBlends2_blendParameter == 8) ? auxTemp2 : (veBlends2_blendParameter == 9) ? throttlePedalPosition : (veBlends2_blendParameter == 10) ? VBatt : (veBlends2_blendParameter == 11) ? vvtPositionB1I : (veBlends2_blendParameter == 12) ? vvtPositionB1E : (veBlends2_blendParameter == 13) ? vvtPositionB2I : (veBlends2_blendParameter == 14) ? vvtPositionB2E : (veBlends2_blendParameter == 15) ? flexPercent : (veBlends2_blendParameter == 16) ? auxLinear1 : (veBlends2_blendParameter == 17) ? auxLinear2 : 0} + veBlends3_blendVal = {(veBlends3_blendParameter == 0) ? 0 : (veBlends3_blendParameter == 1) ? TPSValue : (veBlends3_blendParameter == 2) ? MAPValue : (veBlends3_blendParameter == 3) ? coolant : (veBlends3_blendParameter == 4) ? intake : (veBlends3_blendParameter == 5) ? fuelingLoad : (veBlends3_blendParameter == 6) ? ignitionLoad : (veBlends3_blendParameter == 7) ? auxTemp1 : (veBlends3_blendParameter == 8) ? auxTemp2 : (veBlends3_blendParameter == 9) ? throttlePedalPosition : (veBlends3_blendParameter == 10) ? VBatt : (veBlends3_blendParameter == 11) ? vvtPositionB1I : (veBlends3_blendParameter == 12) ? vvtPositionB1E : (veBlends3_blendParameter == 13) ? vvtPositionB2I : (veBlends3_blendParameter == 14) ? vvtPositionB2E : (veBlends3_blendParameter == 15) ? flexPercent : (veBlends3_blendParameter == 16) ? auxLinear1 : (veBlends3_blendParameter == 17) ? auxLinear2 : 0} + veBlends4_blendVal = {(veBlends4_blendParameter == 0) ? 0 : (veBlends4_blendParameter == 1) ? TPSValue : (veBlends4_blendParameter == 2) ? MAPValue : (veBlends4_blendParameter == 3) ? coolant : (veBlends4_blendParameter == 4) ? intake : (veBlends4_blendParameter == 5) ? fuelingLoad : (veBlends4_blendParameter == 6) ? ignitionLoad : (veBlends4_blendParameter == 7) ? auxTemp1 : (veBlends4_blendParameter == 8) ? auxTemp2 : (veBlends4_blendParameter == 9) ? throttlePedalPosition : (veBlends4_blendParameter == 10) ? VBatt : (veBlends4_blendParameter == 11) ? vvtPositionB1I : (veBlends4_blendParameter == 12) ? vvtPositionB1E : (veBlends4_blendParameter == 13) ? vvtPositionB2I : (veBlends4_blendParameter == 14) ? vvtPositionB2E : (veBlends4_blendParameter == 15) ? flexPercent : (veBlends4_blendParameter == 16) ? auxLinear1 : (veBlends4_blendParameter == 17) ? auxLinear2 : 0} + wbo0_hasFault = { enableAemXSeries && (faultCode >= 3) } [PcVariables] @@ -736,6 +741,34 @@ curve = 32Curve, "3-2 Shift Solenoid Percent by Speed" xBins = ignBlends4_blendBins, ignBlends4_blendVal yBins = ignBlends4_blendValues + curve = veBlend1Bias, "VE blend 1 bias" + columnLabel = "param", "bias" + xAxis = 0, 100, 11 + yAxis = 0, 100, 5 + xBins = veBlends1_blendBins, veBlends1_blendVal + yBins = veBlends1_blendValues + + curve = veBlend2Bias, "VE blend 2 bias" + columnLabel = "param", "bias" + xAxis = 0, 100, 11 + yAxis = 0, 100, 5 + xBins = veBlends2_blendBins, veBlends2_blendVal + yBins = veBlends2_blendValues + + curve = veBlend3Bias, "VE blend 3 bias" + columnLabel = "param", "bias" + xAxis = 0, 100, 11 + yAxis = 0, 100, 5 + xBins = veBlends3_blendBins, veBlends3_blendVal + yBins = veBlends3_blendValues + + curve = veBlend4Bias, "VE blend 4 bias" + columnLabel = "param", "bias" + xAxis = 0, 100, 11 + yAxis = 0, 100, 5 + xBins = veBlends4_blendBins, veBlends4_blendVal + yBins = veBlends4_blendValues + [TableEditor] ; table_id, map3d_id, "title", page @@ -829,6 +862,30 @@ curve = 32Curve, "3-2 Shift Solenoid Percent by Speed" zBins = ignBlends4_table gridOrient = 250, 0, 340 + table = veBlend1Table, veBlend1Map, "VE blend 1", 1 + xBins = veBlends1_rpmBins, RPMValue + yBins = veBlends1_loadBins, fuelingLoad + zBins = veBlends1_table + gridOrient = 250, 0, 340 + + table = veBlend2Table, veBlend2Map, "VE blend 2", 1 + xBins = veBlends2_rpmBins, RPMValue + yBins = veBlends2_loadBins, fuelingLoad + zBins = veBlends2_table + gridOrient = 250, 0, 340 + + table = veBlend3Table, veBlend3Map, "VE blend 3", 1 + xBins = veBlends3_rpmBins, RPMValue + yBins = veBlends3_loadBins, fuelingLoad + zBins = veBlends3_table + gridOrient = 250, 0, 340 + + table = veBlend4Table, veBlend4Map, "VE blend 4", 1 + xBins = veBlends4_rpmBins, RPMValue + yBins = veBlends4_loadBins, fuelingLoad + zBins = veBlends4_table + gridOrient = 250, 0, 340 + table = ignitionIatCorrTableTbl, ignitionIatCorrTableMap, "Ignition Intake Air Temp correction", 1 ; constant, variable xBins = ignitionIatCorrRpmBins, RPMValue @@ -1520,6 +1577,17 @@ menuDialog = main # Air mass model subMenu = veTableDialog, "VE", 0, {isInjectionEnabled == 1} + + groupMenu = "VE blend tables" + groupChildMenu = veBlend1Cfg, "Adder 1 bias", 0, {isInjectionEnabled} + groupChildMenu = veBlend1Table, "Ignition adder 1", 0, { isInjectionEnabled && veBlends1_blendParameter != 0 } + groupChildMenu = veBlend2Cfg, "Adder 2 bias", 0, {isInjectionEnabled} + groupChildMenu = veBlend2Table, "Ignition adder 2", 0, { isInjectionEnabled && veBlends2_blendParameter != 0 } + groupChildMenu = veBlend3Cfg, "Adder 3 bias", 0, {isInjectionEnabled} + groupChildMenu = veBlend3Table, "Ignition adder 3", 0, { isInjectionEnabled && veBlends3_blendParameter != 0 } + groupChildMenu = veBlend4Cfg, "Adder 4 bias", 0, {isInjectionEnabled} + groupChildMenu = veBlend4Table, "Ignition adder 4", 0, { isInjectionEnabled && veBlends4_blendParameter != 0 } + subMenu = tChargeSettings, "Charge temperature estimation", 0, {isInjectionEnabled == 1} subMenu = baroCorrTbl, "Barometric pressure correction", 0, {isInjectionEnabled == 1 && fuelAlgorithm == @@engine_load_mode_e_LM_SPEED_DENSITY@@} subMenu = mapEstimateTableTbl, "MAP estimate table", 0, { enableMapEstimationTableFallback } @@ -1559,15 +1627,15 @@ menuDialog = main subMenu = ignitionTableTbl, "Ignition advance", 0, {isIgnitionEnabled} - groupMenu = "Ignition Adders" - groupChildMenu = ignAdder1Cfg, "Adder 1 bias" - groupChildMenu = ignAdder1Table, "Ignition adder 1", 0, { ignBlends1_blendParameter != 0 } - groupChildMenu = ignAdder2Cfg, "Adder 2 bias" - groupChildMenu = ignAdder2Table, "Ignition adder 2", 0, { ignBlends2_blendParameter != 0 } - groupChildMenu = ignAdder3Cfg, "Adder 3 bias" - groupChildMenu = ignAdder3Table, "Ignition adder 3", 0, { ignBlends3_blendParameter != 0 } - groupChildMenu = ignAdder4Cfg, "Adder 4 bias" - groupChildMenu = ignAdder4Table, "Ignition adder 4", 0, { ignBlends4_blendParameter != 0 } + groupMenu = "Ignition blend tables" + groupChildMenu = ignAdder1Cfg, "Adder 1 bias", 0, {isIgnitionEnabled} + groupChildMenu = ignAdder1Table, "Ignition adder 1", 0, { isIgnitionEnabled && ignBlends1_blendParameter != 0 } + groupChildMenu = ignAdder2Cfg, "Adder 2 bias", 0, {isIgnitionEnabled} + groupChildMenu = ignAdder2Table, "Ignition adder 2", 0, { isIgnitionEnabled && ignBlends2_blendParameter != 0 } + groupChildMenu = ignAdder3Cfg, "Adder 3 bias", 0, {isIgnitionEnabled} + groupChildMenu = ignAdder3Table, "Ignition adder 3", 0, { isIgnitionEnabled && ignBlends3_blendParameter != 0 } + groupChildMenu = ignAdder4Cfg, "Adder 4 bias", 0, {isIgnitionEnabled} + groupChildMenu = ignAdder4Table, "Ignition adder 4", 0, { isIgnitionEnabled && ignBlends4_blendParameter != 0 } groupMenu = "Cylinder ign trims" groupChildMenu = ignTrimTbl1, "Ignition trim cyl 1" @@ -2316,6 +2384,22 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_ field = "Blend parameter", ignBlends4_blendParameter panel = ignAdder4Bias + dialog = veBlend1Cfg, "VE blend 1 config" + field = "Blend parameter", veBlends1_blendParameter + panel = veBlend2Bias + + dialog = veBlend2Cfg, "VE blend 2 config" + field = "Blend parameter", veBlends2_blendParameter + panel = veBlend2Bias + + dialog = veBlend3Cfg, "VE blend 3 config" + field = "Blend parameter", veBlends3_blendParameter + panel = veBlend3Bias + + dialog = veBlend4Cfg, "VE blend 4 config" + field = "Blend parameter", veBlends4_blendParameter + panel = veBlend4Bias + dialog = dwellSettings, "", yAxis panel = dwellCorrection panel = dwellVoltageCorrection