Template-ize bin/value length for interpolation (#878)

* update consumers

* tests

* whitespace

* format
This commit is contained in:
Matthew Kennedy 2019-07-09 11:16:36 -07:00 committed by rusefi
parent 2f68badc47
commit e0db83e027
17 changed files with 68 additions and 54 deletions

View File

@ -244,7 +244,7 @@ private:
#endif /* EFI_TUNER_STUDIO */
}
feedForward = interpolate2d("etbb", targetPosition, engineConfiguration->etbBiasBins, engineConfiguration->etbBiasValues, ETB_BIAS_CURVE_LENGTH);
feedForward = interpolate2d("etbb", targetPosition, engineConfiguration->etbBiasBins, engineConfiguration->etbBiasValues);
pid.iTermMin = engineConfiguration->etb_iTermMin;
pid.iTermMax = engineConfiguration->etb_iTermMax;

View File

@ -238,7 +238,7 @@ static percent_t automaticIdleController() {
if (CONFIG(idlePidRpmUpperLimit) > 0) {
idleState = PID_UPPER;
if (CONFIGB(useIacTableForCoasting) && !cisnan(engine->sensors.clt)) {
percent_t iacPosForCoasting = interpolate2d("iacCoasting", engine->sensors.clt, CONFIG(iacCoastingBins), CONFIG(iacCoasting), CLT_CURVE_SIZE);
percent_t iacPosForCoasting = interpolate2d("iacCoasting", engine->sensors.clt, CONFIG(iacCoastingBins), CONFIG(iacCoasting));
newValue = interpolateClamped(idlePidLowerRpm, newValue, idlePidLowerRpm + CONFIG(idlePidRpmUpperLimit), iacPosForCoasting, rpm);
} else {
// Well, just leave it as is, without PID regulation...
@ -308,11 +308,11 @@ private:
cltCorrection = 1.0f;
// Use separate CLT correction table for cranking
else if (engineConfiguration->overrideCrankingIacSetting && !isRunning) {
cltCorrection = interpolate2d("cltCrankingT", clt, config->cltCrankingCorrBins, config->cltCrankingCorr, CLT_CRANKING_CURVE_SIZE);
cltCorrection = interpolate2d("cltCrankingT", clt, config->cltCrankingCorrBins, config->cltCrankingCorr);
} else {
// this value would be ignored if running in AUTO mode
// but we need it while cranking in AUTO mode
cltCorrection = interpolate2d("cltT", clt, config->cltIdleCorrBins, config->cltIdleCorr, CLT_CURVE_SIZE);
cltCorrection = interpolate2d("cltT", clt, config->cltIdleCorrBins, config->cltIdleCorr);
}
percent_t iacPosition;

View File

@ -242,7 +242,7 @@ float AccelEnrichmemnt::getEngineLoadEnrichment(DECLARE_ENGINE_PARAMETER_SIGNATU
if (distance <= 0) // checking if indexes are out of order due to circular buffer nature
distance += minI(cb.getCount(), cb.getSize());
taper = interpolate2d("accel", distance, engineConfiguration->mapAccelTaperBins, engineConfiguration->mapAccelTaperMult, MAP_ACCEL_TAPER);
taper = interpolate2d("accel", distance, engineConfiguration->mapAccelTaperBins, engineConfiguration->mapAccelTaperMult);
result = taper * d * engineConfiguration->engineLoadAccelEnrichmentMultiplier;
} else if (d < -engineConfiguration->engineLoadDecelEnleanmentThreshold) {

View File

@ -104,7 +104,7 @@ static angle_t getRunningAdvance(int rpm, float engineLoad DECLARE_ENGINE_PARAME
// get advance from the separate table for Idle
if (CONFIG(useSeparateAdvanceForIdle)) {
float idleAdvance = interpolate2d("idleAdvance", rpm, config->idleAdvanceBins, config->idleAdvance, IDLE_ADVANCE_CURVE_SIZE);
float idleAdvance = interpolate2d("idleAdvance", rpm, config->idleAdvanceBins, config->idleAdvance);
// interpolate between idle table and normal (running) table using TPS threshold
float tps = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE);
advanceAngle = interpolateClamped(0.0f, idleAdvance, CONFIGB(idlePidDeactivationTpsThreshold), advanceAngle, tps);
@ -175,7 +175,7 @@ angle_t getAdvanceCorrections(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
static angle_t getCrankingAdvance(int rpm, float engineLoad DECLARE_ENGINE_PARAMETER_SUFFIX) {
// get advance from the separate table for Cranking
if (CONFIG(useSeparateAdvanceForCranking)) {
return interpolate2d("crankingAdvance", rpm, CONFIG(crankingAdvanceBins), CONFIG(crankingAdvance), CRANKING_ADVANCE_CURVE_SIZE);
return interpolate2d("crankingAdvance", rpm, CONFIG(crankingAdvanceBins), CONFIG(crankingAdvance));
}
// Interpolate the cranking timing angle to the earlier running angle for faster engine start

View File

@ -202,7 +202,7 @@ void Engine::preCalculate(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
for (int i = 0; i < MAF_DECODING_CACHE_SIZE; i++) {
float volts = i / MAF_DECODING_CACHE_MULT;
float maf = interpolate2d("maf", volts, config->mafDecodingBins,
config->mafDecoding, MAF_DECODING_COUNT);
config->mafDecoding);
mafDecodingLookup[i] = maf;
}
}

View File

@ -133,8 +133,10 @@ void EngineState::updateSlowSensors(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
#endif
engine->sensors.oilPressure = getOilPressure(PASS_ENGINE_PARAMETER_SIGNATURE);
// todo: should this feature get removed?
// it does the same thing as the warmup CLT multiplier
warmupTargetAfr = interpolate2d("warm", engine->sensors.clt, engineConfiguration->warmupTargetAfrBins,
engineConfiguration->warmupTargetAfr, WARMUP_TARGET_AFR_SIZE);
engineConfiguration->warmupTargetAfr);
}
void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
@ -199,7 +201,7 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
cltTimingCorrection = getCltTimingCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
engineNoiseHipLevel = interpolate2d("knock", rpm, engineConfiguration->knockNoiseRpmBins,
engineConfiguration->knockNoise, ENGINE_NOISE_CURVE_SIZE);
engineConfiguration->knockNoise);
baroCorrection = getBaroCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
@ -223,7 +225,7 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
}
// get VE from the separate table for Idle
if (CONFIG(useSeparateVeForIdle)) {
float idleVe = interpolate2d("idleVe", rpm, config->idleVeBins, config->idleVe, IDLE_VE_CURVE_SIZE);
float idleVe = interpolate2d("idleVe", rpm, config->idleVeBins, config->idleVe);
// interpolate between idle table and normal (running) table using TPS threshold
currentRawVE = interpolateClamped(0.0f, idleVe, CONFIGB(idlePidDeactivationTpsThreshold), currentRawVE, tps);
}

View File

@ -699,7 +699,7 @@ int getTargetRpmForIdleCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
// error is already reported, let's take first value from the table should be good enough error handing solution
targetRpm = CONFIG(cltIdleRpm)[0];
} else {
targetRpm = interpolate2d("cltRpm", clt, CONFIG(cltIdleRpmBins), CONFIG(cltIdleRpm), CLT_CURVE_SIZE);
targetRpm = interpolate2d("cltRpm", clt, CONFIG(cltIdleRpmBins), CONFIG(cltIdleRpm));
}
return targetRpm + engine->fsioState.fsioIdleTargetRPMAdjustment;
}

View File

@ -221,8 +221,8 @@ floatms_t getInjectorLag(float vBatt DECLARE_ENGINE_PARAMETER_SUFFIX) {
warning(OBD_System_Voltage_Malfunction, "vBatt=%.2f", vBatt);
return 0;
}
float vBattCorrection = interpolate2d("lag", vBatt, INJECTOR_LAG_CURVE);
return vBattCorrection;
return interpolate2d("lag", vBatt, engineConfiguration->injector.battLagCorrBins, engineConfiguration->injector.battLagCorr);
}
/**
@ -243,19 +243,19 @@ void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
float getCltFuelCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
if (cisnan(engine->sensors.clt))
return 1; // this error should be already reported somewhere else, let's just handle it
return interpolate2d("cltf", engine->sensors.clt, WARMUP_CLT_EXTRA_FUEL_CURVE);
return interpolate2d("cltf", engine->sensors.clt, config->cltFuelCorrBins, config->cltFuelCorr);
}
angle_t getCltTimingCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
if (cisnan(engine->sensors.clt))
return 0; // this error should be already reported somewhere else, let's just handle it
return interpolate2d("timc", engine->sensors.clt, engineConfiguration->cltTimingBins, engineConfiguration->cltTimingExtra, CLT_TIMING_CURVE_SIZE);
return interpolate2d("timc", engine->sensors.clt, engineConfiguration->cltTimingBins, engineConfiguration->cltTimingExtra);
}
float getIatFuelCorrection(float iat DECLARE_ENGINE_PARAMETER_SUFFIX) {
if (cisnan(iat))
return 1; // this error should be already reported somewhere else, let's just handle it
return interpolate2d("iatc", iat, IAT_FUEL_CORRECTION_CURVE);
return interpolate2d("iatc", iat, config->iatFuelCorrBins, config->iatFuelCorr);
}
/**
@ -340,15 +340,15 @@ floatms_t getCrankingFuel3(float coolantTemperature,
// these magic constants are in Celsius
float baseCrankingFuel = engineConfiguration->cranking.baseFuel;
float durationCoef = interpolate2d("crank", revolutionCounterSinceStart, config->crankingCycleBins,
config->crankingCycleCoef, CRANKING_CURVE_SIZE);
config->crankingCycleCoef);
float coolantTempCoef = cisnan(coolantTemperature) ? 1 : interpolate2d("crank", coolantTemperature, config->crankingFuelBins,
config->crankingFuelCoef, CRANKING_CURVE_SIZE);
config->crankingFuelCoef);
percent_t tps = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE);
float tpsCoef = cisnan(tps) ? 1 : interpolate2d("crankTps", tps, engineConfiguration->crankingTpsBins,
engineConfiguration->crankingTpsCoef, CRANKING_CURVE_SIZE);
engineConfiguration->crankingTpsCoef);
floatms_t result = baseCrankingFuel * durationCoef * coolantTempCoef * tpsCoef;

View File

@ -228,7 +228,7 @@ void refreshMapAveragingPreCalc(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
int rpm = GET_RPM_VALUE;
if (isValidRpm(rpm)) {
MAP_sensor_config_s * c = &engineConfiguration->map;
angle_t start = interpolate2d("mapa", rpm, c->samplingAngleBins, c->samplingAngle, MAP_ANGLE_SIZE);
angle_t start = interpolate2d("mapa", rpm, c->samplingAngleBins, c->samplingAngle);
efiAssertVoid(CUSTOM_ERR_6690, !cisnan(start), "start");
angle_t offsetAngle = TRIGGER_SHAPE(eventAngles[CONFIG(mapAveragingSchedulingAtIndex)]);
@ -241,7 +241,7 @@ void refreshMapAveragingPreCalc(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
fixAngle(cylinderStart, "cylinderStart", CUSTOM_ERR_6562);
engine->engineState.mapAveragingStart[i] = cylinderStart;
}
engine->engineState.mapAveragingDuration = interpolate2d("samp", rpm, c->samplingWindowBins, c->samplingWindow, MAP_WINDOW_SIZE);
engine->engineState.mapAveragingDuration = interpolate2d("samp", rpm, c->samplingWindowBins, c->samplingWindow);
} else {
for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
engine->engineState.mapAveragingStart[i] = NAN;

View File

@ -249,7 +249,7 @@ floatms_t getSparkDwell(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
} else {
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(rpm), "invalid rpm", NAN);
dwellMs = interpolate2d("dwell", rpm, engineConfiguration->sparkDwellRpmBins, engineConfiguration->sparkDwellValues, DWELL_CURVE_SIZE);
dwellMs = interpolate2d("dwell", rpm, engineConfiguration->sparkDwellRpmBins, engineConfiguration->sparkDwellValues);
}
if (cisnan(dwellMs) || dwellMs <= 0) {

View File

@ -114,7 +114,7 @@ float getAfr(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
float volts = getVoltageDivided("ego", sensor->hwChannel);
if (CONFIGB(afr_type) == ES_NarrowBand) {
float afr = interpolate2d("narrow", volts, engineConfiguration->narrowToWideOxygenBins, engineConfiguration->narrowToWideOxygen, NARROW_BAND_WIDE_BAND_CONVERSION_SIZE);
float afr = interpolate2d("narrow", volts, engineConfiguration->narrowToWideOxygenBins, engineConfiguration->narrowToWideOxygen);
#ifdef EFI_NARROW_EGO_AVERAGING
if (useAveraging)
afr = updateEgoAverage(afr);

View File

@ -101,11 +101,11 @@ void updateAuxValves(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
}
engine->engineState.auxValveStart = interpolate2d("aux", x,
engineConfiguration->fsioCurve1Bins,
engineConfiguration->fsioCurve1, FSIO_CURVE_16);
engineConfiguration->fsioCurve1);
engine->engineState.auxValveEnd = interpolate2d("aux", x,
engineConfiguration->fsioCurve2Bins,
engineConfiguration->fsioCurve2, FSIO_CURVE_16);
engineConfiguration->fsioCurve2);
if (engine->engineState.auxValveStart >= engine->engineState.auxValveEnd) {
// this is a fatal error to make this really visible

View File

@ -51,24 +51,27 @@ static volatile int lastSlowAdcCounter = 0;
// LSU conversion tables. See cj125_sensor_type_e
// For LSU4.2, See http://www.bosch-motorsport.com/media/catalog_resources/Lambda_Sensor_LSU_42_Datasheet_51_en_2779111435pdf.pdf
// See LSU4.9, See http://www.bosch-motorsport.com/media/catalog_resources/Lambda_Sensor_LSU_49_Datasheet_51_en_2779147659pdf.pdf
static const int CJ125_LSU_CURVE_SIZE = 25;
// This is a number of bins for each sensor type (should be < CJ125_LSU_CURVE_SIZE)
static const float cjLSUTableSize[2] = {
9, 24,
};
// Pump current, mA
static const float cjLSUBins[2][CJ125_LSU_CURVE_SIZE] = { {
static constexpr float pumpCurrentLsu42[] = {
// LSU 4.2
-1.85f, -1.08f, -0.76f, -0.47f, 0.0f, 0.34f, 0.68f, 0.95f, 1.4f }, {
// LSU 4.9
-2.0f, -1.602f, -1.243f, -0.927f, -0.8f, -0.652f, -0.405f, -0.183f, -0.106f, -0.04f, 0, 0.015f, 0.097f, 0.193f, 0.250f, 0.329f, 0.671f, 0.938f, 1.150f, 1.385f, 1.700f, 2.000f, 2.150f, 2.250f },
-1.85f, -1.08f, -0.76f, -0.47f, 0.0f, 0.34f, 0.68f, 0.95f, 1.4f
};
// Lambda value
static const float cjLSULambda[2][CJ125_LSU_CURVE_SIZE] = { {
// LSU 4.2
0.7f, 0.8f, 0.85f, 0.9f, 1.009f, 1.18f, 1.43f, 1.7f, 2.42f }, {
static constexpr float pumpCurrentLsu49[] = {
// LSU 4.9
0.65f, 0.7f, 0.75f, 0.8f, 0.822f, 0.85f, 0.9f, 0.95f, 0.97f, 0.99f, 1.003f, 1.01f, 1.05f, 1.1f, 1.132f, 1.179f, 1.429f, 1.701f, 1.990f, 2.434f, 3.413f, 5.391f, 7.506f, 10.119f },
-2.0f, -1.602f, -1.243f, -0.927f, -0.8f, -0.652f, -0.405f, -0.183f, -0.106f, -0.04f, 0, 0.015f, 0.097f, 0.193f, 0.250f, 0.329f, 0.671f, 0.938f, 1.150f, 1.385f, 1.700f, 2.000f, 2.150f, 2.250f
};
// Corresponding lambda values for the above pump current
static constexpr float lambdaLsu42[] = {
// LSU 4.2
0.7f, 0.8f, 0.85f, 0.9f, 1.009f, 1.18f, 1.43f, 1.7f, 2.42f
};
static constexpr float lambdaLsu49[] = {
// LSU 4.9
0.65f, 0.7f, 0.75f, 0.8f, 0.822f, 0.85f, 0.9f, 0.95f, 0.97f, 0.99f, 1.003f, 1.01f, 1.05f, 1.1f, 1.132f, 1.179f, 1.429f, 1.701f, 1.990f, 2.434f, 3.413f, 5.391f, 7.506f, 10.119f
};
@ -502,16 +505,15 @@ static void cjSetInit2(int v) {
#endif /* CJ125_DEBUG */
float cjGetAfr(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
cj125_sensor_type_e sensorType;
if (engineConfiguration->cj125isLsu49) {
sensorType = CJ125_LSU_49;
} else {
sensorType = CJ125_LSU_42;
}
// See CJ125 datasheet, page 6
float pumpCurrent = (globalInstance.vUa - globalInstance.vUaCal) * globalInstance.amplCoeff * (CJ125_PUMP_CURRENT_FACTOR / CJ125_PUMP_SHUNT_RESISTOR);
globalInstance.lambda = interpolate2d("cj125Lsu", pumpCurrent, (float *)cjLSUBins[sensorType], (float *)cjLSULambda[sensorType], cjLSUTableSize[sensorType]);
if (engineConfiguration->cj125isLsu49) {
globalInstance.lambda = interpolate2d("cj125Lsu", pumpCurrent, pumpCurrentLsu49, lambdaLsu49);
} else {
globalInstance.lambda = interpolate2d("cj125Lsu", pumpCurrent, pumpCurrentLsu42, lambdaLsu42);
}
// todo: make configurable stoich ratio
return globalInstance.lambda * CJ125_STOICH_RATIO;
}

