Usable fuel consumption data/gauges (#2474)

* fuel consumption

* gauge names

* consumers

* obd

* binary logging

* doesn't need explicit constructor

* getters

* it works

* correct for injections per cycle

* datalog

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2021-03-19 14:04:42 -07:00 committed by GitHub
parent b0948589ac
commit 650d148008
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 52 additions and 63 deletions

View File

@ -158,7 +158,8 @@ typedef struct {
// Fuel system
scaled_percent fuelTankLevel; // 98
float fuelConsumptionPerHour; // 100
scaled_channel<uint16_t> totalFuelConsumption; // 100
scaled_channel<uint16_t, PACK_MULT_FUEL_FLOW> fuelFlowRate; // 102
// Y axis values for selectable tables
scaled_channel<uint16_t, 100> veTableYAxis; // 104

View File

@ -64,6 +64,8 @@ static const LogField fields[] = {
{tsOutputChannels.ignitionLoad, GAUGE_NAME_IGNITION_LOAD, "%", 1},
{tsOutputChannels.massAirFlow, GAUGE_NAME_AIR_FLOW, "kg/h", 1},
{tsOutputChannels.flexPercent, GAUGE_NAME_FLEX, "%", 1},
{tsOutputChannels.fuelFlowRate, GAUGE_NAME_FUEL_FLOW, "g/s", 3},
{tsOutputChannels.totalFuelConsumption, GAUGE_NAME_FUEL_CONSUMPTION, "g", 1},
};
void writeHeader(Writer& outBuffer) {

View File

@ -705,7 +705,8 @@ void updateTunerStudioState(TunerStudioOutputChannels *tsOutputChannels DECLARE_
#endif /* EFI_VEHICLE_SPEED */
#endif /* EFI_PROD_CODE */
tsOutputChannels->fuelConsumptionPerHour = engine->engineState.fuelConsumption.perSecondConsumption;
tsOutputChannels->fuelFlowRate = engine->engineState.fuelConsumption.getConsumptionGramPerSecond();
tsOutputChannels->totalFuelConsumption = engine->engineState.fuelConsumption.getConsumedGrams();
tsOutputChannels->warningCounter = engine->engineState.warnings.warningCounter;
tsOutputChannels->lastErrorCode = engine->engineState.warnings.lastErrorCode;

View File

@ -76,34 +76,25 @@ void MockAdcState::setMockVoltage(int hwChannel, float voltage DECLARE_ENGINE_PA
}
#endif /* EFI_ENABLE_MOCK_ADC */
FuelConsumptionState::FuelConsumptionState() {
accumulatedSecondPrevNt = accumulatedMinutePrevNt = getTimeNowNt();
}
void FuelConsumptionState::consumeFuel(float grams, efitick_t nowNt) {
m_consumedGrams += grams;
void FuelConsumptionState::addData(float durationMs) {
if (durationMs > 0.0f) {
perSecondAccumulator += durationMs;
perMinuteAccumulator += durationMs;
float elapsedSecond = m_timer.getElapsedSecondsAndReset(nowNt);
// If it's been a long time since last injection, ignore this pulse
if (elapsedSecond > 0.2f) {
m_rate = 0;
} else {
m_rate = grams / elapsedSecond;
}
}
void FuelConsumptionState::update(efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
efitick_t deltaNt = nowNt - accumulatedSecondPrevNt;
if (deltaNt >= NT_PER_SECOND) {
perSecondConsumption = getFuelRate(perSecondAccumulator, deltaNt PASS_ENGINE_PARAMETER_SUFFIX);
perSecondAccumulator = 0;
accumulatedSecondPrevNt = nowNt;
}
deltaNt = nowNt - accumulatedMinutePrevNt;
if (deltaNt >= NT_PER_SECOND * 60) {
perMinuteConsumption = getFuelRate(perMinuteAccumulator, deltaNt PASS_ENGINE_PARAMETER_SUFFIX);
perMinuteAccumulator = 0;
accumulatedMinutePrevNt = nowNt;
}
float FuelConsumptionState::getConsumedGrams() const {
return m_consumedGrams;
}
TransmissionState::TransmissionState() {
float FuelConsumptionState::getConsumptionGramPerSecond() const {
return m_rate;
}
EngineState::EngineState() {
@ -144,9 +135,6 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
auto clResult = fuelClosedLoopCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
running.pidCorrection = clResult.banks[0];
// update fuel consumption states
fuelConsumption.update(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
// Fuel cut-off isn't just 0 or 1, it can be tapered
fuelCutoffCorrection = getFuelCutOffCorrection(nowNt, rpm PASS_ENGINE_PARAMETER_SUFFIX);

View File

@ -10,6 +10,7 @@
#include "global.h"
#include "engine_configuration_generated_structures.h"
#include "cyclic_buffer.h"
#include "timer.h"
#define MOCK_ADC_SIZE 26
@ -39,20 +40,20 @@ public:
class FuelConsumptionState {
public:
FuelConsumptionState();
void addData(float durationMs);
void update(efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX);
float perSecondConsumption = 0;
float perMinuteConsumption = 0;
float perSecondAccumulator = 0;
float perMinuteAccumulator = 0;
efitick_t accumulatedSecondPrevNt;
efitick_t accumulatedMinutePrevNt;
void consumeFuel(float grams, efitick_t nowNt);
float getConsumedGrams() const;
float getConsumptionGramPerSecond() const;
private:
float m_consumedGrams = 0;
float m_rate = 0;
Timer m_timer;
};
class TransmissionState {
public:
TransmissionState();
gear_e gearSelectorPosition;
};

View File

@ -477,14 +477,4 @@ float getStandardAirCharge(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
}
#endif
float getFuelRate(floatms_t totalInjDuration, efitick_t timePeriod DECLARE_ENGINE_PARAMETER_SUFFIX) {
if (timePeriod <= 0.0f)
return 0.0f;
float timePeriodMs = (float)NT2US(timePeriod) / 1000.0f;
float fuelRate = totalInjDuration / timePeriodMs;
const float cc_min_to_L_h = 60.0f / 1000.0f;
return fuelRate * CONFIG(injector.flow) * cc_min_to_L_h;
}
#endif

View File

@ -31,6 +31,3 @@ floatms_t getInjectionMass(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
percent_t getInjectorDutyCycle(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX);
float getStandardAirCharge(DECLARE_ENGINE_PARAMETER_SIGNATURE);
// convert injection duration (Ms/Nt) to fuel rate (L/h)
float getFuelRate(floatms_t totalInjDuration, efitick_t timePeriod DECLARE_ENGINE_PARAMETER_SUFFIX);

View File

@ -171,10 +171,13 @@ static void handleGetDataRequest(const CANRxFrame& rx) {
obdSendPacket(1, pid, 4, scaled << 16);
break;
} case PID_FUEL_RATE:
obdSendValue(_1_MODE, pid, 2, engine->engineState.fuelConsumption.perSecondConsumption * 20.0f); // L/h. (A*256+B)/20
} case PID_FUEL_RATE: {
float gPerSecond = engine->engineState.fuelConsumption.getConsumptionGramPerSecond();
float gPerHour = gPerSecond * 3600;
float literPerHour = gPerHour * 0.00139f;
obdSendValue(_1_MODE, pid, 2, literPerHour * 20.0f); // L/h. (A*256+B)/20
break;
default:
} default:
// ignore unhandled PIDs
break;
}

View File

@ -206,8 +206,8 @@ void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t now
// Perform wall wetting adjustment on fuel mass, not duration, so that
// it's correct during fuel pressure (injector flow) or battery voltage (deadtime) transients
const float injectionMass = wallFuel.adjust(ENGINE(injectionMass) PASS_ENGINE_PARAMETER_SUFFIX);
const floatms_t injectionDuration = ENGINE(injectorModel)->getInjectionDuration(injectionMass);
const float injectionMassGrams = wallFuel.adjust(ENGINE(injectionMass) PASS_ENGINE_PARAMETER_SUFFIX);
const floatms_t injectionDuration = ENGINE(injectorModel)->getInjectionDuration(injectionMassGrams);
#if EFI_PRINTF_FUEL_DETAILS
if (printFuelDebug) {
@ -223,15 +223,13 @@ void InjectionEvent::onTriggerTooth(size_t trgEventIndex, int rpm, efitick_t now
* todo: pre-calculate 'numberOfInjections'
* see also injectorDutyCycle
*/
if (!isCranking && injectionDuration * getNumberOfInjections(engineConfiguration->injectionMode PASS_ENGINE_PARAMETER_SUFFIX) > getEngineCycleDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX)) {
int numberOfInjections = isCranking ? getNumberOfInjections(engineConfiguration->crankingInjectionMode PASS_ENGINE_PARAMETER_SUFFIX) : getNumberOfInjections(engineConfiguration->injectionMode PASS_ENGINE_PARAMETER_SUFFIX);
if (injectionDuration * numberOfInjections > getEngineCycleDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX)) {
warning(CUSTOM_TOO_LONG_FUEL_INJECTION, "Too long fuel injection %.2fms", injectionDuration);
} else if (isCranking && injectionDuration * getNumberOfInjections(engineConfiguration->crankingInjectionMode PASS_ENGINE_PARAMETER_SUFFIX) > getEngineCycleDuration(rpm PASS_ENGINE_PARAMETER_SUFFIX)) {
warning(CUSTOM_TOO_LONG_CRANKING_FUEL_INJECTION, "Too long cranking fuel injection %.2fms", injectionDuration);
}
// Store 'pure' injection duration (w/o injector lag) for fuel rate calc.
engine->engineState.fuelConsumption.addData(injectionDuration - ENGINE(engineState.running.injectorLag));
ENGINE(engineState.fuelConsumption).consumeFuel(injectionMassGrams * numberOfInjections, nowNt);
ENGINE(actualLastInjection) = injectionDuration;
if (cisnan(injectionDuration)) {
warning(CUSTOM_OBD_NAN_INJECTION, "NaN injection pulse");

View File

@ -194,6 +194,7 @@ struct_no_prefix engine_configuration_s
#define PACK_MULT_AFR_CFG 10
#define PACK_MULT_LAMBDA_CFG 147
#define PACK_MULT_FUEL_MASS 100
#define PACK_MULT_FUEL_FLOW 200
#define FSIO_TABLE_8 8
#define FSIO_CURVE_8 8
@ -1716,6 +1717,8 @@ end_struct
#define GAUGE_NAME_FUEL_WALL_AMOUNT "fuel: wall amount"
#define GAUGE_NAME_FUEL_WALL_CORRECTION "fuel: wall corr ms"
#define GAUGE_NAME_FUEL_LOAD "fuel: load"
#define GAUGE_NAME_FUEL_CONSUMPTION "fuel: Total consumed"
#define GAUGE_NAME_FUEL_FLOW "fuel: Flow rate"
#define GAUGE_NAME_FUEL_INJ_DUTY "fuel: injector duty cycle"
#define GAUGE_NAME_TCHARGE "fuel: SD tCharge"

View File

@ -283,8 +283,9 @@ enable2ndByteCanID = false
etb1Error = scalar, S16, 96, "%",{1/@@PACK_MULT_PERCENT@@}, 0
; Fuel system
fuelTankLevel = scalar, S16, 98, "%",{1/@@PACK_MULT_PERCENT@@}, 0
fuelConsumptionPerHour=scalar,F32, 100, "kPa", 1, 0.0
fuelTankLevel = scalar, U16, 98, "%",{1/@@PACK_MULT_PERCENT@@}, 0
totalFuelConsumption=scalar,U16, 100, "grams", 1, 0
fuelFlowRate = scalar, U16, 102, "gram/s",{1/@@PACK_MULT_FUEL_FLOW@@}, 0
; Y axis values for selectable tables
veTableYAxis = scalar, U16, 104, "%", 0.01, 0
@ -1064,6 +1065,8 @@ gaugeCategory = Fueling
baseFuelGauge = baseFuel, @@GAUGE_NAME_FUEL_BASE@@, "mg", 0, 100, 0, 0, 100, 100, 2, 0
fuelPidCorrectionGauge = fuelPidCorrection, @@GAUGE_NAME_FUEL_PID_CORR@@, "%", -10, 10, -8, -5, 5, 8, 3, 1
fuelingLoadGauge = fuelingLoad, @@GAUGE_NAME_FUEL_LOAD@@, "%", 0, 300, 0, 0, 300, 300, 1, 1
totalFuelConsumptionGauge = totalFuelConsumption, @@GAUGE_NAME_FUEL_CONSUMPTION@@, "g", 0, 10000, 0, 0, 10000, 10000, 0, 0
fuelFlowRateGauge = fuelFlowRate, @@GAUGE_NAME_FUEL_FLOW@@, "g/s", 0, 50, 0, 0, 50, 50, 2, 0
gaugeCategory = Throttle Body (incl. ETB)
pedalPositionGauge = throttlePedalPosition, @@GAUGE_NAME_THROTTLE_PEDAL@@, "%", 0, 120, 0, 0, 100, 100, 1, 1
@ -1258,6 +1261,8 @@ gaugeCategory = DynoView
entry = coilDutyCycle, @@GAUGE_NAME_DWELL_DUTY@@, float,"%.3f"
entry = currentTargetAfr,@@GAUGE_NAME_TARGET_AFR@@, float,"%.3f"
entry = targetLambda, @@GAUGE_NAME_TARGET_LAMBDA@@, float,"%.4f"
entry = totalFuelConsumption, @@GAUGE_NAME_FUEL_CONSUMPTION@@, int, "%d"
entry = fuelFlowRate, @@GAUGE_NAME_FUEL_FLOW@@, float, "%.2f"
entry = accelerationX, @@GAUGE_NAME_ACCEL_X@@, float,"%.2f", { LIS302DLCsPin != 0 }
entry = accelerationY, @@GAUGE_NAME_ACCEL_Y@@, float,"%.2f", { LIS302DLCsPin != 0 }