| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | #include "pch.h" | |||
| 2 | #include "speed_density_airmass.h" | |||
| 3 | #include "accel_enrichment.h" | |||
| 4 | ||||
| 5 | ||||
| 6 | 1 | AirmassResult SpeedDensityAirmass::getAirmass(float rpm, bool postState) { | ||
| 7 | 1 | ScopePerf perf(PE::GetSpeedDensityFuel); | ||
| 8 | ||||
| 9 |
1/1✓ Branch 1 taken 1 time.
|
1 | auto map = getMap(rpm, postState); | |
| 10 | ||||
| 11 |
1/1✓ Branch 1 taken 1 time.
|
2 | return getAirmass(rpm, map, postState); | |
| 12 | } | |||
| 13 | ||||
| 14 | 1087 | AirmassResult SpeedDensityAirmass::getAirmass(float rpm, float map, bool postState) { | ||
| 15 | /** | |||
| 16 | * most of the values are pre-calculated for performance reasons | |||
| 17 | */ | |||
| 18 | 1087 | float tChargeK = engine->engineState.sd.tChargeK; | ||
| 19 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1087 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1087 times.
|
1087 | if (std::isnan(tChargeK)) { |
| 20 | ✗ | warning(ObdCode::CUSTOM_ERR_TCHARGE_NOT_READY2, "tChargeK not ready"); // this would happen before we have CLT reading for example | ||
| 21 | ✗ | return {}; | ||
| 22 | } | |||
| 23 | ||||
| 24 | 1087 | float ve = getVe(rpm, map, postState); | ||
| 25 | ||||
| 26 | 1087 | float airMass = getAirmassImpl(ve, map, tChargeK); | ||
| 27 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1087 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1087 times.
|
1087 | if (std::isnan(airMass)) { |
| 28 | ✗ | warning(ObdCode::CUSTOM_ERR_6685, "NaN airMass"); | ||
| 29 | ✗ | return {}; | ||
| 30 | } | |||
| 31 | #if EFI_PRINTF_FUEL_DETAILS | |||
| 32 | 1087 | printf("getSpeedDensityAirmass map=%.2f\n", map); | ||
| 33 | #endif /*EFI_PRINTF_FUEL_DETAILS */ | |||
| 34 | ||||
| 35 | return { | |||
| 36 | airMass, | |||
| 37 | map, // AFR/VE table Y axis | |||
| 38 | 1087 | }; | ||
| 39 | } | |||
| 40 | ||||
| 41 | 1086 | float SpeedDensityAirmass::getAirflow(float rpm, float map, bool postState) { | ||
| 42 | 1086 | auto airmassResult = getAirmass(rpm, map, postState); | ||
| 43 | ||||
| 44 | 1086 | float massPerCycle = airmassResult.CylinderAirmass * engineConfiguration->cylindersCount; | ||
| 45 | ||||
| 46 |
2/2✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 1084 times.
✓ Decision 'false' taken 2 times.
|
1086 | if (!engineConfiguration->twoStroke) { |
| 47 | // 4 stroke engines only do a half cycle per rev | |||
| 48 | 1084 | massPerCycle = massPerCycle / 2; | ||
| 49 | } | |||
| 50 | ||||
| 51 | // g/s | |||
| 52 | 1086 | return massPerCycle * rpm / 60; | ||
| 53 | } | |||
| 54 | ||||
| 55 | 9 | float SpeedDensityAirmass::getPredictiveMap(float rpm, bool postState, float mapSensor) { | ||
| 56 | 18 | float blendDuration = interpolate2d(rpm, config->predictiveMapBlendDurationBins, | ||
| 57 | 9 | config->predictiveMapBlendDurationValues); | ||
| 58 | ||||
| 59 | 9 | float elapsedTime = m_predictionTimer.getElapsedSeconds(); | ||
| 60 | ||||
| 61 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 5 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 8 times.
|
9 | if (m_isMapPredictionActive && elapsedTime >= blendDuration) { |
| 62 | // prediction phase is over | |||
| 63 | 1 | m_isMapPredictionActive = false; | ||
| 64 | } | |||
| 65 | ||||
| 66 | 9 | float effectiveMap = 0; | ||
| 67 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 4 times.
|
9 | if (m_isMapPredictionActive) { |
| 68 | 5 | float blendFactor = elapsedTime / blendDuration; | ||
| 69 | // Linearly interpolate between the initial predicted and real values | |||
| 70 | 5 | effectiveMap = m_initialPredictedMap + (m_initialRealMap - m_initialPredictedMap) * blendFactor; | ||
| 71 | ||||
| 72 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 4 times.
|
5 | if (mapSensor >= effectiveMap) { |
| 73 | 1 | m_isMapPredictionActive = false; | ||
| 74 | } | |||
| 75 | } else { | |||
| 76 |
2/2✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
|
4 | if (engine->module<TpsAccelEnrichment>()->isAccelEventTriggered()) { |
| 77 | 2 | float predictedMap = logAndGetFallback(rpm, postState); | ||
| 78 | ||||
| 79 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 2 times.
✗ Decision 'false' not taken.
|
2 | if (predictedMap > mapSensor) { |
| 80 | 2 | m_isMapPredictionActive = true; | ||
| 81 | 2 | engine->module<TpsAccelEnrichment>()->m_timeSinceAccel.reset(); | ||
| 82 | 2 | m_predictionTimer.reset(); | ||
| 83 | 2 | m_initialPredictedMap = predictedMap; | ||
| 84 | 2 | m_initialRealMap = mapSensor; | ||
| 85 | 2 | effectiveMap = predictedMap; | ||
| 86 | } | |||
| 87 | } | |||
| 88 | } | |||
| 89 | 9 | engine->outputChannels.isMapPredictionActive = m_isMapPredictionActive; | ||
| 90 | ||||
| 91 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
2/2✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 6 times.
|
9 | if (!m_isMapPredictionActive) { |
| 92 | 3 | effectiveMap = mapSensor; | ||
| 93 | } | |||
| 94 | ||||
| 95 | #if EFI_TUNER_STUDIO | |||
| 96 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 8 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 8 times.
|
9 | if (postState) { |
| 97 | 1 | engine->outputChannels.effectiveMap = effectiveMap; | ||
| 98 | } | |||
| 99 | #endif // EFI_TUNER_STUDIO | |||
| 100 | ||||
| 101 | 9 | return effectiveMap; | ||
| 102 | } | |||
| 103 | ||||
| 104 | 6 | float SpeedDensityAirmass::logAndGetFallback(float rpm, bool postState) const { | ||
| 105 | 6 | float fallbackMap = m_mapEstimationTable->getValue(rpm, Sensor::getOrZero(SensorType::Tps1)); | ||
| 106 | #if EFI_TUNER_STUDIO | |||
| 107 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 4 times.
|
6 | if (postState) { |
| 108 | 2 | engine->outputChannels.fallbackMap = fallbackMap; | ||
| 109 | } | |||
| 110 | #endif // EFI_TUNER_STUDIO | |||
| 111 | 6 | return fallbackMap; | ||
| 112 | } | |||
| 113 | ||||
| 114 | 13 | float SpeedDensityAirmass::getMap(float rpm, bool postState) { | ||
| 115 |
1/1✓ Branch 2 taken 13 times.
|
13 | auto mapSensor = Sensor::get(SensorType::Map); | |
| 116 |
6/6✓ Branch 1 taken 11 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 4 times.
|
2/2✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 4 times.
|
13 | if (mapSensor && engineConfiguration->accelEnrichmentMode == AE_MODE_PREDICTIVE_MAP) { |
| 117 |
1/1✓ Branch 1 taken 9 times.
|
9 | return getPredictiveMap(rpm, postState, mapSensor.Value); | |
| 118 | } | |||
| 119 |
1/1✓ Branch 1 taken 4 times.
|
4 | return mapSensor.value_or(logAndGetFallback(rpm, postState)); | |
| 120 | } | |||
| 121 |