View File

@ -189,6 +189,8 @@ int findIndex(const float array[], int size, float value) {
return findIndexMsg("", array, size, value);
}
namespace priv
{
/**
* @brief One-dimensional table lookup with linear interpolation
*
@ -208,6 +210,7 @@ float interpolate2d(const char *msg, float value, const float bin[], const float
return interpolateMsg("2d", bin[index], values[index], bin[index + 1], values[index + 1], value);
}
}
/**
* Sets specified value for specified key in a correction curve

View File

@ -26,7 +26,15 @@ void ensureArrayIsAscending(const char *msg, const float array[], int size);
int findIndex2(const float array[], unsigned size, float value);
float interpolateClamped(float x1, float y1, float x2, float y2, float x);
float interpolateMsg(const char *msg, float x1, float y1, float x2, float y2, float x);
namespace priv {
float interpolate2d(const char *msg, float value, const float bin[], const float values[], int size);
}
template <int TSize>
float interpolate2d(const char *msg, const float value, const float (&bin)[TSize], const float (&values)[TSize]) {
return priv::interpolate2d(msg, value, bin, values, TSize);
}
int needInterpolationLogging(void);

View File

@ -85,7 +85,7 @@ void printConvertedTable() {
float volts = V_BINS[vIndex];
float psiValue = interpolate2d("conv", volts, vValues, PSI_BINS, ASIZE);
float psiValue = interpolate2d("conv", volts, vValues, PSI_BINS);
// psiValues[vIndex] = psiValue;
printf("/*v=%f kpa=*/ %f, ", volts, psiValue);

View File

@ -71,24 +71,23 @@ TEST(misc, testInterpolate2d) {
float bins4[] = { 1, 2, 3, 4 };
float values4[] = { 1, 20, 30, 400 };
int size = 4;
int result;
printf("Left size\r\n");
result = interpolate2d("t", 0, bins4, values4, size);
result = interpolate2d("t", 0, bins4, values4);
ASSERT_EQ(1, result);
printf("Right size\r\n");
result = interpolate2d("t", 10, bins4, values4, size);
result = interpolate2d("t", 10, bins4, values4);
ASSERT_EQ(400, result);
printf("Middle1\r\n");
result = interpolate2d("t", 3, bins4, values4, size);
result = interpolate2d("t", 3, bins4, values4);
ASSERT_EQ(30, result);
printf("Middle1\r\n");
result = interpolate2d("t", 3.5, bins4, values4, size);
result = interpolate2d("t", 3.5, bins4, values4);
ASSERT_EQ(215, result);
}