firmware/controllers/algo/ignition/ignition_state.cpp
| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | /** | |||
| 2 | * @file ignition_state.cpp | |||
| 3 | * | |||
| 4 | * @date Mar 27, 2013 | |||
| 5 | * @author Andrey Belomutskiy, (c) 2012-2020 | |||
| 6 | * | |||
| 7 | * This file is part of rusEfi - see http://rusefi.com | |||
| 8 | * | |||
| 9 | * rusEfi is free software; you can redistribute it and/or modify it under the terms of | |||
| 10 | * the GNU General Public License as published by the Free Software Foundation; either | |||
| 11 | * version 3 of the License, or (at your option) any later version. | |||
| 12 | * | |||
| 13 | * rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without | |||
| 14 | * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 15 | * GNU General Public License for more details. | |||
| 16 | * | |||
| 17 | * You should have received a copy of the GNU General Public License along with this program. | |||
| 18 | * If not, see <http://www.gnu.org/licenses/>. | |||
| 19 | */ | |||
| 20 | ||||
| 21 | #include "pch.h" | |||
| 22 | ||||
| 23 | #include "idle_thread.h" | |||
| 24 | #include "launch_control.h" | |||
| 25 | #include "gppwm_channel.h" | |||
| 26 | ||||
| 27 | #if EFI_ENGINE_CONTROL | |||
| 28 | ||||
| 29 | static Map3D<TRACTION_CONTROL_ETB_DROP_SLIP_SIZE, TRACTION_CONTROL_ETB_DROP_SPEED_SIZE, int8_t, uint16_t, uint8_t> tcTimingDropTable{"tct"}; | |||
| 30 | static Map3D<TRACTION_CONTROL_ETB_DROP_SLIP_SIZE, TRACTION_CONTROL_ETB_DROP_SPEED_SIZE, int8_t, uint16_t, uint8_t> tcSparkSkipTable{"tcs"}; | |||
| 31 | ||||
| 32 | #if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT | |||
| 33 | ||||
| 34 | /** | |||
| 35 | * @return ignition timing angle advance before TDC | |||
| 36 | */ | |||
| 37 | 81644 | angle_t getRunningAdvance(float rpm, float engineLoad) { | ||
| 38 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 81642 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 81642 times.
|
81644 | if (std::isnan(engineLoad)) { |
| 39 | 2 | warning(ObdCode::CUSTOM_NAN_ENGINE_LOAD, "NaN engine load"); | ||
| 40 | 2 | return NAN; | ||
| 41 | } | |||
| 42 | ||||
| 43 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 81642 times.
|
81642 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(engineLoad), "invalid el", NAN); | |
| 44 | ||||
| 45 | // compute base ignition angle from main table | |||
| 46 | 81642 | float advanceAngle = IgnitionState::getInterpolatedIgnitionAngle(rpm, engineLoad); | ||
| 47 | ||||
| 48 | 81642 | float vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed); | ||
| 49 | 81642 | float wheelSlip = Sensor::getOrZero(SensorType::WheelSlipRatio); | ||
| 50 |
1/1✓ Branch 2 taken 81642 times.
|
81642 | engine->ignitionState.tractionAdvanceDrop = tcTimingDropTable.getValue(wheelSlip, vehicleSpeed); | |
| 51 | 81642 | engine->engineState.tractionControlSparkSkip = tcSparkSkipTable.getValue(wheelSlip, vehicleSpeed); | ||
| 52 | 81642 | engine->engineState.updateSparkSkip(); | ||
| 53 | ||||
| 54 | 81642 | advanceAngle += engine->ignitionState.tractionAdvanceDrop; | ||
| 55 | ||||
| 56 | #if EFI_ANTILAG_SYSTEM | |||
| 57 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 81642 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 81642 times.
|
81642 | if (engine->antilagController.isAntilagCondition) { |
| 58 | ✗ | float throttleIntent = Sensor::getOrZero(SensorType::DriverThrottleIntent); | ||
| 59 | ✗ | engine->antilagController.timingALSCorrection = interpolate3d( | ||
| 60 | ✗ | config->ALSTimingRetardTable, | ||
| 61 | ✗ | config->alsIgnRetardLoadBins, throttleIntent, | ||
| 62 | ✗ | config->alsIgnRetardrpmBins, rpm | ||
| 63 | ); | |||
| 64 | ✗ | advanceAngle += engine->antilagController.timingALSCorrection; | ||
| 65 | } | |||
| 66 | #endif /* EFI_ANTILAG_SYSTEM */ | |||
| 67 | ||||
| 68 | // Add any adjustments if configured | |||
| 69 |
2/2✓ Branch 1 taken 326568 times.
✓ Branch 2 taken 81642 times.
|
2/2✓ Decision 'true' taken 326568 times.
✓ Decision 'false' taken 81642 times.
|
408210 | for (size_t i = 0; i < efi::size(config->ignBlends); i++) { |
| 70 | 326568 | auto result = calculateBlend(config->ignBlends[i], rpm, engineLoad); | ||
| 71 | ||||
| 72 | 326568 | engine->outputChannels.ignBlendParameter[i] = result.BlendParameter; | ||
| 73 | 326568 | engine->outputChannels.ignBlendBias[i] = result.Bias; | ||
| 74 | 326568 | engine->outputChannels.ignBlendOutput[i] = result.Value; | ||
| 75 | 326568 | engine->outputChannels.ignBlendYAxis[i] = result.TableYAxis; | ||
| 76 | ||||
| 77 | 326568 | advanceAngle += result.Value; | ||
| 78 | } | |||
| 79 | ||||
| 80 | // get advance from the separate table for Idle | |||
| 81 | #if EFI_IDLE_CONTROL | |||
| 82 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 81635 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 81637 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 81644 times.
|
81649 | if (engineConfiguration->useSeparateAdvanceForIdle && |
| 83 |
3/4✓ Branch 3 taken 2 times.
✓ Branch 4 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
|
7 | (engine->module<IdleController>()->isIdlingOrTaper() || engine->module<IdleController>()->isCoastingAdvance())) { | |
| 84 |
1/1✓ Branch 1 taken 5 times.
|
5 | float idleAdvance = interpolate2d(rpm, config->idleAdvanceBins, config->idleAdvance); | |
| 85 | ||||
| 86 |
1/1✓ Branch 2 taken 5 times.
|
5 | auto tps = Sensor::get(SensorType::DriverThrottleIntent); | |
| 87 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
|
5 | if (tps) { |
| 88 | // interpolate between idle table and normal (running) table using TPS threshold | |||
| 89 | // 0 TPS -> idle table | |||
| 90 | // 1/2 threshold -> idle table | |||
| 91 | // idle threshold -> normal table | |||
| 92 | 5 | float idleThreshold = engineConfiguration->idlePidDeactivationTpsThreshold; | ||
| 93 |
1/1✓ Branch 1 taken 5 times.
|
5 | advanceAngle = interpolateClamped(idleThreshold / 2, idleAdvance, idleThreshold, advanceAngle, tps.Value); | |
| 94 | } | |||
| 95 | } | |||
| 96 | #endif | |||
| 97 | ||||
| 98 | #if EFI_IDLE_CONTROL | |||
| 99 | // reset ignition table dot, see #8198 | |||
| 100 |
6/6✓ Branch 0 taken 7 times.
✓ Branch 1 taken 81635 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 81637 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 81637 times.
|
81642 | if(engineConfiguration->useSeparateAdvanceForIdle && engine->module<IdleController>()->isIdlingOrTaper()){ |
| 101 | 5 | engine->ignitionState.rpmForIgnitionIdleTableDot = rpm; | ||
| 102 | 5 | engine->ignitionState.rpmForIgnitionTableDot = -1; | ||
| 103 | 5 | engine->ignitionState.loadForIgnitionTableDot = -1; | ||
| 104 | } else { | |||
| 105 | 81637 | engine->ignitionState.rpmForIgnitionIdleTableDot = -1; | ||
| 106 | 81637 | engine->ignitionState.rpmForIgnitionTableDot = rpm; | ||
| 107 | 81637 | engine->ignitionState.loadForIgnitionTableDot = engineLoad; | ||
| 108 | } | |||
| 109 | #endif | |||
| 110 | ||||
| 111 | #if EFI_LAUNCH_CONTROL | |||
| 112 |
4/4✓ Branch 0 taken 692 times.
✓ Branch 1 taken 80950 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 628 times.
|
2/2✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 81578 times.
|
81642 | if (engineConfiguration->launchControlEnabled && engineConfiguration->enableLaunchRetard) { |
| 113 | 64 | const float launchAngle = engineConfiguration->launchTimingRetard; | ||
| 114 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 52 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 52 times.
|
64 | if (engine->launchController.isPreLaunchCondition) { |
| 115 | 12 | const int launchRpm = engineConfiguration->launchRpm; | ||
| 116 | 12 | const int smoothRetardStartRpm = (launchRpm - engineConfiguration->launchRpmWindow); | ||
| 117 | 12 | const int smoothRetardEndRpm = (launchRpm - engineConfiguration->launchCorrectionsEndRpm); | ||
| 118 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 12 times.
✗ Decision 'false' not taken.
|
12 | if (smoothRetardStartRpm <= rpm) { |
| 119 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 8 times.
|
12 | if (engineConfiguration->launchSmoothRetard && (rpm <= smoothRetardEndRpm)) { |
| 120 | // https://github.com/rusefi/rusefi/issues/5611#issuecomment-2130431696 | |||
| 121 | 4 | return interpolateClamped(smoothRetardStartRpm, advanceAngle, smoothRetardEndRpm, launchAngle, rpm); | ||
| 122 | } else { | |||
| 123 | 8 | return launchAngle; | ||
| 124 | } | |||
| 125 | } | |||
| 126 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 42 times.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 42 times.
|
52 | } else if (engine->launchController.isLaunchCondition) { |
| 127 | 10 | return launchAngle; | ||
| 128 | } | |||
| 129 | } | |||
| 130 |
2/2✓ Branch 0 taken 533 times.
✓ Branch 1 taken 81087 times.
|
81620 | if (engineConfiguration->torqueReductionEnabled | |
| 131 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 522 times.
|
533 | && engine->shiftTorqueReductionController.isFlatShiftConditionSatisfied | |
| 132 | ) { | |||
| 133 | 11 | return engine->shiftTorqueReductionController.getTorqueReductionIgnitionRetard(); | ||
| 134 | } | |||
| 135 |
6/6✓ Branch 0 taken 12 times.
✓ Branch 1 taken 81597 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 81605 times.
|
81609 | if (engineConfiguration->nitrousControlEnabled && engine->module<NitrousController>()->isNitrousCondition) { | |
| 136 | 4 | advanceAngle -= engineConfiguration->nitrousIgnitionRetard; | ||
| 137 | } | |||
| 138 | #endif /* EFI_LAUNCH_CONTROL */ | |||
| 139 | ||||
| 140 | #ifdef MODULE_VVL_CONTROLLER | |||
| 141 | 81609 | advanceAngle += engine->module<VvlController>().unmock().getTimingModifier(); | ||
| 142 | #endif /* MODULE_VVL_CONTROLLER */ | |||
| 143 | ||||
| 144 | 81609 | return advanceAngle; | ||
| 145 | } | |||
| 146 | ||||
| 147 | 91140 | angle_t getCltTimingCorrection(float engineLoad) { | ||
| 148 |
1/1✓ Branch 2 taken 91140 times.
|
91140 | const auto clt = Sensor::get(SensorType::Clt); | |
| 149 | ||||
| 150 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 91140 times.
|
91140 | if (!clt) | |
| 151 | ✗ | return 0; // this error should be already reported somewhere else, let's just handle it | ||
| 152 | ||||
| 153 | 182280 | return interpolate3d( | ||
| 154 | 91140 | config->ignitionCltCorrTable, | ||
| 155 | 91140 | config->ignitionCltCorrLoadBins, engineLoad, | ||
| 156 |
1/1✓ Branch 1 taken 91140 times.
|
91140 | config->ignitionCltCorrTempBins, clt.Value | |
| 157 | 91140 | ); | ||
| 158 | } | |||
| 159 | ||||
| 160 | 91140 | void IgnitionState::updateAdvanceCorrections(float engineLoad) { | ||
| 161 |
1/1✓ Branch 2 taken 91140 times.
|
91140 | cltTimingCorrection = getCltTimingCorrection(engineLoad); | |
| 162 | 91140 | } | ||
| 163 | ||||
| 164 | 57345 | angle_t getAdvanceCorrections(float engineLoad) { | ||
| 165 |
1/1✓ Branch 2 taken 57345 times.
|
57345 | auto iat = Sensor::get(SensorType::Iat); | |
| 166 | ||||
| 167 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 57345 times.
|
57345 | if (!iat) { | |
| 168 | ✗ | engine->ignitionState.timingIatCorrection = 0; | ||
| 169 | } else { | |||
| 170 | 114690 | engine->ignitionState.timingIatCorrection = interpolate3d( | ||
| 171 | 57345 | config->ignitionIatCorrTable, | ||
| 172 | 57345 | config->ignitionIatCorrLoadBins, engineLoad, | ||
| 173 |
1/1✓ Branch 1 taken 57345 times.
|
57345 | config->ignitionIatCorrTempBins, iat.Value | |
| 174 | ); | |||
| 175 | } | |||
| 176 | ||||
| 177 | #if EFI_IDLE_CONTROL | |||
| 178 | 57345 | float instantRpm = engine->triggerCentral.instantRpm.getInstantRpm(); | ||
| 179 | ||||
| 180 |
2/2✓ Branch 2 taken 57345 times.
✓ Branch 6 taken 57345 times.
|
57345 | engine->ignitionState.timingPidCorrection = engine->module<IdleController>()->getIdleTimingAdjustment(instantRpm); | |
| 181 | #endif // EFI_IDLE_CONTROL | |||
| 182 | ||||
| 183 |
2/2✓ Branch 2 taken 57345 times.
✓ Branch 6 taken 57345 times.
|
57345 | engine->ignitionState.dfcoTimingRetard = engine->module<DfcoController>()->getTimingRetard(); | |
| 184 | ||||
| 185 | #if EFI_TUNER_STUDIO | |||
| 186 | 57345 | engine->outputChannels.multiSparkCounter = engine->engineState.multispark.count; | ||
| 187 | #endif /* EFI_TUNER_STUDIO */ | |||
| 188 | ||||
| 189 | 57345 | return engine->ignitionState.timingIatCorrection | ||
| 190 | 57345 | + engine->ignitionState.cltTimingCorrection | ||
| 191 | 57345 | + engine->ignitionState.timingPidCorrection | ||
| 192 | 114690 | - engine->ignitionState.dfcoTimingRetard; | ||
| 193 | } | |||
| 194 | ||||
| 195 | /** | |||
| 196 | * @return ignition timing angle advance before TDC for Cranking | |||
| 197 | */ | |||
| 198 | 24285 | angle_t getCrankingAdvance(float rpm, float engineLoad) { | ||
| 199 | // get advance from the separate table for Cranking | |||
| 200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24285 times.
|
24285 | if (engineConfiguration->useSeparateAdvanceForCranking) { | |
| 201 | ✗ | return interpolate2d(rpm, config->crankingAdvanceBins, config->crankingAdvance); | ||
| 202 | } | |||
| 203 | ||||
| 204 | // Interpolate the cranking timing angle to the earlier running angle for faster engine start | |||
| 205 | 24285 | angle_t crankingToRunningTransitionAngle = getRunningAdvance(engineConfiguration->cranking.rpm, engineLoad); | ||
| 206 | // interpolate not from zero, but starting from min. possible rpm detected | |||
| 207 | 24285 | return interpolateClamped(engine->rpmCalculator.getMinCrankingRpm(), engineConfiguration->crankingTimingAngle, engineConfiguration->cranking.rpm, crankingToRunningTransitionAngle, rpm); | ||
| 208 | } | |||
| 209 | #endif // EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT | |||
| 210 | ||||
| 211 | 91142 | angle_t IgnitionState::getAdvance(float rpm, float engineLoad) { | ||
| 212 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 91142 times.
|
91142 | if (std::isnan(engineLoad)) { | |
| 213 | ✗ | return 0; // any error should already be reported | ||
| 214 | } | |||
| 215 |
2/2✓ Branch 0 taken 9515 times.
✓ Branch 1 taken 81627 times.
|
91142 | if (engineConfiguration->timingMode == TM_FIXED) { | |
| 216 | // fixed timing is the simple: cranking/running does not matter, no corrections! | |||
| 217 | 9515 | return engineConfiguration->fixedTiming; | ||
| 218 | } | |||
| 219 | ||||
| 220 | angle_t angle; | |||
| 221 | ||||
| 222 | 81627 | bool isCranking = engine->rpmCalculator.isCranking(); | ||
| 223 |
2/2✓ Branch 0 taken 24283 times.
✓ Branch 1 taken 57344 times.
|
81627 | if (isCranking) { | |
| 224 | 24283 | angle = getCrankingAdvance(rpm, engineLoad); | ||
| 225 |
2/4✓ Branch 0 taken 24283 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24283 times.
|
24283 | assertAngleRange(angle, "crAngle", ObdCode::CUSTOM_ERR_ANGLE_CR); | |
| 226 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24283 times.
|
24283 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(angle), "cr_AngleN", 0); | |
| 227 | } else { | |||
| 228 | 57344 | angle = getRunningAdvance(rpm, engineLoad); | ||
| 229 | ||||
| 230 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 57344 times.
|
57344 | if (std::isnan(angle)) { | |
| 231 | ✗ | warning(ObdCode::CUSTOM_ERR_6610, "NaN angle from table"); | ||
| 232 | ✗ | return 0; | ||
| 233 | } | |||
| 234 | } | |||
| 235 | ||||
| 236 | // Allow if we're either not cranking OR allowed to correct in cranking | |||
| 237 |
3/4✓ Branch 0 taken 24283 times.
✓ Branch 1 taken 57344 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24283 times.
|
81627 | bool allowCorrections = !isCranking || engineConfiguration->useAdvanceCorrectionsForCranking; | |
| 238 | ||||
| 239 |
2/2✓ Branch 0 taken 57344 times.
✓ Branch 1 taken 24283 times.
|
81627 | if (allowCorrections) { | |
| 240 | 57344 | angle_t correction = getAdvanceCorrections(engineLoad); | ||
| 241 |
1/2✓ Branch 1 taken 57344 times.
✗ Branch 2 not taken.
|
57344 | if (!std::isnan(correction)) { // correction could be NaN during settings update | |
| 242 | 57344 | angle += correction; | ||
| 243 | } | |||
| 244 | } | |||
| 245 | ||||
| 246 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 81627 times.
|
81627 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(angle), "_AngleN5", 0); | |
| 247 | 81627 | return angle; | ||
| 248 | } | |||
| 249 | ||||
| 250 | 91142 | angle_t IgnitionState::getWrappedAdvance(const float rpm, const float engineLoad) { | ||
| 251 |
1/1✓ Branch 2 taken 91142 times.
|
91142 | angle_t angle = getAdvance(rpm, engineLoad) * luaTimingMult + luaTimingAdd; | |
| 252 |
1/1✓ Branch 1 taken 91142 times.
|
91142 | wrapAngle(angle, "getWrappedAdvance", ObdCode::CUSTOM_ERR_ADCANCE_CALC_ANGLE); | |
| 253 | 91142 | return angle; | ||
| 254 | } | |||
| 255 | ||||
| 256 | PUBLIC_API_WEAK_SOMETHING_WEIRD | |||
| 257 | 354185 | angle_t getCylinderIgnitionTrim(size_t cylinderNumber, float rpm, float ignitionLoad) { | ||
| 258 | 354185 | return IgnitionState::getInterpolatedIgnitionTrim(cylinderNumber, rpm, ignitionLoad); | ||
| 259 | } | |||
| 260 | ||||
| 261 | 91161 | size_t getMultiSparkCount(float rpm) { | ||
| 262 | // Compute multispark (if enabled) | |||
| 263 | 182322 | if (engineConfiguration->multisparkEnable | ||
| 264 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
|
13 | && rpm <= engineConfiguration->multisparkMaxRpm | |
| 265 |
5/6✓ Branch 0 taken 13 times.
✓ Branch 1 taken 91148 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 91150 times.
|
91174 | && engineConfiguration->multisparkMaxExtraSparkCount > 0) { | |
| 266 | // For zero RPM, disable multispark. We don't yet know the engine speed, so multispark may not be safe. | |||
| 267 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 10 times.
|
11 | if (rpm == 0) { | |
| 268 | 1 | return 0; | ||
| 269 | } | |||
| 270 | ||||
| 271 | 10 | floatus_t multiDelay = 1000.0f * engineConfiguration->multisparkSparkDuration; | ||
| 272 | 10 | floatus_t multiDwell = 1000.0f * engineConfiguration->multisparkDwell; | ||
| 273 | ||||
| 274 | // dwell times are below 10 seconds here so we use 32 bit type for performance reasons | |||
| 275 | 10 | engine->engineState.multispark.delay = (uint32_t)USF2NT(multiDelay); | ||
| 276 | 10 | engine->engineState.multispark.dwell = (uint32_t)USF2NT(multiDwell); | ||
| 277 | ||||
| 278 | 10 | constexpr float usPerDegreeAt1Rpm = 60e6 / 360; | ||
| 279 | 10 | floatus_t usPerDegree = usPerDegreeAt1Rpm / rpm; | ||
| 280 | ||||
| 281 | // How long is there for sparks? The user configured an angle, convert to time. | |||
| 282 | 10 | floatus_t additionalSparksUs = usPerDegree * engineConfiguration->multisparkMaxSparkingAngle; | ||
| 283 | // How long does one spark take? | |||
| 284 | 10 | floatus_t oneSparkTime = multiDelay + multiDwell; | ||
| 285 | ||||
| 286 | // How many sparks can we fit in the alloted time? | |||
| 287 | 10 | float sparksFitInTime = additionalSparksUs / oneSparkTime; | ||
| 288 | ||||
| 289 | // Take the floor (convert to uint8_t) - we want to undershoot, not overshoot | |||
| 290 | 10 | uint32_t floored = sparksFitInTime; | ||
| 291 | ||||
| 292 | // Allow no more than the maximum number of extra sparks | |||
| 293 | 10 | return minI(floored, engineConfiguration->multisparkMaxExtraSparkCount); | ||
| 294 | } else { | |||
| 295 | 91150 | return 0; | ||
| 296 | } | |||
| 297 | } | |||
| 298 | ||||
| 299 | 607 | void initIgnitionAdvanceControl() { | ||
| 300 | 607 | tcTimingDropTable.initTable(engineConfiguration->tractionControlTimingDrop, engineConfiguration->tractionControlSlipBins, engineConfiguration->tractionControlSpeedBins); | ||
| 301 | 607 | tcSparkSkipTable.initTable(engineConfiguration->tractionControlIgnitionSkip, engineConfiguration->tractionControlSlipBins, engineConfiguration->tractionControlSpeedBins); | ||
| 302 | 607 | } | ||
| 303 | ||||
| 304 | /** | |||
| 305 | * @return Spark dwell time, in milliseconds. 0 if tables are not ready. | |||
| 306 | */ | |||
| 307 | 91144 | floatms_t IgnitionState::getSparkDwell(float rpm, bool isCranking) { | ||
| 308 | float dwellMs; | |||
| 309 |
2/2✓ Branch 0 taken 29500 times.
✓ Branch 1 taken 61644 times.
|
91144 | if (isCranking) { | |
| 310 | 29500 | dwellMs = engineConfiguration->ignitionDwellForCrankingMs; | ||
| 311 | } else { | |||
| 312 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 61644 times.
|
61644 | efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(rpm), "invalid rpm", NAN); | |
| 313 | ||||
| 314 | 61644 | baseDwell = interpolate2d(rpm, config->sparkDwellRpmBins, config->sparkDwellValues); | ||
| 315 | 61644 | dwellVoltageCorrection = interpolate2d( | ||
| 316 | Sensor::getOrZero(SensorType::BatteryVoltage), | |||
| 317 | 61644 | config->dwellVoltageCorrVoltBins, | ||
| 318 | 61644 | config->dwellVoltageCorrValues | ||
| 319 | ); | |||
| 320 | ||||
| 321 | // for compat (table full of zeroes) | |||
| 322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61644 times.
|
61644 | if (dwellVoltageCorrection < 0.1f) { | |
| 323 | ✗ | dwellVoltageCorrection = 1; | ||
| 324 | } | |||
| 325 | ||||
| 326 | 61644 | dwellMs = baseDwell * dwellVoltageCorrection; | ||
| 327 | } | |||
| 328 | ||||
| 329 |
3/6✓ Branch 1 taken 91144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 91144 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91144 times.
|
91144 | if (std::isnan(dwellMs) || dwellMs <= 0) { | |
| 330 | // this could happen during engine configuration reset | |||
| 331 | ✗ | warning(ObdCode::CUSTOM_ERR_DWELL_DURATION, "invalid dwell: %.2f at rpm=%.0f", dwellMs, rpm); | ||
| 332 | ✗ | return 0; | ||
| 333 | } | |||
| 334 | 91144 | return dwellMs; | ||
| 335 | } | |||
| 336 | ||||
| 337 | 91144 | void IgnitionState::updateDwell(float rpm, bool isCranking) { | ||
| 338 | 91144 | sparkDwell = getSparkDwell(rpm, isCranking); | ||
| 339 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 91144 times.
|
91144 | dwellDurationAngle = std::isnan(rpm) ? NAN : getDwell() / getOneDegreeTimeMs(rpm); | |
| 340 | 91144 | } | ||
| 341 | ||||
| 342 | 661708 | floatms_t IgnitionState::getDwell() const { | ||
| 343 | 661708 | return sparkDwell; | ||
| 344 | } | |||
| 345 | ||||
| 346 | 91140 | angle_t IgnitionState::getTrailingSparkAngle(const float rpm, const float engineLoad){ | ||
| 347 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 91140 times.
|
91140 | if (std::isnan(engineLoad)) { | |
| 348 | // default value from: https://github.com/rusefi/rusefi/commit/86683afca22ed1a8af8fd5ac9231442e2124646e#diff-6e80cdd8c55add68105618ad9e8954170a47f59814201dadd2b888509d6b2e39R176 | |||
| 349 | ✗ | return 10; | ||
| 350 | } | |||
| 351 | 182280 | return interpolate3d( | ||
| 352 | 91140 | config->trailingSparkTable, | ||
| 353 | 91140 | config->trailingSparkLoadBins, engineLoad, | ||
| 354 | 91140 | config->trailingSparkRpmBins, rpm | ||
| 355 | 91140 | ); | ||
| 356 | } | |||
| 357 | ||||
| 358 | 354185 | angle_t IgnitionState::getSparkHardwareLatencyCorrection(){ | ||
| 359 | // time => degree | |||
| 360 | 354185 | angle_t correction = engineConfiguration->sparkHardwareLatencyCorrection / engine->rpmCalculator.oneDegreeUs; | ||
| 361 | ||||
| 362 |
2/2✓ Branch 1 taken 215018 times.
✓ Branch 2 taken 139167 times.
|
354185 | if (!std::isnan(correction)) { | |
| 363 | 215018 | return correction; | ||
| 364 | } | |||
| 365 | 139167 | return 0; | ||
| 366 | } | |||
| 367 | ||||
| 368 | 81642 | angle_t IgnitionState::getInterpolatedIgnitionAngle(const float rpm, const float ignitionLoad) { | ||
| 369 | 163284 | return interpolate3d( | ||
| 370 | 81642 | config->ignitionTable, | ||
| 371 | 81642 | config->ignitionLoadBins, ignitionLoad, | ||
| 372 | 81642 | config->ignitionRpmBins, rpm | ||
| 373 | 81642 | ); | ||
| 374 | } | |||
| 375 | ||||
| 376 | 354185 | angle_t IgnitionState::getInterpolatedIgnitionTrim( | ||
| 377 | const size_t cylinderNumber, | |||
| 378 | const float rpm, | |||
| 379 | const float ignitionLoad | |||
| 380 | ) { | |||
| 381 | 708370 | return interpolate3d( | ||
| 382 | 354185 | config->ignTrims[cylinderNumber].table, | ||
| 383 | 354185 | config->ignTrimLoadBins, ignitionLoad, | ||
| 384 | 354185 | config->ignTrimRpmBins, rpm | ||
| 385 | 354185 | ); | ||
| 386 | } | |||
| 387 | ||||
| 388 | #endif // EFI_ENGINE_CONTROL | |||
| 389 |