GCC Code Coverage Report


Directory: ./
File: firmware/controllers/algo/wall_fuel.cpp
Date: 2025-10-03 00:57:22
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 8625 float WallFuel::adjust(float desiredMassGrams) {
15 8625 invocationCounter++;
16
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8625 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8625 times.
8625 if (std::isnan(desiredMassGrams)) {
17 return desiredMassGrams;
18 }
19
20 8625 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 8625 times.
✓ Branch 5 taken 8625 times.
✓ Branch 7 taken 8515 times.
✓ Branch 8 taken 110 times.
2/2
✓ Decision 'true' taken 8515 times.
✓ Decision 'false' taken 110 times.
8625 if (!engine->module<WallFuelController>()->getEnable()) {
48 8515 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 522954 float WallFuel::getWallFuel() const {
73 522954 return wallFuel;
74 }
75
76 975 float WallFuelController::computeTau() const {
77
1/2
✓ Branch 0 taken 975 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 975 times.
✗ Decision 'false' not taken.
975 if (!engineConfiguration->complexWallModel) {
78 975 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 975 float WallFuelController::computeBeta() const {
106
1/2
✓ Branch 0 taken 975 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 975 times.
✗ Decision 'false' not taken.
975 if (!engineConfiguration->complexWallModel) {
107 975 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 1120 void WallFuelController::onFastCallback() {
136 // disable wall wetting cranking
137 // TODO: is this correct? Why not correct for cranking?
138
2/2
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 975 times.
2/2
✓ Decision 'true' taken 145 times.
✓ Decision 'false' taken 975 times.
1120 if (engine->rpmCalculator.isCranking()) {
139 145 m_enable = false;
140 145 return;
141 }
142
143 975 float tau = computeTau();
144 975 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 965 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
1/2
✓ Decision 'true' taken 975 times.
✗ Decision 'false' not taken.
975 if (tau < 0.01f || beta < 0.01f) {
149 975 m_enable = false;
150 975 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