convert mass -> duration later in the pipeline (#1906)

* cranking duration to mass

* implement

* units

* patch types

* suppress warning

* fix output channels

* add note about how to set it
This commit is contained in:
Matthew Kennedy 2020-10-26 04:23:13 -07:00 committed by GitHub
parent ac9b8fee45
commit a90792fa44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 59 additions and 74 deletions

View File

@ -113,12 +113,12 @@ typedef struct {
// Fuel math
scaled_channel<uint16_t, 1000> chargeAirMass; // 44 cylinder airmass in mg, 0-65 grams
scaled_ms crankingFuelMs; // 46
scaled_fuel_mass_mg crankingFuelMass; // 46
scaled_afr currentTargetAfr; // 48
// This is the raw value we take from the fuel map or base fuel algorithm, before the corrections
scaled_fuel_mass_mg fuelBase; // 50
// Total fuel with CLT, IAT and TPS acceleration without injector lag corrections per cycle, as pulse per cycle
scaled_ms fuelRunning; // 52
scaled_fuel_mass_mg fuelRunning; // 52
// Actual last injection time - including all compensation and injection mode
scaled_ms actualLastInjection; // 54
scaled_channel<uint8_t, 2> injectorDutyCycle; // 56

View File

@ -720,7 +720,7 @@ void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels DECLARE_
tsOutputChannels->ignitionAdvance = timing > 360 ? timing - 720 : timing;
// 60
tsOutputChannels->sparkDwell = ENGINE(engineState.sparkDwell);
tsOutputChannels->crankingFuelMs = ENGINE(engineState.cranking.fuel);
tsOutputChannels->crankingFuelMass = ENGINE(engineState.cranking.fuel);
tsOutputChannels->chargeAirMass = engine->engineState.sd.airMassInOneCylinder;
tsOutputChannels->coilDutyCycle = getCoilDutyCycle(rpm PASS_ENGINE_PARAMETER_SUFFIX);

View File

@ -901,7 +901,7 @@ static void setDefaultEngineConfiguration(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
* Cranking defaults
*/
engineConfiguration->startUpFuelPumpDuration = 4;
engineConfiguration->cranking.baseFuel = 5;
engineConfiguration->cranking.baseFuel = 12;
engineConfiguration->crankingChargeAngle = 70;

View File

@ -38,5 +38,11 @@ float InjectorModelBase::getInjectionDuration(float fuelMassGram) const {
// TODO: support injector nonlinearity correction
floatms_t baseDuration = fuelMassGram / m_massFlowRate * 1000;
return baseDuration + m_deadtime;
if (baseDuration <= 0) {
// If 0 duration, don't add deadtime, just skip the injection.
return 0.0f;
} else {
return baseDuration + m_deadtime;
}
}

View File

@ -15,7 +15,7 @@ public:
virtual floatms_t getDeadtime() const = 0;
virtual float getInjectorMassFlowRate() const = 0;
virtual void postState(float deadTime) const {};
virtual void postState(float deadTime) const { (void)deadTime; };
private:
float m_deadtime = 0;

View File

@ -55,15 +55,16 @@ DISPLAY(DISPLAY_FIELD(dwellAngle))
DISPLAY(DISPLAY_FIELD(cltTimingCorrection))
DISPLAY_TEXT(eol);
DISPLAY(DISPLAY_IF(isCrankingState)) floatms_t getCrankingFuel3(
floatms_t baseFuel,
DISPLAY(DISPLAY_IF(isCrankingState)) float getCrankingFuel3(
float baseFuel,
uint32_t revolutionCounterSinceStart DECLARE_ENGINE_PARAMETER_SUFFIX) {
// these magic constants are in Celsius
float baseCrankingFuel;
if (engineConfiguration->useRunningMathForCranking) {
baseCrankingFuel = baseFuel;
} else {
baseCrankingFuel = engineConfiguration->cranking.baseFuel;
// parameter is in milligrams, convert to grams
baseCrankingFuel = engineConfiguration->cranking.baseFuel * 0.001f;
}
/**
* Cranking fuel changes over time
@ -105,7 +106,7 @@ DISPLAY(DISPLAY_IF(isCrankingState)) floatms_t getCrankingFuel3(
* engine->engineState.cranking.tpsCoefficient;
DISPLAY_TEXT(Cranking_fuel);
engine->engineState.DISPLAY_PREFIX(cranking).DISPLAY_FIELD(fuel) = crankingFuel;
engine->engineState.DISPLAY_PREFIX(cranking).DISPLAY_FIELD(fuel) = crankingFuel * 1000;
if (crankingFuel <= 0) {
warning(CUSTOM_ERR_ZERO_CRANKING_FUEL, "Cranking fuel value %f", crankingFuel);
@ -148,7 +149,7 @@ floatms_t getRunningFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
DISPLAY_TEXT(eol);
DISPLAY_TEXT(Running_fuel);
ENGINE(engineState.DISPLAY_PREFIX(running).DISPLAY_FIELD(fuel)) = runningFuel;
ENGINE(engineState.DISPLAY_PREFIX(running).DISPLAY_FIELD(fuel)) = runningFuel * 1000;
DISPLAY_TEXT(eol);
DISPLAY_TEXT(Injector_lag);
@ -181,17 +182,10 @@ AirmassModelBase* getAirmassModel(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
}
}
/**
* per-cylinder fuel amount
* todo: rename this method since it's now base+TPSaccel
*/
floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
// Per-cylinder base fuel mass
static float getBaseFuelMass(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
ScopePerf perf(PE::GetBaseFuel);
floatms_t tpsAccelEnrich = ENGINE(tpsAccelEnrichment.getTpsEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE));
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(tpsAccelEnrich), "NaN tpsAccelEnrich", 0);
ENGINE(engineState.tpsAccelEnrich) = tpsAccelEnrich;
// airmass modes - get airmass first, then convert to fuel
auto model = getAirmassModel(PASS_ENGINE_PARAMETER_SIGNATURE);
efiAssert(CUSTOM_ERR_ASSERT, model != nullptr, "Invalid airmass mode", 0.0f);
@ -207,23 +201,9 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
// Fudge it by the global correction factor
baseFuelMass *= CONFIG(globalFuelCorrection);
ENGINE(injectorModel)->prepare();
float baseFuel = ENGINE(injectorModel)->getInjectionDuration(baseFuelMass);
// Ugh, there's a bug that means we have to cancel out the deadtime.
// See https://github.com/rusefi/rusefi/issues/1903
baseFuel -= engine->engineState.running.injectorLag;
if (cisnan(baseFuel)) {
// todo: we should not have this here but https://github.com/rusefi/rusefi/issues/1690
return 0;
}
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN baseFuel", 0);
engine->engineState.baseFuel = baseFuelMass;
return tpsAccelEnrich + baseFuel;
return baseFuelMass;
}
angle_t getInjectionOffset(float rpm, float load DECLARE_ENGINE_PARAMETER_SUFFIX) {
@ -302,11 +282,11 @@ percent_t getInjectorDutyCycle(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
return 100 * totalInjectiorAmountPerCycle / engineCycleDuration;
}
static floatms_t getFuel(bool isCranking, floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
static float getCycleFuelMass(bool isCranking, float baseFuelMass DECLARE_ENGINE_PARAMETER_SUFFIX) {
if (isCranking) {
return getCrankingFuel(baseFuel PASS_ENGINE_PARAMETER_SUFFIX);
return getCrankingFuel(baseFuelMass PASS_ENGINE_PARAMETER_SUFFIX);
} else {
return getRunningFuel(baseFuel PASS_ENGINE_PARAMETER_SUFFIX);
return getRunningFuel(baseFuelMass PASS_ENGINE_PARAMETER_SUFFIX);
}
}
@ -319,25 +299,28 @@ floatms_t getInjectionDuration(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
#if EFI_SHAFT_POSITION_INPUT
// Always update base fuel - some cranking modes use it
floatms_t baseFuel = getBaseFuel(rpm PASS_ENGINE_PARAMETER_SUFFIX);
float baseFuelMass = getBaseFuelMass(rpm PASS_ENGINE_PARAMETER_SUFFIX);
bool isCranking = ENGINE(rpmCalculator).isCranking();
floatms_t fuelPerCycle = getFuel(isCranking, baseFuel PASS_ENGINE_PARAMETER_SUFFIX);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(fuelPerCycle), "NaN fuelPerCycle", 0);
float cycleFuelMass = getCycleFuelMass(isCranking, baseFuelMass PASS_ENGINE_PARAMETER_SUFFIX);
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(cycleFuelMass), "NaN cycleFuelMass", 0);
// Fuel cut-off isn't just 0 or 1, it can be tapered
fuelPerCycle *= ENGINE(engineState.fuelCutoffCorrection);
// If no fuel, don't add injector lag
if (fuelPerCycle == 0.0f)
return 0;
cycleFuelMass *= ENGINE(engineState.fuelCutoffCorrection);
floatms_t theoreticalInjectionLength = fuelPerCycle * getInjectionModeDurationMultiplier(PASS_ENGINE_PARAMETER_SIGNATURE);
floatms_t injectorLag = ENGINE(engineState.running.injectorLag);
if (cisnan(injectorLag)) {
warning(CUSTOM_ERR_INJECTOR_LAG, "injectorLag not ready");
return 0; // we can end up here during configuration reset
}
return theoreticalInjectionLength + injectorLag;
float durationMultiplier = getInjectionModeDurationMultiplier(PASS_ENGINE_PARAMETER_SIGNATURE);
float injectionFuelMass = cycleFuelMass * durationMultiplier;
ENGINE(injectorModel)->prepare();
// TODO: move everything below here to injector scheduling, so that wall wetting works properly
floatms_t injectionDuration = ENGINE(injectorModel)->getInjectionDuration(injectionFuelMass);
floatms_t tpsAccelEnrich = ENGINE(tpsAccelEnrichment.getTpsEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE));
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(tpsAccelEnrich), "NaN tpsAccelEnrich", 0);
ENGINE(engineState.tpsAccelEnrich) = tpsAccelEnrich;
return injectionDuration + (durationMultiplier * tpsAccelEnrich);
#else
return 0;
#endif
@ -462,7 +445,7 @@ float getBaroCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
/**
* @return Duration of fuel injection while craning
*/
floatms_t getCrankingFuel(float baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
float getCrankingFuel(float baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX) {
return getCrankingFuel3(baseFuel, engine->rpmCalculator.getRevolutionCounterSinceStart() PASS_ENGINE_PARAMETER_SUFFIX);
}

View File

@ -12,11 +12,6 @@
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE);
/**
* @return total injection time into all cylinders, before CLT & IAT corrections
*/
floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
/**
* @return baseFuel with CLT and IAT corrections
*/
@ -30,8 +25,8 @@ float getIatFuelCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
float getCltFuelCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
float getFuelCutOffCorrection(efitick_t nowNt, int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
angle_t getCltTimingCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
floatms_t getCrankingFuel(floatms_t baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX);
floatms_t getCrankingFuel3(floatms_t baseFuel, uint32_t revolutionCounterSinceStart DECLARE_ENGINE_PARAMETER_SUFFIX);
float getCrankingFuel(float baseFuel DECLARE_ENGINE_PARAMETER_SUFFIX);
float getCrankingFuel3(float baseFuel, uint32_t revolutionCounterSinceStart DECLARE_ENGINE_PARAMETER_SUFFIX);
floatms_t getInjectionDuration(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
percent_t getInjectorDutyCycle(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);

View File

@ -266,7 +266,7 @@ end_struct
custom ego_sensor_e 4 bits, S32, @OFFSET@, [0:2], @@ego_sensor_e_enum@@
struct cranking_parameters_s
float baseFuel;+Base duration of the fuel injection during cranking, this is modified by the multipliers for CLT, IAT, TPS ect, to give the final cranking pulse width.;"ms", 1, 0, 0, 200, 1
float baseFuel;+Base mass of the per-cylinder fuel injected during cranking. This is then modified by the multipliers for CLT, IAT, TPS ect, to give the final cranking pulse width.\nA reasonable starting point is 60mg per liter per cylinder.\nex: 2 liter 4 cyl = 500cc/cyl, so 30mg cranking fuel.;"mg", 1, 0, 0, 500, 1
int16_t rpm;+This sets the RPM limit below which the ECU will use cranking fuel and ignition logic, typically this is around 350-450rpm. \nset cranking_rpm X;"RPM", 1, 0, 0, 3000, 0
end_struct

View File

@ -227,10 +227,10 @@ enable2ndByteCanID = false
; fuel math
chargeAirMass = scalar, U16, 44, "g",0.001, 0
crankingFuelMs = scalar, U16, 46, "ms",{1/@@PACK_MULT_MS@@}, 0.0
crankingFuelMs = scalar, U16, 46, "mg",{1/@@PACK_MULT_FUEL_MASS@@}, 0.0
currentTargetAfr= scalar, U16, 48, "ratio",,{1/@@PACK_MULT_AFR@@},, 0
baseFuel = scalar, U16, 50, "mg",{1/@@PACK_MULT_FUEL_MASS@@}, 0
fuelRunning = scalar, U16, 52, "ms",{1/@@PACK_MULT_MS@@}, 0
fuelRunning = scalar, U16, 52, "mg",{1/@@PACK_MULT_FUEL_MASS@@}, 0
actualLastInjection=scalar,U16, 54, "ms",{1/@@PACK_MULT_MS@@}, 0.0
injectorDutyCycle=scalar, U08, 56, "%", 0.5, 0
veValue = scalar, U08, 57, "ratio", 0.5, 0
@ -977,16 +977,16 @@ gaugeCategory = Fueling
;Name Var Title Units Lo Hi LoD LoW HiW HiD vd ld
tChargeGauge = tCharge, @@GAUGE_NAME_FUEL_CHARGE_TEMP@@, "deg C", -40, 140, -15, 1, 95, 110, 1, 1
baroCorrectionGauge = baroCorrection,@@GAUGE_NAME_FUEL_BARO_CORR@@, "ratio", 0.5, 1.5, 0.6, 0.7, 1.3, 1.4, 1, 1
crankingFuelGauge = crankingFuelMs, @@GAUGE_NAME_FUEL_CRANKING@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
crankingFuelGauge = crankingFuelMs, @@GAUGE_NAME_FUEL_CRANKING@@, "mg", 0, 100, 0, 0, 100, 100, 3, 1
iatCorrectionGauge = iatCorrection, @@GAUGE_NAME_FUEL_IAT_CORR@@, "mult", 0, 3, 0, 0, 3, 3, 2, 2
cltCorrectionGauge = cltCorrection, @@GAUGE_NAME_FUEL_CLT_CORR@@, "mult", 0, 3, 0, 0, 3, 3, 2, 2
injectorDutyCycleGauge=injectorDutyCycle, @@GAUGE_NAME_FUEL_INJ_DUTY@@,"%", 0, 120, 10, 10, 100, 100, 1, 1
actualLastInjectionGauge = actualLastInjection, @@GAUGE_NAME_FUEL_LAST_INJECTION@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
veValueGauge = veValue, "fuel: VE", "", 0, 120, 10, 10, 100, 100, 1, 1
injectorLagMsGauge = injectorLagMs, @@GAUGE_NAME_INJECTOR_LAG@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
fuelRunningGauge = fuelRunning, @@GAUGE_NAME_FUEL_RUNNING@@, "mSec", 0, 25.5, 1.0, 1.2, 20, 25, 3, 1
baseFuelGauge = baseFuel, @@GAUGE_NAME_FUEL_BASE@@, "mSec", 0, 100, 0, 0, 100, 100, 2, 0
injectorLagMsGauge = injectorLagMs, @@GAUGE_NAME_INJECTOR_LAG@@, "mSec", 0, 10, 0, 0, 10, 10, 3, 1
fuelRunningGauge = fuelRunning, @@GAUGE_NAME_FUEL_RUNNING@@, "mg", 0, 100, 0, 0, 100, 100, 3, 1
baseFuelGauge = baseFuel, @@GAUGE_NAME_FUEL_BASE@@, "mg", 0, 100, 0, 0, 100, 100, 2, 0
fuelPidCorrectionGauge = fuelPidCorrection, @@GAUGE_NAME_FUEL_PID_CORR@@, "%", -10, 10, -8, -5, 5, 8, 3, 1
fuelingLoadGauge = fuelingLoad, @@GAUGE_NAME_FUEL_LOAD@@, "%", 0, 300, 0, 0, 300, 300, 1, 1
@ -2800,7 +2800,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@\x00\x31\x00\x00"
dialog = crankingFuel, "Fuel"
field = "Injection mode", crankingInjectionMode
field = "Fuel Source For Cranking", useRunningMathForCranking
field = "Base fuel pulse width", cranking_baseFuel, {useRunningMathForCranking == 0}
field = "Base fuel mass", cranking_baseFuel, {useRunningMathForCranking == 0}
dialog = crankingIAC, "IAC"
field = "Cranking IAC position", crankingIACposition

View File

@ -49,7 +49,7 @@ TEST(fuelControl, transitionIssue1592) {
engineConfiguration->globalTriggerAngleOffset = 20;
// Yes, this is a ton of fuel but it makes the repro easier
engineConfiguration->cranking.baseFuel = 89;
engineConfiguration->cranking.baseFuel = 213.6;
engineConfiguration->cranking.rpm = 500;
// Test the transition from batch cranking to sequential running

View File

@ -24,7 +24,8 @@ TEST(engine, testPlainCrankingWithoutAdvancedFeatures) {
ASSERT_EQ( 4, engine->executor.size()) << "plain#2";
eth.assertEvent5("sim start", 0, (void*)startSimultaniousInjection, 100000 - 1875);
eth.assertEvent5("sim end", 1, (void*)endSimultaniousInjection, 100000);
// -1 because ugh floating point math
eth.assertEvent5("sim end", 1, (void*)endSimultaniousInjection, 100000 - 1);
}

View File

@ -52,7 +52,7 @@ TEST(cranking, testFasterEngineSpinningUp) {
ASSERT_EQ(IM_WASTED_SPARK, getCurrentIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE));
// check real events
eth.assertEvent5("inj start#1", 0, (void*)startSimultaniousInjection, 98125);
eth.assertEvent5("inj end#1", 1, (void*)endSimultaniousInjection, 100000);
eth.assertEvent5("inj end#1", 1, (void*)endSimultaniousInjection, 99999);
// skip the rest of the cycle
eth.fireFall(200);
@ -74,7 +74,7 @@ TEST(cranking, testFasterEngineSpinningUp) {
ASSERT_EQ( 4, engine->executor.size()) << "plain#2";
// check real events
eth.assertEvent5("inj start#2", 0, (void*)startSimultaniousInjection, 148125);
eth.assertEvent5("inj end#2", 1, (void*)endSimultaniousInjection, 150000);
eth.assertEvent5("inj end#2", 1, (void*)endSimultaniousInjection, 149999);
// skip, clear & advance 1 more revolution at higher RPM
eth.fireFall(60);
@ -94,7 +94,7 @@ TEST(cranking, testFasterEngineSpinningUp) {
// check real events for sequential injection
// Note: See addFuelEvents() fix inside setRpmValue()!
eth.assertEvent5("inj start#3", 0, (void*)turnInjectionPinHigh, -31875);
eth.assertEvent5("inj end#3", 1, (void*)turnInjectionPinLow, -30000);
eth.assertEvent5("inj end#3", 1, (void*)turnInjectionPinLow, -30001);
}
static void doTestFasterEngineSpinningUp60_2(int startUpDelayMs, int rpm1, int expectedRpm) {

View File

@ -74,7 +74,7 @@ TEST(misc, testFuelMap) {
engine->engineState.mockAdcState.setMockVoltage(EFI_ADC_10, 0 PASS_ENGINE_PARAMETER_SUFFIX);
engineConfiguration->cranking.baseFuel = 4;
engineConfiguration->cranking.baseFuel = 4000;
// Should use 20 degree correction in case of failed sensor
Sensor::resetMockValue(SensorType::Clt);