2021-10-16 17:16:40 -07:00
|
|
|
/*
|
|
|
|
* @file wall_fuel.cpp
|
|
|
|
*
|
|
|
|
* @author Matthew Kennedy
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "wall_fuel.h"
|
|
|
|
|
|
|
|
void WallFuel::resetWF() {
|
|
|
|
wallFuel = 0;
|
|
|
|
}
|
|
|
|
|
2021-11-25 15:45:44 -08:00
|
|
|
float WallFuel::adjust(float desiredMassGrams) {
|
2021-10-16 17:16:40 -07:00
|
|
|
invocationCounter++;
|
2024-07-22 12:15:40 -07:00
|
|
|
if (std::isnan(desiredMassGrams)) {
|
2021-11-25 15:45:44 -08:00
|
|
|
return desiredMassGrams;
|
2021-10-16 17:16:40 -07:00
|
|
|
}
|
2021-11-25 15:45:44 -08:00
|
|
|
|
2021-10-16 17:16:40 -07:00
|
|
|
ScopePerf perf(PE::WallFuelAdjust);
|
|
|
|
|
|
|
|
/*
|
|
|
|
this math is based on
|
|
|
|
SAE 810494 by C. F. Aquino
|
|
|
|
SAE 1999-01-0553 by Peter J Maloney
|
|
|
|
|
|
|
|
M_cmd = commanded fuel mass (output of this function)
|
2021-11-25 15:45:44 -08:00
|
|
|
desiredMassGrams = desired fuel mass (input to this function)
|
2021-10-16 17:16:40 -07:00
|
|
|
fuelFilmMass = fuel film mass (how much is currently on the wall)
|
|
|
|
|
|
|
|
First we compute how much fuel to command, by accounting for
|
|
|
|
a) how much fuel will evaporate from the walls, entering the air
|
|
|
|
b) how much fuel from the injector will hit the walls, being deposited
|
|
|
|
|
|
|
|
Next, we compute how much fuel will be deposited on the walls. The net
|
|
|
|
effect of these two steps is computed (some leaves walls, some is deposited)
|
|
|
|
and stored back in fuelFilmMass.
|
|
|
|
|
|
|
|
alpha describes the amount of fuel that REMAINS on the wall per cycle.
|
|
|
|
It is computed as a function of the evaporation time constant (tau) and
|
|
|
|
the time the fuel spent on the wall this cycle, (recriprocal RPM).
|
|
|
|
|
|
|
|
beta describes the amount of fuel that hits the wall.
|
|
|
|
*/
|
|
|
|
|
2022-01-27 04:45:50 -08:00
|
|
|
// If disabled, pass value through
|
|
|
|
if (!engine->module<WallFuelController>()->getEnable()) {
|
2021-11-25 15:45:44 -08:00
|
|
|
return desiredMassGrams;
|
2021-10-16 17:16:40 -07:00
|
|
|
}
|
|
|
|
|
2022-01-27 04:45:50 -08:00
|
|
|
float alpha = engine->module<WallFuelController>()->getAlpha();
|
|
|
|
float beta = engine->module<WallFuelController>()->getBeta();
|
2021-10-16 17:16:40 -07:00
|
|
|
|
|
|
|
float fuelFilmMass = wallFuel;
|
2021-11-25 15:45:44 -08:00
|
|
|
float M_cmd = (desiredMassGrams - (1 - alpha) * fuelFilmMass) / (1 - beta);
|
2021-10-16 17:16:40 -07:00
|
|
|
|
|
|
|
// We can't inject a negative amount of fuel
|
|
|
|
// If this goes below zero we will be over-fueling slightly,
|
|
|
|
// but that's ok.
|
|
|
|
if (M_cmd <= 0) {
|
|
|
|
M_cmd = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remainder on walls from last time + new from this time
|
|
|
|
float fuelFilmMassNext = alpha * fuelFilmMass + beta * M_cmd;
|
|
|
|
|
|
|
|
wallFuel = fuelFilmMassNext;
|
2021-11-25 15:45:44 -08:00
|
|
|
wallFuelCorrection = M_cmd - desiredMassGrams;
|
2021-10-16 17:16:40 -07:00
|
|
|
return M_cmd;
|
|
|
|
}
|
|
|
|
|
2021-11-25 15:45:44 -08:00
|
|
|
float WallFuel::getWallFuel() const {
|
2021-10-16 17:16:40 -07:00
|
|
|
return wallFuel;
|
|
|
|
}
|
2022-01-27 04:45:50 -08:00
|
|
|
|
2022-01-27 21:32:36 -08:00
|
|
|
float WallFuelController::computeTau() const {
|
|
|
|
if (!engineConfiguration->complexWallModel) {
|
|
|
|
return engineConfiguration->wwaeTau;
|
|
|
|
}
|
2022-01-27 04:45:50 -08:00
|
|
|
|
2022-01-27 21:32:36 -08:00
|
|
|
// Default to normal operating temperature in case of
|
|
|
|
// CLT failure, this is not critical to get perfect
|
|
|
|
float clt = Sensor::get(SensorType::Clt).value_or(90);
|
|
|
|
|
|
|
|
float tau = interpolate2d(
|
|
|
|
clt,
|
2024-03-17 12:06:14 -07:00
|
|
|
config->wwCltBins,
|
|
|
|
config->wwTauCltValues
|
2022-01-27 21:32:36 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// If you have a MAP sensor, apply MAP correction
|
|
|
|
if (Sensor::hasSensor(SensorType::Map)) {
|
|
|
|
auto map = Sensor::get(SensorType::Map).value_or(60);
|
|
|
|
|
|
|
|
tau *= interpolate2d(
|
|
|
|
map,
|
2024-03-17 12:06:14 -07:00
|
|
|
config->wwMapBins,
|
|
|
|
config->wwTauMapValues
|
2022-01-27 21:32:36 -08:00
|
|
|
);
|
|
|
|
}
|
2022-01-27 04:45:50 -08:00
|
|
|
|
2022-01-27 21:32:36 -08:00
|
|
|
return tau;
|
2022-01-27 04:45:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
float WallFuelController::computeBeta() const {
|
2022-01-27 21:32:36 -08:00
|
|
|
if (!engineConfiguration->complexWallModel) {
|
|
|
|
return engineConfiguration->wwaeBeta;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default to normal operating temperature in case of
|
|
|
|
// CLT failure, this is not critical to get perfect
|
|
|
|
float clt = Sensor::get(SensorType::Clt).value_or(90);
|
|
|
|
|
|
|
|
float beta = interpolate2d(
|
|
|
|
clt,
|
2024-03-17 12:06:14 -07:00
|
|
|
config->wwCltBins,
|
|
|
|
config->wwBetaCltValues
|
2022-01-27 21:32:36 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// If you have a MAP sensor, apply MAP correction
|
|
|
|
if (Sensor::hasSensor(SensorType::Map)) {
|
|
|
|
auto map = Sensor::get(SensorType::Map).value_or(60);
|
|
|
|
|
|
|
|
beta *= interpolate2d(
|
|
|
|
map,
|
2024-03-17 12:06:14 -07:00
|
|
|
config->wwMapBins,
|
|
|
|
config->wwBetaMapValues
|
2022-01-27 21:32:36 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp to 0..1 (you can't have more than 100% of the fuel hit the wall!)
|
|
|
|
return clampF(0, beta, 1);
|
2022-01-27 04:45:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WallFuelController::onFastCallback() {
|
|
|
|
// disable wall wetting cranking
|
|
|
|
// TODO: is this correct? Why not correct for cranking?
|
|
|
|
if (engine->rpmCalculator.isCranking()) {
|
|
|
|
m_enable = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float tau = computeTau();
|
|
|
|
float beta = computeBeta();
|
|
|
|
|
|
|
|
// if tau or beta is really small, we get div/0.
|
|
|
|
// you probably meant to disable wwae.
|
|
|
|
if (tau < 0.01f || beta < 0.01f) {
|
|
|
|
m_enable = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto rpm = Sensor::getOrZero(SensorType::Rpm);
|
|
|
|
|
|
|
|
// Ignore low RPM
|
|
|
|
if (rpm < 100) {
|
|
|
|
m_enable = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float alpha = expf_taylor(-120 / (rpm * tau));
|
|
|
|
|
|
|
|
// If beta is larger than alpha, the system is underdamped.
|
|
|
|
// For reasonable values {tau, beta}, this should only be possible
|
|
|
|
// at extremely low engine speeds (<300rpm ish)
|
|
|
|
// Clamp beta to less than alpha.
|
|
|
|
if (beta > alpha) {
|
|
|
|
beta = alpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store parameters so the model can read them
|
|
|
|
m_alpha = alpha;
|
|
|
|
m_beta = beta;
|
|
|
|
m_enable = true;
|
|
|
|
}
|