Selectable VE axis override (#1769)
* add config fields * config options * new output channels * dump out state to ts * s * implement override * enums * this test is no longer used * test new behavior * old * comments
This commit is contained in:
parent
141cad585c
commit
ef0b2f7be0
|
@ -158,8 +158,11 @@ typedef struct {
|
||||||
scaled_percent fuelTankLevel; // 98
|
scaled_percent fuelTankLevel; // 98
|
||||||
float fuelConsumptionPerHour; // 100
|
float fuelConsumptionPerHour; // 100
|
||||||
|
|
||||||
|
// Y axis values for selectable tables
|
||||||
|
scaled_channel<uint16_t, 100> veTableYAxis; // 104
|
||||||
|
scaled_channel<uint16_t, 100> afrTableYAxis; // 106
|
||||||
|
|
||||||
// Knock
|
// Knock
|
||||||
uint32_t knockCount; // 104
|
|
||||||
float knockLevel; // 108
|
float knockLevel; // 108
|
||||||
|
|
||||||
// Mode, firmware, protocol, run time
|
// Mode, firmware, protocol, run time
|
||||||
|
|
|
@ -532,6 +532,8 @@ void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels DECLARE_
|
||||||
|
|
||||||
tsOutputChannels->fuelingLoad = getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
tsOutputChannels->fuelingLoad = getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
tsOutputChannels->ignitionLoad = getIgnitionLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
tsOutputChannels->ignitionLoad = getIgnitionLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
tsOutputChannels->veTableYAxis = ENGINE(engineState.currentVeLoad);
|
||||||
|
tsOutputChannels->afrTableYAxis = ENGINE(engineState.currentAfrLoad);
|
||||||
|
|
||||||
// KLUDGE? we always show VBatt because Proteus board has VBatt input sensor hardcoded
|
// KLUDGE? we always show VBatt because Proteus board has VBatt input sensor hardcoded
|
||||||
// offset 28
|
// offset 28
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
#include "airmass.h"
|
#include "airmass.h"
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
EXTERN_ENGINE;
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
AirmassModelBase::AirmassModelBase(const ValueProvider3D& veTable) : m_veTable(&veTable) {}
|
AirmassModelBase::AirmassModelBase(const ValueProvider3D& veTable) : m_veTable(&veTable) {}
|
||||||
|
|
||||||
|
float AirmassModelBase::getVeLoadAxis(float passedLoad) const {
|
||||||
|
switch(CONFIG(veOverrideMode)) {
|
||||||
|
case VE_None: return passedLoad;
|
||||||
|
case VE_MAP: return getMap(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
case VE_TPS: return Sensor::get(SensorType::Tps1).value_or(0);
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float AirmassModelBase::getVe(int rpm, float load) const {
|
float AirmassModelBase::getVe(int rpm, float load) const {
|
||||||
efiAssert(OBD_PCM_Processor_Fault, m_veTable != nullptr, "VE table null", 0);
|
efiAssert(OBD_PCM_Processor_Fault, m_veTable != nullptr, "VE table null", 0);
|
||||||
|
|
||||||
// TODO: allow override of the Y axis value based on a config field
|
// Override the load value if necessary
|
||||||
|
load = getVeLoadAxis(load);
|
||||||
|
|
||||||
float ve = m_veTable->getValue(rpm, load);
|
float ve = m_veTable->getValue(rpm, load);
|
||||||
|
|
||||||
auto tps = Sensor::get(SensorType::Tps1);
|
auto tps = Sensor::get(SensorType::Tps1);
|
||||||
|
@ -20,5 +32,6 @@ float AirmassModelBase::getVe(int rpm, float load) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ENGINE(engineState.currentVe) = ve;
|
ENGINE(engineState.currentVe) = ve;
|
||||||
|
ENGINE(engineState.currentVeLoad) = load;
|
||||||
return ve * 0.01f;
|
return ve * 0.01f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,6 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ValueProvider3D* const m_veTable;
|
const ValueProvider3D* const m_veTable;
|
||||||
|
|
||||||
|
float getVeLoadAxis(float passedLoad) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,6 +60,8 @@ public:
|
||||||
efitick_t timeSinceLastTChargeK;
|
efitick_t timeSinceLastTChargeK;
|
||||||
|
|
||||||
float currentVe = 0;
|
float currentVe = 0;
|
||||||
|
float currentVeLoad = 0;
|
||||||
|
float currentAfrLoad = 0;
|
||||||
|
|
||||||
int vssEventCounter = 0;
|
int vssEventCounter = 0;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ mass_t FuelComputerBase::getCycleFuel(mass_t airmass, int rpm, float load) const
|
||||||
float lambda = getTargetLambda(rpm, load);
|
float lambda = getTargetLambda(rpm, load);
|
||||||
float afr = stoich * lambda;
|
float afr = stoich * lambda;
|
||||||
|
|
||||||
|
// TODO: override target AFR load axis value
|
||||||
|
ENGINE(engineState.currentAfrLoad) = load;
|
||||||
ENGINE(engineState.targetAFR) = afr;
|
ENGINE(engineState.targetAFR) = afr;
|
||||||
|
|
||||||
return airmass / afr;
|
return airmass / afr;
|
||||||
|
|
|
@ -983,3 +983,17 @@ typedef enum __attribute__ ((__packed__)) {
|
||||||
GPPWM_GreaterThan = 0,
|
GPPWM_GreaterThan = 0,
|
||||||
GPPWM_LessThan = 1,
|
GPPWM_LessThan = 1,
|
||||||
} gppwm_compare_mode_e;
|
} gppwm_compare_mode_e;
|
||||||
|
|
||||||
|
typedef enum __attribute__ ((__packed__)) {
|
||||||
|
VE_None = 0,
|
||||||
|
VE_MAP = 1,
|
||||||
|
VE_TPS = 2,
|
||||||
|
} ve_override_e;
|
||||||
|
|
||||||
|
typedef enum __attribute__ ((__packed__)) {
|
||||||
|
AFR_None = 0,
|
||||||
|
AFR_MAP = 1,
|
||||||
|
AFR_Tps = 2,
|
||||||
|
AFR_AccPedal = 3,
|
||||||
|
AFR_CylFilling = 4,
|
||||||
|
} afr_override_e;
|
||||||
|
|
|
@ -761,7 +761,7 @@ bit is_enabled_spi_2
|
||||||
bit useIacTableForCoasting;+This setting allows the ECU to open the IAC during overrun conditions to help reduce engine breaking, this can be helpful for large engines in light weight cars. Used in Auto-PID Idle mode.
|
bit useIacTableForCoasting;+This setting allows the ECU to open the IAC during overrun conditions to help reduce engine breaking, this can be helpful for large engines in light weight cars. Used in Auto-PID Idle mode.
|
||||||
bit useNoiselessTriggerDecoder
|
bit useNoiselessTriggerDecoder
|
||||||
bit useIdleTimingPidControl
|
bit useIdleTimingPidControl
|
||||||
bit useTPSBasedVeTable
|
bit unused744b25
|
||||||
bit is_enabled_spi_4
|
bit is_enabled_spi_4
|
||||||
bit pauseEtbControl;+Disable the electronic throttle motor and DC idle motor for testing.\nThis mode is for testing ETB/DC idle position sensors, etc without actually driving the throttle.
|
bit pauseEtbControl;+Disable the electronic throttle motor and DC idle motor for testing.\nThis mode is for testing ETB/DC idle position sensors, etc without actually driving the throttle.
|
||||||
bit alignEngineSnifferAtTDC
|
bit alignEngineSnifferAtTDC
|
||||||
|
@ -1155,9 +1155,16 @@ int16_t tps2Max;Full throttle#2. tpsMax value as 10 bit ADC value. Not Voltage!\
|
||||||
#define can_baudrate_e_enum "100kbps", "250kbps" , "500kbps", "1Mbps"
|
#define can_baudrate_e_enum "100kbps", "250kbps" , "500kbps", "1Mbps"
|
||||||
custom can_baudrate_e 1 bits, U08, @OFFSET@, [0:1], @@can_baudrate_e_enum@@
|
custom can_baudrate_e 1 bits, U08, @OFFSET@, [0:1], @@can_baudrate_e_enum@@
|
||||||
can_baudrate_e canBaudRate; set can_baudrate
|
can_baudrate_e canBaudRate; set can_baudrate
|
||||||
uint8_t un1used_former_warmup_target_afr;;"units", 1, 0, -20, 100, 0
|
|
||||||
|
#define ve_override_e_enum "None", "MAP", "TPS"
|
||||||
|
custom ve_override_e 1 bits, U08, @OFFSET@, [0:1] @@ve_override_e_enum@@
|
||||||
|
ve_override_e veOverrideMode;+Override the Y axis (load) value used for the VE table.\nAdvanced users only: If you aren't sure you need this, you probably don't need this.
|
||||||
|
|
||||||
can_baudrate_e can2BaudRate;
|
can_baudrate_e can2BaudRate;
|
||||||
uint8_t unused_former_warmup_target_afr2;;"units", 1, 0, -20, 100, 0
|
|
||||||
|
#define afr_override_e_enum "None", "MAP", "TPS", "Acc Pedal", "Cyl Filling %"
|
||||||
|
custom afr_override_e 1 bits, U08, @OFFSET@, [0:2], @@afr_override_e_enum@@
|
||||||
|
afr_override_e afrOverrideMode;+Override the Y axis (load) value used for the AFR table.\nAdvanced users only: If you aren't sure you need this, you probably don't need this.
|
||||||
|
|
||||||
uint32_t verboseCan2BaseAddress;;"", 1, 0, 0, 536870911, 0
|
uint32_t verboseCan2BaseAddress;;"", 1, 0, 0, 536870911, 0
|
||||||
bit enableVerboseCan2Tx;+CAN broadcast using custom rusEFI protocol\nenable can_broadcast/disable can_broadcast
|
bit enableVerboseCan2Tx;+CAN broadcast using custom rusEFI protocol\nenable can_broadcast/disable can_broadcast
|
||||||
|
|
|
@ -267,8 +267,11 @@ enable2ndByteCanID = false
|
||||||
fuelTankLevel = scalar, S16, 98, "amount",{1/@@PACK_MULT_PERCENT@@}, 0
|
fuelTankLevel = scalar, S16, 98, "amount",{1/@@PACK_MULT_PERCENT@@}, 0
|
||||||
fuelConsumptionPerHour=scalar,F32, 100, "kPa", 1, 0.0
|
fuelConsumptionPerHour=scalar,F32, 100, "kPa", 1, 0.0
|
||||||
|
|
||||||
|
; Y axis values for selectable tables
|
||||||
|
veTableYAxis = scalar, U16, 104, "%", 0.01, 0
|
||||||
|
afrTableYAxis = scalar, U16, 106, "%", 0.01, 0
|
||||||
|
|
||||||
; Knock
|
; Knock
|
||||||
knockCount = scalar, U32, 104,"counter", 1, 0
|
|
||||||
knockLevel = scalar, F32, 108, "Volts", 1, 0
|
knockLevel = scalar, F32, 108, "Volts", 1, 0
|
||||||
|
|
||||||
; Mode, firmware, protocol, run time
|
; Mode, firmware, protocol, run time
|
||||||
|
@ -787,7 +790,7 @@ enable2ndByteCanID = false
|
||||||
table = veTableTbl, veTableMap, "VE Table", 1
|
table = veTableTbl, veTableMap, "VE Table", 1
|
||||||
; constant, variable
|
; constant, variable
|
||||||
xBins = veRpmBins, RPMValue
|
xBins = veRpmBins, RPMValue
|
||||||
yBins = veLoadBins, fuelingLoad
|
yBins = veLoadBins, veTableYAxis
|
||||||
zBins = veTable
|
zBins = veTable
|
||||||
; gridHeight = 2.0
|
; gridHeight = 2.0
|
||||||
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
|
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
|
||||||
|
@ -817,7 +820,7 @@ enable2ndByteCanID = false
|
||||||
table = afrTableTbl, afrTableMap, "Target AFR Table", 1
|
table = afrTableTbl, afrTableMap, "Target AFR Table", 1
|
||||||
; constant, variable
|
; constant, variable
|
||||||
xBins = afrRpmBins, RPMValue
|
xBins = afrRpmBins, RPMValue
|
||||||
yBins = afrLoadBins, fuelingLoad
|
yBins = afrLoadBins, afrTableYAxis
|
||||||
zBins = afrTable
|
zBins = afrTable
|
||||||
; gridHeight = 2.0
|
; gridHeight = 2.0
|
||||||
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
|
gridOrient = 250, 0, 340 ; Space 123 rotation of grid in degrees.
|
||||||
|
@ -868,7 +871,6 @@ gaugeCategory = Sensors - Extra 2
|
||||||
egt7Gauge = egt7, "EGT#7", "C", 0, 2000
|
egt7Gauge = egt7, "EGT#7", "C", 0, 2000
|
||||||
egt8Gauge = egt8, "EGT#8", "C", 0, 2000
|
egt8Gauge = egt8, "EGT#8", "C", 0, 2000
|
||||||
rpmAccelerationGa = rpmAcceleration, "rpm delta", "dRpm", 0, 3, 0, 1, 3, 4, 1, 1
|
rpmAccelerationGa = rpmAcceleration, "rpm delta", "dRpm", 0, 3, 0, 1, 3, 4, 1, 1
|
||||||
knockCountGauge = knockCount,"Knock count", "count", 0, 120, 10, 10, 100, 100, 1, 1
|
|
||||||
knockLevelGauge = knockLevel,"Knock level", "volts", 0, 7, 10, 10, 100, 100, 1, 2
|
knockLevelGauge = knockLevel,"Knock level", "volts", 0, 7, 10, 10, 100, 100, 1, 2
|
||||||
fuelTankLevelGauge = fuelTankLevel,"Fuel level", "x", 0, 7, 10, 10, 100, 100, 1, 2
|
fuelTankLevelGauge = fuelTankLevel,"Fuel level", "x", 0, 7, 10, 10, 100, 100, 1, 2
|
||||||
speedToRpmRatioGauge = speedToRpmRatio, "speed2rpm", "", 0, 100, 0, 0, 100, 100, 4, 4
|
speedToRpmRatioGauge = speedToRpmRatio, "speed2rpm", "", 0, 100, 0, 0, 100, 100, 4, 4
|
||||||
|
@ -1101,7 +1103,6 @@ gaugeCategory = Knock
|
||||||
entry = ignitionLoad, @@GAUGE_NAME_IGNITION_LOAD@@, float, "%.1f"
|
entry = ignitionLoad, @@GAUGE_NAME_IGNITION_LOAD@@, float, "%.1f"
|
||||||
entry = ignitionAdvance, @@GAUGE_NAME_TIMING_ADVANCE@@, float, "%.2f"
|
entry = ignitionAdvance, @@GAUGE_NAME_TIMING_ADVANCE@@, float, "%.2f"
|
||||||
entry = knockLevel, @@GAUGE_NAME_KNOCK_LEVEL@@, float, "%.2f"
|
entry = knockLevel, @@GAUGE_NAME_KNOCK_LEVEL@@, float, "%.2f"
|
||||||
entry = knockCount, @@GAUGE_NAME_KNOCK_COUNTER@@, int, "%d"
|
|
||||||
entry = vehicleSpeedKph, @@GAUGE_NAME_VVS@@, float, "%.2f"
|
entry = vehicleSpeedKph, @@GAUGE_NAME_VVS@@, float, "%.2f"
|
||||||
entry = speedToRpmRatio, "s2rpm", float, "%.3f"
|
entry = speedToRpmRatio, "s2rpm", float, "%.3f"
|
||||||
entry = rpmAcceleration, "dRPM", float, "%.3f"
|
entry = rpmAcceleration, "dRPM", float, "%.3f"
|
||||||
|
@ -1578,7 +1579,9 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00"
|
||||||
field = "Mode", injectionMode, {isInjectionEnabled == 1}
|
field = "Mode", injectionMode, {isInjectionEnabled == 1}
|
||||||
field = "#Batch injection with individual wiring"
|
field = "#Batch injection with individual wiring"
|
||||||
field = "Two wire batch emulation", twoWireBatchInjection, {isInjectionEnabled == 1 && injectionMode == 2}
|
field = "Two wire batch emulation", twoWireBatchInjection, {isInjectionEnabled == 1 && injectionMode == 2}
|
||||||
field = "Use TPS instead of Load for VE table", useTPSBasedVeTable, {isInjectionEnabled == 1 && fuelAlgorithm == LM_SPEED_DENSITY}
|
field = "Override VE table load axis", veOverrideMode, { isInjectionEnabled }
|
||||||
|
;field = "Override AFR table load axis", afrOverrideMode, { isInjectionEnabled }
|
||||||
|
; ^^^ Not yet implemented, hidden for now! ^^^
|
||||||
|
|
||||||
dialog = ignitionOutputs, "Ignition Outputs"
|
dialog = ignitionOutputs, "Ignition Outputs"
|
||||||
field = "Ignition Pin Mode", ignitionPinMode, {isIgnitionEnabled == 1}
|
field = "Ignition Pin Mode", ignitionPinMode, {isIgnitionEnabled == 1}
|
||||||
|
|
|
@ -202,37 +202,3 @@ TEST(misc, testPinHelper) {
|
||||||
ASSERT_EQ(0, getElectricalValue(1, OM_INVERTED));
|
ASSERT_EQ(0, getElectricalValue(1, OM_INVERTED));
|
||||||
ASSERT_EQ(1, getElectricalValue(0, OM_INVERTED));
|
ASSERT_EQ(1, getElectricalValue(0, OM_INVERTED));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fuel_Map3D_t veMap;
|
|
||||||
|
|
||||||
TEST(fuel, testTpsBasedVeDefect799) {
|
|
||||||
|
|
||||||
WITH_ENGINE_TEST_HELPER(FORD_ASPIRE_1996);
|
|
||||||
|
|
||||||
engineConfiguration->fuelAlgorithm = LM_SPEED_DENSITY;
|
|
||||||
CONFIG(useTPSBasedVeTable) = true;
|
|
||||||
|
|
||||||
int mapFrom = 100;
|
|
||||||
// set MAP axis range
|
|
||||||
setLinearCurve(config->veLoadBins, mapFrom, mapFrom + FUEL_LOAD_COUNT - 1, 1);
|
|
||||||
|
|
||||||
// RPM does not matter - set table values to match load axis
|
|
||||||
for (int load = 0; load < FUEL_LOAD_COUNT;load++) {
|
|
||||||
for (int rpmIndex = 0;rpmIndex < FUEL_RPM_COUNT;rpmIndex++) {
|
|
||||||
veMap.pointers[load][rpmIndex] = mapFrom + load;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// just validating that we set 3D map as we wanted
|
|
||||||
ASSERT_EQ(107, veMap.getValue(2000, 107));
|
|
||||||
|
|
||||||
// set TPS axis range which does not overlap MAP range for this test
|
|
||||||
setLinearCurve(CONFIG(ignitionTpsBins), 0, 15, 1);
|
|
||||||
|
|
||||||
engine->mockMapValue = 107;
|
|
||||||
Sensor::setMockValue(SensorType::Tps1, 7);
|
|
||||||
|
|
||||||
engine->engineState.periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
||||||
// value in the middle of the map as expected
|
|
||||||
ASSERT_EQ(107, engine->engineState.currentVe);
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
using ::testing::StrictMock;
|
using ::testing::StrictMock;
|
||||||
using ::testing::FloatNear;
|
using ::testing::FloatNear;
|
||||||
|
using ::testing::InSequence;
|
||||||
|
using ::testing::_;
|
||||||
|
|
||||||
TEST(FuelMath, getStandardAirCharge) {
|
TEST(FuelMath, getStandardAirCharge) {
|
||||||
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
|
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
|
||||||
|
@ -98,3 +100,41 @@ TEST(AirmassModes, MafNormal) {
|
||||||
EXPECT_NEAR(0.277777f * 0.75f, airmass.CylinderAirmass, EPS4D);
|
EXPECT_NEAR(0.277777f * 0.75f, airmass.CylinderAirmass, EPS4D);
|
||||||
EXPECT_NEAR(70.9814f, airmass.EngineLoadPercent, EPS4D);
|
EXPECT_NEAR(70.9814f, airmass.EngineLoadPercent, EPS4D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AirmassModes, VeOverride) {
|
||||||
|
StrictMock<MockVp3d> veTable;
|
||||||
|
|
||||||
|
{
|
||||||
|
InSequence is;
|
||||||
|
|
||||||
|
// Default
|
||||||
|
EXPECT_CALL(veTable, getValue(_, 10.0f)).WillOnce(Return(0));
|
||||||
|
// TPS
|
||||||
|
EXPECT_CALL(veTable, getValue(_, 30.0f)).WillOnce(Return(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DummyAirmassModel : public AirmassModelBase {
|
||||||
|
DummyAirmassModel(const ValueProvider3D& veTable) : AirmassModelBase(veTable) {}
|
||||||
|
|
||||||
|
AirmassResult getAirmass(int rpm) override {
|
||||||
|
// Default load value 10, will be overriden
|
||||||
|
getVe(rpm, 10.0f);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
|
||||||
|
DummyAirmassModel dut(veTable);
|
||||||
|
INJECT_ENGINE_REFERENCE(&dut);
|
||||||
|
|
||||||
|
// Use default mode - will call with 10
|
||||||
|
dut.getAirmass(0);
|
||||||
|
EXPECT_FLOAT_EQ(ENGINE(engineState.currentVeLoad), 10.0f);
|
||||||
|
|
||||||
|
// Override to TPS
|
||||||
|
CONFIG(veOverrideMode) = VE_TPS;
|
||||||
|
Sensor::setMockValue(SensorType::Tps1, 30.0f);
|
||||||
|
dut.getAirmass(0);
|
||||||
|
EXPECT_FLOAT_EQ(ENGINE(engineState.currentVeLoad), 30.0f);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue