Tps-accel. fractional mode (#715)
* Add new config settings for tps_accel_fractional_mode * Add new variables for the fractional algo * Add resetFractionValues() method * Call onEngineCycleTps() and fix onEngineCycle() * Implement the fractional algo * More debug outputs for tps-enrich * Nice & juicy unit-test!
This commit is contained in:
parent
c34d7cac48
commit
4b5ed3e0e1
|
@ -190,12 +190,38 @@ floatms_t AccelEnrichmemnt::getTpsEnrichment(DECLARE_ENGINE_PARAMETER_SIGNATURE)
|
|||
extraFuel = 0;
|
||||
}
|
||||
|
||||
// Fractional enrichment (fuel portions are accumulated and split between several engine cycles.
|
||||
// This is a crude imitation of carburetor's acceleration pump.
|
||||
if (CONFIG(tpsAccelFractionPeriod) > 1 || CONFIG(tpsAccelFractionDivisor) > 1.0f) {
|
||||
// make sure both values are non-zero
|
||||
float periodF = (float)maxI(CONFIG(tpsAccelFractionPeriod), 1);
|
||||
float divisor = maxF(CONFIG(tpsAccelFractionDivisor), 1.0f);
|
||||
|
||||
// if current extra fuel portion is not "strong" enough, then we keep up the "pump pressure" with the accumulated portion
|
||||
floatms_t maxExtraFuel = maxF(extraFuel, accumulatedValue);
|
||||
// use only a fixed fraction of the accumulated portion
|
||||
floatms_t injFuel = maxExtraFuel / divisor;
|
||||
|
||||
// update max counters
|
||||
maxExtraPerCycle = maxF(extraFuel, maxExtraPerCycle);
|
||||
maxInjectedPerPeriod = maxF(injFuel, maxInjectedPerPeriod);
|
||||
|
||||
// evenly split it between several engine cycles
|
||||
extraFuel = injFuel / periodF;
|
||||
} else {
|
||||
resetFractionValues();
|
||||
}
|
||||
|
||||
if (engineConfiguration->debugMode == DBG_TPS_ACCEL) {
|
||||
#if EFI_TUNER_STUDIO || defined(__DOXYGEN__)
|
||||
tsOutputChannels.debugFloatField1 = tpsFrom;
|
||||
tsOutputChannels.debugFloatField2 = tpsTo;
|
||||
tsOutputChannels.debugFloatField3 = valueFromTable;
|
||||
tsOutputChannels.debugFloatField4 = extraFuel;
|
||||
tsOutputChannels.debugFloatField5 = accumulatedValue;
|
||||
tsOutputChannels.debugFloatField6 = maxExtraPerPeriod;
|
||||
tsOutputChannels.debugFloatField7 = maxInjectedPerPeriod;
|
||||
tsOutputChannels.debugIntField1 = cycleCnt;
|
||||
#endif /* EFI_TUNER_STUDIO */
|
||||
}
|
||||
|
||||
|
@ -236,6 +262,15 @@ float AccelEnrichmemnt::getEngineLoadEnrichment(DECLARE_ENGINE_PARAMETER_SIGNATU
|
|||
void AccelEnrichmemnt::reset() {
|
||||
cb.clear();
|
||||
previousValue = NAN;
|
||||
resetFractionValues();
|
||||
}
|
||||
|
||||
void AccelEnrichmemnt::resetFractionValues() {
|
||||
accumulatedValue = 0;
|
||||
maxExtraPerCycle = 0;
|
||||
maxExtraPerPeriod = 0;
|
||||
maxInjectedPerPeriod = 0;
|
||||
cycleCnt = 0;
|
||||
}
|
||||
|
||||
void AccelEnrichmemnt::setLength(int length) {
|
||||
|
@ -247,7 +282,32 @@ void AccelEnrichmemnt::onNewValue(float currentValue DECLARE_ENGINE_PARAMETER_SU
|
|||
}
|
||||
|
||||
void AccelEnrichmemnt::onEngineCycleTps(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
onNewValue(getTPS(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// we update values in handleFuel() directly
|
||||
//onNewValue(getTPS(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
// we used some extra fuel during the current cycle, so we "charge" our "acceleration pump" with it
|
||||
accumulatedValue -= maxExtraPerPeriod;
|
||||
maxExtraPerPeriod = maxF(maxExtraPerCycle, maxExtraPerPeriod);
|
||||
maxExtraPerCycle = 0;
|
||||
accumulatedValue += maxExtraPerPeriod;
|
||||
|
||||
// update the accumulated value every 'Period' engine cycles
|
||||
if (--cycleCnt <= 0) {
|
||||
maxExtraPerPeriod = 0;
|
||||
|
||||
// we've injected this portion during the cycle, so we set what's left for the next cycle
|
||||
accumulatedValue -= maxInjectedPerPeriod;
|
||||
maxInjectedPerPeriod = 0;
|
||||
|
||||
// it's an infinitely convergent series, so we set a limit at some point
|
||||
// (also make sure that accumulatedValue is positive, for safety)
|
||||
static const floatms_t smallEpsilon = 0.001f;
|
||||
if (accumulatedValue < smallEpsilon)
|
||||
accumulatedValue = 0;
|
||||
|
||||
// reset the counter
|
||||
cycleCnt = CONFIG(tpsAccelFractionPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
void AccelEnrichmemnt::onEngineCycle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||
|
|
|
@ -36,12 +36,21 @@ public:
|
|||
void onEngineCycle(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
void onEngineCycleTps(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||
void reset();
|
||||
void resetFractionValues();
|
||||
void setLength(int length);
|
||||
cyclic_buffer<float> cb;
|
||||
void onNewValue(float currentValue DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
private:
|
||||
float previousValue;
|
||||
/**
|
||||
* Used for Fractional TPS enrichment.
|
||||
*/
|
||||
floatms_t accumulatedValue;
|
||||
floatms_t maxExtraPerCycle;
|
||||
floatms_t maxExtraPerPeriod;
|
||||
floatms_t maxInjectedPerPeriod;
|
||||
int cycleCnt;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -391,7 +391,10 @@ static ALWAYS_INLINE void handleFuel(const bool limitedFuel, uint32_t trgEventIn
|
|||
#endif /* FUEL_MATH_EXTREME_LOGGING */
|
||||
|
||||
ENGINE(tpsAccelEnrichment.onNewValue(getTPS(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX));
|
||||
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
if (trgEventIndex == 0) {
|
||||
ENGINE(tpsAccelEnrichment.onEngineCycleTps(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
ENGINE(engineLoadAccelEnrichment.onEngineCycle(PASS_ENGINE_PARAMETER_SIGNATURE));
|
||||
}
|
||||
|
||||
/**
|
||||
* we have same assignment of 'getInjectionDuration' to 'injectionDuration' in periodicFastCallback()
|
||||
|
|
|
@ -991,10 +991,13 @@ tChargeMode_e tChargeMode;
|
|||
int16_t idleTimingPidWorkZone;The timing correction works only if RPM is close enough, otherwise the IAC correction works;"RPM", 1, 0, 0, 1000, 0
|
||||
int16_t idleTimingPidDeadZone;If RPM is too perfect, let's leave the advance angle alone to avoid oscillation;"RPM", 1, 0, 0, 1000, 0
|
||||
int16_t idlePidFalloffDeltaRpm;Added to the work zone for smooth correction falloff;"RPM", 1, 0, 0, 1000, 0
|
||||
int16_t unusedIdleTimingPid;
|
||||
|
||||
int16_t tpsAccelFractionPeriod;+A delay in cycles between fuel-enrich. portions;"cycles", 1, 0, 0, 500, 0
|
||||
float tpsAccelFractionDivisor;+A fraction divisor: 1 or less = entire portion at once, or split into diminishing fractions;"coef", 1, 0, 0, 100, 2
|
||||
|
||||
spi_device_e tle8888spiDevice;
|
||||
|
||||
int[614] mainUnusedEnd;
|
||||
int[613] mainUnusedEnd;
|
||||
|
||||
|
||||
end_struct
|
||||
|
|
|
@ -2160,6 +2160,9 @@ cmd_set_engine_type_default = "w\x00\x31\x00\x00"
|
|||
field = "Accel Threshold", tpsAccelEnrichmentThreshold
|
||||
field = "Decel Threshold", tpsDecelEnleanmentThreshold
|
||||
; field = "Decel Multiplier", tpsDecelEnleanmentMultiplier
|
||||
field = "#Accelerator Pump model:"
|
||||
field = "Fraction Period", tpsAccelFractionPeriod
|
||||
field = "Fraction Divisor", tpsAccelFractionDivisor
|
||||
|
||||
dialog = WallWettingAccelPanel, "Wall Wetting (alpha version)"
|
||||
field = "evaporation time constant", wwaeTau
|
||||
|
|
|
@ -37,3 +37,69 @@ TEST(big, testAccelEnrichment) {
|
|||
engine->tpsAccelEnrichment.onNewValue(0 PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
ASSERT_EQ( 0, engine->tpsAccelEnrichment.getMaxDelta(PASS_ENGINE_PARAMETER_SIGNATURE)) << "maxDelta";
|
||||
}
|
||||
|
||||
static void doFractionalTpsIteration(int period, int divisor, int numCycles, std::vector<floatms_t> &tpsEnrich DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||
// every cycle
|
||||
engineConfiguration->tpsAccelFractionPeriod = period;
|
||||
// split into 2 portions
|
||||
engineConfiguration->tpsAccelFractionDivisor = divisor;
|
||||
|
||||
engine->tpsAccelEnrichment.reset();
|
||||
engine->tpsAccelEnrichment.onNewValue(0 PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
for (int i = 0; i < numCycles; i++) {
|
||||
engine->tpsAccelEnrichment.onNewValue(10 PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
engine->tpsAccelEnrichment.onEngineCycleTps(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
tpsEnrich[i] = engine->tpsAccelEnrichment.getTpsEnrichment(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(big, testAccelEnrichmentFractionalTps) {
|
||||
printf("====================================================================================== testAccelEnrichmentFractionalTps\r\n");
|
||||
|
||||
WITH_ENGINE_TEST_HELPER(FORD_ASPIRE_1996);
|
||||
|
||||
// setup
|
||||
engineConfiguration->tpsAccelEnrichmentThreshold = 5;
|
||||
|
||||
// fill tps2tps map (todo: there should be a better way?)
|
||||
static const float tpsTpsConst = 1.0f;
|
||||
for (int loadIndex = 0; loadIndex < TPS_TPS_ACCEL_TABLE; loadIndex++) {
|
||||
for (int rpmIndex = 0; rpmIndex < TPS_TPS_ACCEL_TABLE; rpmIndex++) {
|
||||
config->tpsTpsAccelTable[loadIndex][rpmIndex] = tpsTpsConst;
|
||||
}
|
||||
}
|
||||
|
||||
Logging logger;
|
||||
initAccelEnrichment(&logger PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
|
||||
engine->rpmCalculator.setRpmValue(600 PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
engine->periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||
|
||||
engine->tpsAccelEnrichment.setLength(2);
|
||||
|
||||
|
||||
const int numCycles = 4;
|
||||
std::vector<floatms_t> tpsEnrich(numCycles);
|
||||
|
||||
// first, test the default behavior without fractional division
|
||||
doFractionalTpsIteration(1, 1, numCycles, tpsEnrich PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// the portion for the first cycle is full-enriched and there's no enrichment for next cycles
|
||||
EXPECT_THAT(tpsEnrich, testing::ElementsAre(1.0f, 0.0f, 0.0f, 0.0f)) << "fractionalTps#1";
|
||||
|
||||
// divide into 2 each cycle
|
||||
doFractionalTpsIteration(1, 2, numCycles, tpsEnrich PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// we have half-portion for the first cycle, then 1/4-th and 1/8th and so on...
|
||||
EXPECT_THAT(tpsEnrich, testing::ElementsAre(0.5f, 0.25f, 0.125f, 0.0625f)) << "fractionalTps#2";
|
||||
|
||||
// split every portion into 3 sub-portions (so the whole enrichment takes longer)
|
||||
doFractionalTpsIteration(3, 1, numCycles, tpsEnrich PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// we have 1/3rd-portion for the first three cycles
|
||||
const float th = (1.0f / 3.0f);
|
||||
EXPECT_THAT(tpsEnrich, testing::ElementsAre(testing::FloatEq(th), testing::FloatEq(th), testing::FloatEq(th), 0.0f)) << "fractionalTps#3";
|
||||
|
||||
// split every divided portion into 2 sub-portions (so the whole enrichment takes longer)
|
||||
doFractionalTpsIteration(2, 2, numCycles, tpsEnrich PASS_ENGINE_PARAMETER_SUFFIX);
|
||||
// we have half-portion for the first two cycles, and 1/4-th portion for the next 2 cycles, and so on...
|
||||
EXPECT_THAT(tpsEnrich, testing::ElementsAre(0.25f, 0.25f, 0.125f, 0.125f)) << "fractionalTps#4";
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue