12#define MAX_ADJ (0.25f)
14#define SAVE_AFTER_HITS 1000
42 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
48 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
49 for (
size_t loadIndex = 0; loadIndex < VE_LOAD_COUNT; loadIndex++) {
50 for (
size_t rpmIndex = 0; rpmIndex < VE_RPM_COUNT; rpmIndex++) {
51 trims[bank][loadIndex][rpmIndex] = 0.01 * (loadIndex + rpmIndex * 0.1);
63 for (
size_t loadIndex = 0; loadIndex < VE_LOAD_COUNT; loadIndex++) {
64 for (
size_t rpmIndex = 0; rpmIndex < VE_RPM_COUNT; rpmIndex++) {
68 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
69 k += 1.0f +
trims[bank][loadIndex][rpmIndex];
71 k = k / FT_BANK_COUNT;
84 ltftLoadPending =
false;
93 return 1 / clampF(30, cfg.timeConstant, 3000);
99 float raw = 0.01 * cfg.
maxAdd;
101 return clampF(0, raw, MAX_ADJ);
109 return clampF(-MAX_ADJ, raw, 0);
115 if ((!cfg.enabled) || (ltftSavePending) || (ltftLoadPending)) {
116 ltftLearning =
false;
126 if ((abs(x.Frac) > 0.5) ||
127 (abs(y.Frac) > 0.5)) {
130 ltftLearning =
false;
134 bool adjusted =
false;
138 float weight = 1.0 - hypotf(x.Frac, y.Frac) / hypotf(0.5, 0.5);
141 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
142 float lambdaCorrection = clResult.
banks[bank] - 1.0;
145 if (std::abs(lambdaCorrection) < 0.01f * cfg.deadband) {
150 float trim = m_state->trims[bank][x.Idx][y.Idx];
153 float newTrim =
trim + k * (lambdaCorrection -
trim);
159 newTrim = clampF(getMinAdjustment(), newTrim, getMaxAdjustment());
162 ltftAccummulatedCorrection[bank] += newTrim -
trim;
165 m_state->trims[bank][x.Idx][y.Idx] = newTrim;
170 ltftLearning = adjusted;
173 showUpdateToUser =
true;
188 if ((!cfg.correctionEnabled) || (ltftLoadPending)) {
189 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
190 ltftCorrection[bank] = 1.0f;
192 ltftCorrecting =
false;
203 if ((abs(x.Frac) > 0.5) ||
204 (abs(y.Frac) > 0.5)) {
213 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
214 ltftCorrection[bank] = 1.0f + interpolate3d(
215 m_state->trims[bank],
222 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
223 result.
banks[bank] = ltftCorrection[bank];
226 ltftCorrecting =
true;
234 ltftLoadPending =
false;
239 ltftSavePending =
true;
246 ltftSavePending =
false;
256 for (
size_t bank = 0; bank < FT_BANK_COUNT; bank++) {
257 ltftAccummulatedCorrection[bank] = 0.0;
262 m_state->applyToVe();
265 veNeedRefresh =
true;
270 veNeedRefresh =
false;
278 if (ltftPageRefreshFlag) {
279 ltftPageRefreshFlag =
false;
280 showUpdateToUser =
false;
281 pageRefreshTimer.reset();
284 ltftPageRefreshFlag = showUpdateToUser && pageRefreshTimer.hasElapsedSec(1);
289 m_state->fillRandom();
294 if ((ltftLoadPending) &&
295#
if EFI_SHAFT_POSITION_INPUT
299 efiPrintf(
"LTFT: failed to load calibrations");
301 ltftLoadPending =
false;
302 ltftLoadError =
true;
static bool call_board_override(std::optional< setup_custom_board_overrides_type > board_override)
RpmCalculator rpmCalculator
constexpr auto & module()
void onSlowCallback() override
bool needsDelayedShutoff() override
void init(LtftState *state)
float getMinAdjustment() const
void learn(ClosedLoopFuelResult clResult, float rpm, float fuelLoad)
float getIntegratorGain() const
ClosedLoopFuelResult getTrims(float rpm, float fuelLoad)
float getMaxAdjustment() const
float getSecondsSinceEngineStart(efitick_t nowNt) const
static EngineAccessor engine
static constexpr persistent_config_s * config
static constexpr engine_configuration_s * engineConfiguration
bool settingsLtftRequestWriteToFlash()
constexpr float integrator_dt
std::optional< setup_custom_board_overrides_type > custom_board_LtftTrimToVeApply
static LtftState ltftState
size_t ltftGetTsPageSize()
void applyLongTermFuelTrimToVe()
void resetLongTermFuelTrim()
void devPokeLongTermFuelTrim()
LtftState * ltftGetState()
trim("ETB: trim", SensorCategory.SENSOR_INPUTS, FieldType.INT, 1820, 1.0, -1.0, -1.0, "")
ltftCntDeadband("LTFT learning: in deadband", SensorCategory.SENSOR_INPUTS, FieldType.INT, 2016, 1.0, 0.0, 10000.0, "cnt")
ltftCntMiss("LTFT learning: miss", SensorCategory.SENSOR_INPUTS, FieldType.INT, 2012, 1.0, 0.0, 10000.0, "cnt")
ltftCntHit("LTFT learning: hits", SensorCategory.SENSOR_INPUTS, FieldType.INT, 2008, 1.0, 0.0, 10000.0, "cnt")
state("state", SensorCategory.SENSOR_INPUTS, FieldType.INT8, 1871, 1.0, -1.0, -1.0, "")
bool storageReqestReadID(StorageItemId id)
StorageStatus storageRead(StorageItemId id, uint8_t *ptr, size_t size)
StorageStatus storageWrite(StorageItemId id, const uint8_t *ptr, size_t size)
float banks[FT_BANK_COUNT]
float trims[FT_BANK_COUNT][VE_LOAD_COUNT][VE_RPM_COUNT]
scaled_channel< uint8_t, 10, 1 > maxRemove
scaled_channel< uint8_t, 10, 1 > maxAdd
uint16_t veLoadBins[VE_LOAD_COUNT]
scaled_channel< uint16_t, 10, 1 > veTable[VE_LOAD_COUNT][VE_RPM_COUNT]
uint16_t veRpmBins[VE_RPM_COUNT]
constexpr void setTable(TElement(&dest)[N][M], const VElement value)