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 | 1086 | AirmassResult SpeedDensityAirmass::getAirmass(float rpm, float map, bool postState) { | ||
15 | /** | |||
16 | * most of the values are pre-calculated for performance reasons | |||
17 | */ | |||
18 | 1086 | float tChargeK = engine->engineState.sd.tChargeK; | ||
19 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1086 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1086 times.
|
1086 | 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 | 1086 | float ve = getVe(rpm, map, postState); | ||
25 | ||||
26 | 1086 | float airMass = getAirmassImpl(ve, map, tChargeK); | ||
27 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1086 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1086 times.
|
1086 | if (std::isnan(airMass)) { |
28 | ✗ | warning(ObdCode::CUSTOM_ERR_6685, "NaN airMass"); | ||
29 | ✗ | return {}; | ||
30 | } | |||
31 | #if EFI_PRINTF_FUEL_DETAILS | |||
32 | 1086 | 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 | 1086 | }; | ||
39 | } | |||
40 | ||||
41 | 1085 | float SpeedDensityAirmass::getAirflow(float rpm, float map, bool postState) { | ||
42 | 1085 | auto airmassResult = getAirmass(rpm, map, postState); | ||
43 | ||||
44 | 1085 | float massPerCycle = airmassResult.CylinderAirmass * engineConfiguration->cylindersCount; | ||
45 | ||||
46 |
2/2✓ Branch 0 taken 1083 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 1083 times.
✓ Decision 'false' taken 2 times.
|
1085 | if (!engineConfiguration->twoStroke) { |
47 | // 4 stroke engines only do a half cycle per rev | |||
48 | 1083 | massPerCycle = massPerCycle / 2; | ||
49 | } | |||
50 | ||||
51 | // g/s | |||
52 | 1085 | 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 |