GCC Code Coverage Report


Directory: ./
File: firmware/controllers/algo/wall_fuel.cpp
Date: 2025-10-24 14:26:41
Coverage Exec Excl Total
Lines: 47.8% 32 0 67
Functions: 83.3% 5 0 6
Branches: 50.0% 17 0 34
Decisions: 40.9% 9 - 22

Line Branch Decision Exec Source
1 /*
2 * @file wall_fuel.cpp
3 *
4 * @author Matthew Kennedy
5 */
6
7 #include "pch.h"
8 #include "wall_fuel.h"
9
10 void WallFuel::resetWF() {
11 wallFuel = 0;
12 }
13
14 9403 float WallFuel::adjust(float desiredMassGrams) {
15 9403 invocationCounter++;
16
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9403 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 9403 times.
9403 if (std::isnan(desiredMassGrams)) {
17 return desiredMassGrams;
18 }
19
20 9403 ScopePerf perf(PE::WallFuelAdjust);
21
22 /*
23 this math is based on
24 SAE 810494 by C. F. Aquino
25 SAE 1999-01-0553 by Peter J Maloney
26
27 M_cmd = commanded fuel mass (output of this function)
28 desiredMassGrams = desired fuel mass (input to this function)
29 fuelFilmMass = fuel film mass (how much is currently on the wall)
30
31 First we compute how much fuel to command, by accounting for
32 a) how much fuel will evaporate from the walls, entering the air
33 b) how much fuel from the injector will hit the walls, being deposited
34
35 Next, we compute how much fuel will be deposited on the walls. The net
36 effect of these two steps is computed (some leaves walls, some is deposited)
37 and stored back in fuelFilmMass.
38
39 alpha describes the amount of fuel that REMAINS on the wall per cycle.
40 It is computed as a function of the evaporation time constant (tau) and
41 the time the fuel spent on the wall this cycle, (recriprocal RPM).
42
43 beta describes the amount of fuel that hits the wall.
44 */
45
46 // If disabled, pass value through
47
4/4
✓ Branch 1 taken 9403 times.
✓ Branch 5 taken 9403 times.
✓ Branch 7 taken 9293 times.
✓ Branch 8 taken 110 times.
2/2
✓ Decision 'true' taken 9293 times.
✓ Decision 'false' taken 110 times.
9403 if (!engine->module<WallFuelController>()->getEnable()) {
48 9293 return desiredMassGrams;
49 }
50
51
2/2
✓ Branch 1 taken 110 times.
✓ Branch 5 taken 110 times.
110 float alpha = engine->module<WallFuelController>()->getAlpha();
52
2/2
✓ Branch 1 taken 110 times.
✓ Branch 5 taken 110 times.
110 float beta = engine->module<WallFuelController>()->getBeta();
53
54 110 float fuelFilmMass = wallFuel;
55 110 float M_cmd = (desiredMassGrams - (1 - alpha) * fuelFilmMass) / (1 - beta);
56
57 // We can't inject a negative amount of fuel
58 // If this goes below zero we will be over-fueling slightly,
59 // but that's ok.
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 110 times.
110 if (M_cmd <= 0) {
61 M_cmd = 0;
62 }
63
64 // remainder on walls from last time + new from this time
65 110 float fuelFilmMassNext = alpha * fuelFilmMass + beta * M_cmd;
66
67 110 wallFuel = fuelFilmMassNext;
68 110 wallFuelCorrection = M_cmd - desiredMassGrams;
69 110 return M_cmd;
70 }
71
72 531078 float WallFuel::getWallFuel() const {
73 531078 return wallFuel;
74 }
75
76 955 float WallFuelController::computeTau() const {
77
1/2
✓ Branch 0 taken 955 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 955 times.
✗ Decision 'false' not taken.
955 if (!engineConfiguration->complexWallModel) {
78 955 return engineConfiguration->wwaeTau;
79 }
80
81 // Default to normal operating temperature in case of
82 // CLT failure, this is not critical to get perfect
83 float clt = Sensor::get(SensorType::Clt).value_or(90);
84
85 float tau = interpolate2d(
86 clt,
87 config->wwCltBins,
88 config->wwTauCltValues
89 );
90
91 // If you have a MAP sensor, apply MAP correction
92 if (Sensor::hasSensor(SensorType::Map)) {
93 auto map = Sensor::get(SensorType::Map).value_or(60);
94
95 tau *= interpolate2d(
96 map,
97 config->wwMapBins,
98 config->wwTauMapValues
99 );
100 }
101
102 return tau;
103 }
104
105 955 float WallFuelController::computeBeta() const {
106
1/2
✓ Branch 0 taken 955 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 955 times.
✗ Decision 'false' not taken.
955 if (!engineConfiguration->complexWallModel) {
107 955 return engineConfiguration->wwaeBeta;
108 }
109
110 // Default to normal operating temperature in case of
111 // CLT failure, this is not critical to get perfect
112 float clt = Sensor::get(SensorType::Clt).value_or(90);
113
114 float beta = interpolate2d(
115 clt,
116 config->wwCltBins,
117 config->wwBetaCltValues
118 );
119
120 // If you have a MAP sensor, apply MAP correction
121 if (Sensor::hasSensor(SensorType::Map)) {
122 auto map = Sensor::get(SensorType::Map).value_or(60);
123
124 beta *= interpolate2d(
125 map,
126 config->wwMapBins,
127 config->wwBetaMapValues
128 );
129 }
130
131 // Clamp to 0..1 (you can't have more than 100% of the fuel hit the wall!)
132 return clampF(0, beta, 1);
133 }
134
135 1101 void WallFuelController::onFastCallback() {
136 // disable wall wetting cranking
137 // TODO: is this correct? Why not correct for cranking?
138
2/2
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 955 times.
2/2
✓ Decision 'true' taken 146 times.
✓ Decision 'false' taken 955 times.
1101 if (engine->rpmCalculator.isCranking()) {
139 146 m_enable = false;
140 146 return;
141 }
142
143 955 float tau = computeTau();
144 955 float beta = computeBeta();
145
146 // if tau or beta is really small, we get div/0.
147 // you probably meant to disable wwae.
148
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 945 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 955 times.
✗ Decision 'false' not taken.
955 if (tau < 0.01f || beta < 0.01f) {
149 955 m_enable = false;
150 955 return;
151 }
152
153 auto rpm = Sensor::getOrZero(SensorType::Rpm);
154
155 // Ignore low RPM
156 if (rpm < 100) {
157 m_enable = false;
158 return;
159 }
160
161 float alpha = expf_taylor(-120 / (rpm * tau));
162
163 // If beta is larger than alpha, the system is underdamped.
164 // For reasonable values {tau, beta}, this should only be possible
165 // at extremely low engine speeds (<300rpm ish)
166 // Clamp beta to less than alpha.
167 if (beta > alpha) {
168 beta = alpha;
169 }
170
171 // Store parameters so the model can read them
172 m_alpha = alpha;
173 m_beta = beta;
174 m_enable = true;
175 }
176