mirror of https://github.com/rusefi/rusefi-1.git
Merge pull request #1686 from mck1117/ys-1b
Refactor fuel math in to FuelComputer
This commit is contained in:
commit
2dd3beb9bd
|
@ -290,7 +290,6 @@ static void showFuelInfo2(float rpm, float engineLoad) {
|
||||||
|
|
||||||
float magicAir = SpeedDensityBase::getAirmassImpl(1, 100, convertCelsiusToKelvin(20) PASS_ENGINE_PARAMETER_SUFFIX);
|
float magicAir = SpeedDensityBase::getAirmassImpl(1, 100, convertCelsiusToKelvin(20) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
||||||
scheduleMsg(&logger, "SD magic fuel %.2f", getInjectionDurationForAirmass(magicAir, 14.7 PASS_ENGINE_PARAMETER_SUFFIX));
|
|
||||||
scheduleMsg(&logger, "inj flow %.2fcc/min displacement %.2fL", engineConfiguration->injector.flow,
|
scheduleMsg(&logger, "inj flow %.2fcc/min displacement %.2fL", engineConfiguration->injector.flow,
|
||||||
engineConfiguration->specs.displacement);
|
engineConfiguration->specs.displacement);
|
||||||
|
|
||||||
|
|
|
@ -16,3 +16,4 @@ CONTROLLERS_ALGO_SRC_CPP = $(PROJECT_DIR)/controllers/algo/advance_map.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/airmass/maf_airmass.cpp \
|
$(PROJECT_DIR)/controllers/algo/airmass/maf_airmass.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_airmass.cpp \
|
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_airmass.cpp \
|
||||||
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_base.cpp \
|
$(PROJECT_DIR)/controllers/algo/airmass/speed_density_base.cpp \
|
||||||
|
$(PROJECT_DIR)/controllers/algo/fuel/fuel_computer.cpp \
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include "fuel_computer.h"
|
||||||
|
|
||||||
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
|
mass_t FuelComputerBase::getCycleFuel(mass_t airmass, int rpm, float load) const {
|
||||||
|
float stoich = getStoichiometricRatio();
|
||||||
|
float lambda = getTargetLambda(rpm, load);
|
||||||
|
float afr = stoich * lambda;
|
||||||
|
|
||||||
|
ENGINE(engineState.targetAFR) = afr;
|
||||||
|
|
||||||
|
return airmass / afr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuelComputer::FuelComputer(const ValueProvider3D& afrTable) : m_afrTable(&afrTable) {}
|
||||||
|
|
||||||
|
float FuelComputer::getStoichiometricRatio() const {
|
||||||
|
// TODO: vary this with ethanol content/configured setting/whatever
|
||||||
|
return 14.7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FuelComputer::getTargetLambda(int rpm, float load) const {
|
||||||
|
efiAssert(OBD_PCM_Processor_Fault, m_afrTable != nullptr, "AFR table null", 0);
|
||||||
|
|
||||||
|
// TODO: set the table value in lambda instead of afr
|
||||||
|
return m_afrTable->getValue(rpm, load) / getStoichiometricRatio();
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
class ValueProvider3D;
|
||||||
|
|
||||||
|
using mass_t = float;
|
||||||
|
|
||||||
|
struct IFuelComputer {
|
||||||
|
virtual mass_t getCycleFuel(mass_t airmass, int rpm, float load) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This contains the math of the fuel model, but doesn't actually read any configuration
|
||||||
|
class FuelComputerBase : public IFuelComputer {
|
||||||
|
public:
|
||||||
|
DECLARE_ENGINE_PTR;
|
||||||
|
|
||||||
|
mass_t getCycleFuel(mass_t airmass, int rpm, float load) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual float getStoichiometricRatio() const = 0;
|
||||||
|
virtual float getTargetLambda(int rpm, float load) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is a usable implemenation of a fuel model that reads real configuration
|
||||||
|
class FuelComputer final : public FuelComputerBase {
|
||||||
|
public:
|
||||||
|
FuelComputer(const ValueProvider3D& afrTable);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float getStoichiometricRatio() const override;
|
||||||
|
float getTargetLambda(int rpm, float load) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ValueProvider3D* const m_afrTable;
|
||||||
|
};
|
|
@ -27,6 +27,7 @@
|
||||||
#include "maf_airmass.h"
|
#include "maf_airmass.h"
|
||||||
#include "speed_density_airmass.h"
|
#include "speed_density_airmass.h"
|
||||||
#include "fuel_math.h"
|
#include "fuel_math.h"
|
||||||
|
#include "fuel_computer.h"
|
||||||
#include "interpolation.h"
|
#include "interpolation.h"
|
||||||
#include "engine_configuration.h"
|
#include "engine_configuration.h"
|
||||||
#include "allsensors.h"
|
#include "allsensors.h"
|
||||||
|
@ -163,10 +164,10 @@ constexpr float convertToGramsPerSecond(float ccPerMinute) {
|
||||||
/**
|
/**
|
||||||
* @return per cylinder injection time, in seconds
|
* @return per cylinder injection time, in seconds
|
||||||
*/
|
*/
|
||||||
float getInjectionDurationForAirmass(float airMass, float afr DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
static float getInjectionDurationForFuelMass(float fuelMass DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
float gPerSec = convertToGramsPerSecond(CONFIG(injector.flow));
|
float gPerSec = convertToGramsPerSecond(CONFIG(injector.flow));
|
||||||
|
|
||||||
return airMass / (afr * gPerSec);
|
return fuelMass / gPerSec;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SpeedDensityAirmass sdAirmass(veMap);
|
static SpeedDensityAirmass sdAirmass(veMap);
|
||||||
|
@ -185,6 +186,8 @@ AirmassModelBase* getAirmassModel(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FuelComputer fuelComputer(afrMap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* per-cylinder fuel amount
|
* per-cylinder fuel amount
|
||||||
* todo: rename this method since it's now base+TPSaccel
|
* todo: rename this method since it's now base+TPSaccel
|
||||||
|
@ -202,17 +205,14 @@ floatms_t getBaseFuel(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
|
||||||
auto airmass = model->getAirmass(rpm);
|
auto airmass = model->getAirmass(rpm);
|
||||||
|
|
||||||
// The airmass mode will tell us how to look up AFR - use the provided Y axis value
|
|
||||||
float targetAfr = afrMap.getValue(rpm, airmass.EngineLoadPercent);
|
|
||||||
|
|
||||||
// Plop some state for others to read
|
// Plop some state for others to read
|
||||||
ENGINE(engineState.targetAFR) = targetAfr;
|
|
||||||
ENGINE(engineState.sd.airMassInOneCylinder) = airmass.CylinderAirmass;
|
ENGINE(engineState.sd.airMassInOneCylinder) = airmass.CylinderAirmass;
|
||||||
ENGINE(engineState.fuelingLoad) = airmass.EngineLoadPercent;
|
ENGINE(engineState.fuelingLoad) = airmass.EngineLoadPercent;
|
||||||
// TODO: independently selectable ignition load mode
|
// TODO: independently selectable ignition load mode
|
||||||
ENGINE(engineState.ignitionLoad) = airmass.EngineLoadPercent;
|
ENGINE(engineState.ignitionLoad) = airmass.EngineLoadPercent;
|
||||||
|
|
||||||
float baseFuel = getInjectionDurationForAirmass(airmass.CylinderAirmass, targetAfr PASS_ENGINE_PARAMETER_SUFFIX) * 1000;
|
float baseFuelMass = fuelComputer.getCycleFuel(airmass.CylinderAirmass, rpm, airmass.EngineLoadPercent);
|
||||||
|
float baseFuel = getInjectionDurationForFuelMass(baseFuelMass PASS_ENGINE_PARAMETER_SUFFIX) * 1000;
|
||||||
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN baseFuel", 0);
|
efiAssert(CUSTOM_ERR_ASSERT, !cisnan(baseFuel), "NaN baseFuel", 0);
|
||||||
|
|
||||||
engine->engineState.baseFuel = baseFuel;
|
engine->engineState.baseFuel = baseFuel;
|
||||||
|
@ -345,6 +345,8 @@ floatms_t getInjectorLag(float vBatt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
void initFuelMap(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
INJECT_ENGINE_REFERENCE(&sdAirmass);
|
INJECT_ENGINE_REFERENCE(&sdAirmass);
|
||||||
INJECT_ENGINE_REFERENCE(&mafAirmass);
|
INJECT_ENGINE_REFERENCE(&mafAirmass);
|
||||||
|
INJECT_ENGINE_REFERENCE(&alphaNAirmass);
|
||||||
|
INJECT_ENGINE_REFERENCE(&fuelComputer);
|
||||||
|
|
||||||
#if (IGN_LOAD_COUNT == FUEL_LOAD_COUNT) && (IGN_RPM_COUNT == FUEL_RPM_COUNT)
|
#if (IGN_LOAD_COUNT == FUEL_LOAD_COUNT) && (IGN_RPM_COUNT == FUEL_RPM_COUNT)
|
||||||
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
|
fuelPhaseMap.init(config->injectionPhase, config->injPhaseLoadBins, config->injPhaseRpmBins);
|
||||||
|
|
|
@ -39,4 +39,3 @@ float getStandardAirCharge(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
// convert injection duration (Ms/Nt) to fuel rate (L/h)
|
// convert injection duration (Ms/Nt) to fuel rate (L/h)
|
||||||
float getFuelRate(floatms_t totalInjDuration, efitick_t timePeriod DECLARE_ENGINE_PARAMETER_SUFFIX);
|
float getFuelRate(floatms_t totalInjDuration, efitick_t timePeriod DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
float getInjectionDurationForAirmass(float airMass, float afr DECLARE_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ CONTROLLERS_INC=\
|
||||||
$(CONTROLLERS_DIR)/system/timer \
|
$(CONTROLLERS_DIR)/system/timer \
|
||||||
$(CONTROLLERS_DIR)/algo \
|
$(CONTROLLERS_DIR)/algo \
|
||||||
$(CONTROLLERS_DIR)/algo/airmass \
|
$(CONTROLLERS_DIR)/algo/airmass \
|
||||||
|
$(CONTROLLERS_DIR)/algo/fuel \
|
||||||
$(CONTROLLERS_DIR)/engine_cycle \
|
$(CONTROLLERS_DIR)/engine_cycle \
|
||||||
$(CONTROLLERS_DIR)/trigger/decoders \
|
$(CONTROLLERS_DIR)/trigger/decoders \
|
||||||
$(CONTROLLERS_DIR)/trigger \
|
$(CONTROLLERS_DIR)/trigger \
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "engine_test_helper.h"
|
||||||
|
|
||||||
|
// sneaky...
|
||||||
|
#define protected public
|
||||||
|
#include "fuel_computer.h"
|
||||||
|
#include "mocks.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using ::testing::FloatEq;
|
||||||
|
|
||||||
|
class MockFuelComputer : public FuelComputerBase {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD(float, getStoichiometricRatio, (), (const, override));
|
||||||
|
MOCK_METHOD(float, getTargetLambda, (int rpm, float load), (const, override));
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FuelComputer, getCycleFuel) {
|
||||||
|
WITH_ENGINE_TEST_HELPER(TEST_ENGINE);
|
||||||
|
|
||||||
|
MockFuelComputer dut;
|
||||||
|
INJECT_ENGINE_REFERENCE(&dut);
|
||||||
|
|
||||||
|
EXPECT_CALL(dut, getStoichiometricRatio())
|
||||||
|
.WillOnce(Return(3.0f));
|
||||||
|
EXPECT_CALL(dut, getTargetLambda(1000, FloatEq(0.8f)))
|
||||||
|
.WillOnce(Return(5.0f));
|
||||||
|
|
||||||
|
auto result = dut.getCycleFuel(7.0f, 1000, 0.8f);
|
||||||
|
EXPECT_FLOAT_EQ(result, 7.0f / (5 * 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FuelComputer, LambdaLookup) {
|
||||||
|
MockVp3d afrTable;
|
||||||
|
FuelComputer dut(afrTable);
|
||||||
|
|
||||||
|
EXPECT_CALL(afrTable, getValue(1500, FloatEq(0.7f)))
|
||||||
|
.WillOnce(Return(14.7f));
|
||||||
|
|
||||||
|
EXPECT_FLOAT_EQ(dut.getTargetLambda(1500, 0.7f), 1.0f);
|
||||||
|
}
|
|
@ -78,7 +78,7 @@ TEST(AirmassModes, AlphaNFailedTps) {
|
||||||
EXPECT_EQ(result.CylinderAirmass, 0);
|
EXPECT_EQ(result.CylinderAirmass, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(misc, MafNormal) {
|
TEST(AirmassModes, MafNormal) {
|
||||||
WITH_ENGINE_TEST_HELPER(FORD_ASPIRE_1996);
|
WITH_ENGINE_TEST_HELPER(FORD_ASPIRE_1996);
|
||||||
engineConfiguration->fuelAlgorithm = LM_REAL_MAF;
|
engineConfiguration->fuelAlgorithm = LM_REAL_MAF;
|
||||||
engineConfiguration->injector.flow = 200;
|
engineConfiguration->injector.flow = 200;
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
/**
|
|
||||||
* @file test_speed_density.cpp
|
|
||||||
*
|
|
||||||
* @date Jun 26, 2014
|
|
||||||
* @author Andrey Belomutskiy, (c) 2012-2020
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "engine_test_helper.h"
|
|
||||||
#include "speed_density.h"
|
|
||||||
#include "fuel_math.h"
|
|
||||||
|
|
||||||
TEST(big, testSpeedDensity) {
|
|
||||||
printf("*************************************************** testSpeedDensity\r\n");
|
|
||||||
WITH_ENGINE_TEST_HELPER(FORD_INLINE_6_1995);
|
|
||||||
|
|
||||||
engineConfiguration->trigger.customTotalToothCount = 8;
|
|
||||||
eth.applyTriggerWaveform();
|
|
||||||
|
|
||||||
eth.fireTriggerEvents(36);
|
|
||||||
ASSERT_EQ( 1500, GET_RPM()) << "RPM";
|
|
||||||
|
|
||||||
// 427 cubic inches, that's a LOT of engine
|
|
||||||
engineConfiguration->specs.displacement = 6.99728;
|
|
||||||
engineConfiguration->specs.cylindersCount = 8;
|
|
||||||
|
|
||||||
engineConfiguration->injector.flow = gramm_second_to_cc_minute(5.303);
|
|
||||||
|
|
||||||
float airMass = SpeedDensityBase::getAirmassImpl(0.92, 98, 293.16 PASS_ENGINE_PARAMETER_SUFFIX);
|
|
||||||
|
|
||||||
ASSERT_FLOAT_EQ(0.9371106624, airMass);
|
|
||||||
|
|
||||||
// 0.01414 sec or 14.14 ms
|
|
||||||
EXPECT_NEAR(0.014137, getInjectionDurationForAirmass(airMass, 12.5 PASS_ENGINE_PARAMETER_SUFFIX), EPS4D);
|
|
||||||
}
|
|
|
@ -12,6 +12,7 @@ TESTS_SRC_CPP = \
|
||||||
tests/ignition_injection/test_multispark.cpp \
|
tests/ignition_injection/test_multispark.cpp \
|
||||||
tests/ignition_injection/test_ignition_scheduling.cpp \
|
tests/ignition_injection/test_ignition_scheduling.cpp \
|
||||||
tests/ignition_injection/test_fuelCut.cpp \
|
tests/ignition_injection/test_fuelCut.cpp \
|
||||||
|
tests/ignition_injection/test_fuel_computer.cpp \
|
||||||
tests/test_util.cpp \
|
tests/test_util.cpp \
|
||||||
tests/test_ion.cpp \
|
tests/test_ion.cpp \
|
||||||
tests/test_aux_valves.cpp \
|
tests/test_aux_valves.cpp \
|
||||||
|
@ -29,7 +30,6 @@ TESTS_SRC_CPP = \
|
||||||
tests/test_one_cylinder_logic.cpp \
|
tests/test_one_cylinder_logic.cpp \
|
||||||
tests/test_pwm_generator.cpp \
|
tests/test_pwm_generator.cpp \
|
||||||
tests/test_logic_expression.cpp \
|
tests/test_logic_expression.cpp \
|
||||||
tests/test_speed_density.cpp \
|
|
||||||
tests/test_signal_executor.cpp \
|
tests/test_signal_executor.cpp \
|
||||||
tests/test_cpp_memory_layout.cpp \
|
tests/test_cpp_memory_layout.cpp \
|
||||||
tests/test_sensors.cpp \
|
tests/test_sensors.cpp \
|
||||||
|
|
Loading…
Reference in New Issue