rusefi/firmware/controllers/algo/advance_map.cpp

258 lines
8.4 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file advance_map.cpp
*
* @date Mar 27, 2013
2020-01-07 21:02:40 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*
* This file is part of rusEfi - see http://rusefi.com
*
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "pch.h"
2015-07-10 06:01:56 -07:00
#include "advance_map.h"
#include "idle_thread.h"
2020-03-24 16:55:12 -07:00
#include "launch_control.h"
2015-07-10 06:01:56 -07:00
#if EFI_ENGINE_CONTROL
2021-05-23 10:54:49 -07:00
// todo: reset this between cranking attempts?! #2735
int minCrankingRpm = 0;
2015-07-10 06:01:56 -07:00
/**
* @return ignition timing angle advance before TDC
*/
static angle_t getRunningAdvance(int rpm, float engineLoad) {
if (engineConfiguration->timingMode == TM_FIXED) {
2017-12-03 10:22:29 -08:00
return engineConfiguration->fixedTiming;
2020-03-24 16:55:12 -07:00
}
2015-07-10 06:01:56 -07:00
if (cisnan(engineLoad)) {
2016-11-02 20:01:48 -07:00
warning(CUSTOM_NAN_ENGINE_LOAD, "NaN engine load");
2015-07-10 06:01:56 -07:00
return NAN;
}
2020-03-24 16:55:12 -07:00
2018-07-25 20:30:00 -07:00
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(engineLoad), "invalid el", NAN);
2015-07-10 06:01:56 -07:00
float advanceAngle = interpolate3d(
config->ignitionTable,
config->ignitionLoadBins, engineLoad,
config->ignitionRpmBins, rpm
);
2020-03-24 16:55:12 -07:00
// get advance from the separate table for Idle
if (engineConfiguration->useSeparateAdvanceForIdle &&
engine->module<IdleController>()->isIdlingOrTaper()) {
float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance);
auto [valid, tps] = Sensor::get(SensorType::DriverThrottleIntent);
if (valid) {
// interpolate between idle table and normal (running) table using TPS threshold
advanceAngle = interpolateClamped(0.0f, idleAdvance, engineConfiguration->idlePidDeactivationTpsThreshold, advanceAngle, tps);
}
}
2020-03-24 16:55:12 -07:00
#if EFI_LAUNCH_CONTROL
if (engine->launchController.isLaunchCondition && engineConfiguration->enableLaunchRetard) {
if (engineConfiguration->launchSmoothRetard) {
float launchAngle = engineConfiguration->launchTimingRetard;
int launchAdvanceRpmRange = engineConfiguration->launchTimingRpmRange;
int launchRpm = engineConfiguration->launchRpm;
2020-03-24 16:55:12 -07:00
// interpolate timing from rpm at launch triggered to full retard at launch launchRpm + launchTimingRpmRange
return interpolateClamped(launchRpm, advanceAngle, (launchRpm + launchAdvanceRpmRange), launchAngle, rpm);
} else {
return engineConfiguration->launchTimingRetard;
}
}
#endif /* EFI_LAUNCH_CONTROL */
return advanceAngle;
}
angle_t getAdvanceCorrections(int rpm) {
2016-05-17 21:03:11 -07:00
float iatCorrection;
const auto [iatValid, iat] = Sensor::get(SensorType::Iat);
if (!iatValid) {
2016-05-17 21:03:11 -07:00
iatCorrection = 0;
} else {
iatCorrection = interpolate3d(
config->ignitionIatCorrTable,
config->ignitionIatCorrLoadBins, iat,
config->ignitionIatCorrRpmBins, rpm
);
2016-05-17 21:03:11 -07:00
}
float pidTimingCorrection = engine->module<IdleController>()->getIdleTimingAdjustment(rpm);
2019-04-12 19:07:03 -07:00
#if EFI_TUNER_STUDIO
engine->outputChannels.timingIatCorrection = iatCorrection;
engine->outputChannels.timingCltCorrection = engine->engineState.cltTimingCorrection;
engine->outputChannels.timingPidCorrection = pidTimingCorrection;
engine->outputChannels.multiSparkCounter = engine->engineState.multispark.count;
#endif /* EFI_TUNER_STUDIO */
return iatCorrection
+ engine->engineState.cltTimingCorrection
+ pidTimingCorrection;
2015-07-10 06:01:56 -07:00
}
/**
* @return ignition timing angle advance before TDC for Cranking
*/
static angle_t getCrankingAdvance(int rpm, float engineLoad) {
// get advance from the separate table for Cranking
if (engineConfiguration->useSeparateAdvanceForCranking) {
return interpolate2d(rpm, engineConfiguration->crankingAdvanceBins, engineConfiguration->crankingAdvance);
}
// Interpolate the cranking timing angle to the earlier running angle for faster engine start
angle_t crankingToRunningTransitionAngle = getRunningAdvance(engineConfiguration->cranking.rpm, engineLoad);
// interpolate not from zero, but starting from min. possible rpm detected
if (rpm < minCrankingRpm || minCrankingRpm == 0)
minCrankingRpm = rpm;
return interpolateClamped(minCrankingRpm, engineConfiguration->crankingTimingAngle, engineConfiguration->cranking.rpm, crankingToRunningTransitionAngle, rpm);
}
angle_t getAdvance(int rpm, float engineLoad) {
2019-04-12 19:07:03 -07:00
#if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
2017-12-03 13:45:39 -08:00
if (cisnan(engineLoad)) {
return 0; // any error should already be reported
}
2015-07-10 06:01:56 -07:00
angle_t angle;
bool isCranking = engine->rpmCalculator.isCranking();
if (isCranking) {
angle = getCrankingAdvance(rpm, engineLoad);
2021-10-02 22:30:42 -07:00
assertAngleRange(angle, "crAngle", CUSTOM_ERR_ANGLE_CR);
2018-09-16 19:11:59 -07:00
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "cr_AngleN", 0);
2015-07-10 06:01:56 -07:00
} else {
angle = getRunningAdvance(rpm, engineLoad);
2018-09-16 19:11:59 -07:00
if (cisnan(angle)) {
warning(CUSTOM_ERR_6610, "NaN angle from table");
return 0;
}
}
// Allow correction only if set to dynamic
// AND we're either not cranking OR allowed to correct in cranking
bool allowCorrections = engineConfiguration->timingMode == TM_DYNAMIC
&& (!isCranking || engineConfiguration->useAdvanceCorrectionsForCranking);
if (allowCorrections) {
angle_t correction = getAdvanceCorrections(rpm);
2018-10-07 11:22:05 -07:00
if (!cisnan(correction)) { // correction could be NaN during settings update
angle += correction;
}
2015-07-10 06:01:56 -07:00
}
2018-09-29 11:11:25 -07:00
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(angle), "_AngleN5", 0);
fixAngle(angle, "getAdvance", CUSTOM_ERR_ADCANCE_CALC_ANGLE);
2015-07-10 06:01:56 -07:00
return angle;
2019-01-31 14:55:23 -08:00
#else
return 0;
#endif
2015-07-10 06:01:56 -07:00
}
angle_t getCylinderIgnitionTrim(size_t cylinderNumber, int rpm, float ignitionLoad) {
return interpolate3d(
config->ignTrims[cylinderNumber].table,
config->ignTrimLoadBins, ignitionLoad,
config->ignTrimRpmBins, rpm
);
}
size_t getMultiSparkCount(int rpm) {
// Compute multispark (if enabled)
if (engineConfiguration->multisparkEnable
&& rpm <= engineConfiguration->multisparkMaxRpm
&& engineConfiguration->multisparkMaxExtraSparkCount > 0) {
// For zero RPM, disable multispark. We don't yet know the engine speed, so multispark may not be safe.
if (rpm == 0) {
return 0;
}
floatus_t multiDelay = engineConfiguration->multisparkSparkDuration;
floatus_t multiDwell = engineConfiguration->multisparkDwell;
// dwell times are below 10 seconds here so we use 32 bit type for performance reasons
engine->engineState.multispark.delay = (uint32_t)USF2NT(multiDelay);
engine->engineState.multispark.dwell = (uint32_t)USF2NT(multiDwell);
constexpr float usPerDegreeAt1Rpm = 60e6 / 360;
floatus_t usPerDegree = usPerDegreeAt1Rpm / rpm;
// How long is there for sparks? The user configured an angle, convert to time.
floatus_t additionalSparksUs = usPerDegree * engineConfiguration->multisparkMaxSparkingAngle;
// How long does one spark take?
floatus_t oneSparkTime = multiDelay + multiDwell;
// How many sparks can we fit in the alloted time?
float sparksFitInTime = additionalSparksUs / oneSparkTime;
// Take the floor (convert to uint8_t) - we want to undershoot, not overshoot
uint32_t floored = sparksFitInTime;
// Allow no more than the maximum number of extra sparks
return minI(floored, engineConfiguration->multisparkMaxExtraSparkCount);
} else {
return 0;
}
}
2015-12-24 11:02:03 -08:00
/**
* @param octane gas octane number
* @param bore in mm
*/
float getTopAdvanceForBore(chamber_style_e style, int octane, double compression, double bore) {
int octaneCorrection;
if ( octane <= 90) {
octaneCorrection = -2;
} else if (octane < 94) {
octaneCorrection = -1;
} else {
octaneCorrection = 0;
}
int compressionCorrection;
if (compression <= 9) {
compressionCorrection = 2;
} else if (compression <= 10) {
compressionCorrection = 1;
} else if (compression <= 11) {
compressionCorrection = 0;
} else {
// compression ratio above 11
compressionCorrection = -2;
}
int base;
if (style == CS_OPEN) {
base = 33;
} else if (style == CS_CLOSED) {
base = 28;
} else {
// CS_SWIRL_TUMBLE
base = 22;
}
float boreCorrection = (bore - 4 * 25.4) / 25.4 * 6;
float result = base + octaneCorrection + compressionCorrection + boreCorrection;
return ((int)(result * 10)) / 10.0;
}
2015-12-31 10:02:19 -08:00
#endif // EFI_ENGINE_CONTROL