From 78119b7df4c9933c1cd39d55bc8cdde69494d60e Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Wed, 12 Jan 2022 12:41:35 -0800 Subject: [PATCH] improve maf output channels and logging (#3743) * maf channels * s * binary log * if only I could type * can * instant RPM too * s * test * graceful zero rpm * test works * float near --- firmware/console/binary/output_channels.txt | 8 +++++--- firmware/console/binary_log/binary_logging.cpp | 3 ++- firmware/console/status_loop.cpp | 18 ++++++++---------- firmware/controllers/algo/engine_state.h | 6 ++---- firmware/controllers/algo/fuel_math.cpp | 6 ++++++ firmware/controllers/can/can_verbose.cpp | 2 +- firmware/controllers/math/speed_density.cpp | 1 - firmware/integration/rusefi_config.txt | 3 ++- firmware/tunerstudio/rusefi.input | 9 +++++---- unit_tests/tests/test_engine_math.cpp | 10 ++++++++-- 10 files changed, 39 insertions(+), 27 deletions(-) diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index f3f193b765..2918fac699 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -55,9 +55,9 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 0, 0 int16_t autoscale throttlePedalPosition;@@GAUGE_NAME_THROTTLE_PEDAL@@;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0 uint16_t tpsADC;;"ADC", 1, 0, 0, 0, 0 - uint16_t autoscale MAFValue;@@GAUGE_NAME_MAF@@;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 0, 0 + uint16_t autoscale rawMaf;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 0, 0 - uint16_t autoscale massAirFlowValue;@@GAUGE_NAME_AIR_FLOW@@;"Kg/h",{1/@@PACK_MULT_MASS_FLOW@@}, 0, 0, 0, 0 + uint16_t autoscale mafMeasured;@@GAUGE_NAME_AIR_FLOW_MEASURED@@;"kg/h",{1/@@PACK_MULT_MASS_FLOW@@}, 0, 0, 0, 0 uint16_t autoscale MAPValue;@@GAUGE_NAME_MAP@@;"kPa",{1/@@PACK_MULT_PRESSURE@@}, 0, 0, 0, 0 uint16_t autoscale baroPressure;;"kPa",{1/@@PACK_MULT_PRESSURE@@}, 0, 0, 0, 0 @@ -268,9 +268,11 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 0, 0 float m_I_sum_percent;"DI: m_I_sum_percent";"v", 1, 0, 0, 100, 0 float m_pressureTarget_kPa;"DI: m_pressureTarget_kPa";"v", 1, 0, 0, 100, 0 + uint16_t autoscale mafEstimate;@@GAUGE_NAME_AIR_FLOW_ESTIMATE@@;"kg/h",{1/@@PACK_MULT_MASS_FLOW@@}, 0, 0, 0, 0 + uint16_t instantRpm;;"rpm", 1, 0, 0, 0, 0 ! we have some unused bytes to allow compatible TS changes - int[28 iterate] unusedAtTheEnd;;"",1, 0, 0, 0, 0 + uint8_t[108 iterate] unusedAtTheEnd;;"",1, 0, 0, 0, 0 bit launchSpeedCondition bit launchRpmCondition diff --git a/firmware/console/binary_log/binary_logging.cpp b/firmware/console/binary_log/binary_logging.cpp index 0d6fc7d445..4a3dc20344 100644 --- a/firmware/console/binary_log/binary_logging.cpp +++ b/firmware/console/binary_log/binary_logging.cpp @@ -97,7 +97,8 @@ static constexpr LogField fields[] = { {engine->outputChannels.fuelTankLevel, GAUGE_NAME_FUEL_LEVEL, "%", 0}, {engine->outputChannels.fuelingLoad, GAUGE_NAME_FUEL_LOAD, "%", 1}, {engine->outputChannels.ignitionLoad, GAUGE_NAME_IGNITION_LOAD, "%", 1}, - {engine->outputChannels.massAirFlowValue, GAUGE_NAME_AIR_FLOW, "kg/h", 1}, + {engine->outputChannels.mafMeasured, GAUGE_NAME_AIR_FLOW_MEASURED, "kg/h", 1}, + {engine->outputChannels.mafEstimate, GAUGE_NAME_AIR_FLOW_ESTIMATE, "kg/h", 1}, {engine->outputChannels.tcuDesiredGear, GAUGE_NAME_DESIRED_GEAR, "gear", 0}, {engine->outputChannels.tcuCurrentGear, GAUGE_NAME_CURRENT_GEAR, "gear", 0}, {engine->outputChannels.flexPercent, GAUGE_NAME_FLEX, "%", 1}, diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index 72b3704a55..7e323425a2 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -157,10 +157,6 @@ static int packEngineMode() { engineConfiguration->ignitionMode; } -static float getAirFlowGauge() { - return Sensor::get(SensorType::Maf).value_or(engine->engineState.airFlow); -} - static int prevCkpEventCounter = -1; /** @@ -555,7 +551,7 @@ static void updateRawSensors() { engine->outputChannels.rawOilPressure = Sensor::getRaw(SensorType::OilPressure); engine->outputChannels.rawLowFuelPressure = Sensor::getRaw(SensorType::FuelPressureLow); engine->outputChannels.rawHighFuelPressure = Sensor::getRaw(SensorType::FuelPressureHigh); - engine->outputChannels.MAFValue = Sensor::getRaw(SensorType::Maf); + engine->outputChannels.rawMaf = Sensor::getRaw(SensorType::Maf); engine->outputChannels.rawWastegatePosition = Sensor::getRaw(SensorType::WastegatePosition); engine->outputChannels.rawIdlePositionSensor = Sensor::getRaw(SensorType::IdlePosition); } @@ -701,6 +697,8 @@ void updateTunerStudioState() { // offset 0 tsOutputChannels->RPMValue = rpm; + auto instantRpm = engine->triggerCentral.triggerState.getInstantRpm(); + tsOutputChannels->instantRpm = instantRpm; updateSensors(rpm); updateFuelInfo(); @@ -709,9 +707,11 @@ void updateTunerStudioState() { // 104 tsOutputChannels->rpmAcceleration = engine->rpmCalculator.getRpmAcceleration(); - // offset 108 - // For air-interpolated tCharge mode, we calculate a decent massAirFlow approximation, so we can show it to users even without MAF sensor! - tsOutputChannels->massAirFlowValue = getAirFlowGauge(); + + // Output both the estimated air flow, and measured air flow (if available) + tsOutputChannels->mafMeasured = Sensor::getOrZero(SensorType::Maf); + tsOutputChannels->mafEstimate = engine->engineState.airflowEstimate; + // offset 116 // TPS acceleration tsOutputChannels->deltaTps = engine->tpsAccelEnrichment.getMaxDelta(); @@ -851,8 +851,6 @@ void updateTunerStudioState() { break; case DBG_INSTANT_RPM: { - float instantRpm = engine->triggerCentral.triggerState.getInstantRpm(); - tsOutputChannels->debugFloatField1 = instantRpm; tsOutputChannels->debugFloatField2 = instantRpm / GET_RPM(); tsOutputChannels->mostRecentTimeBetweenSparkEvents = engine->mostRecentTimeBetweenSparkEvents; diff --git a/firmware/controllers/algo/engine_state.h b/firmware/controllers/algo/engine_state.h index ec3744f7c3..69c270b1ae 100644 --- a/firmware/controllers/algo/engine_state.h +++ b/firmware/controllers/algo/engine_state.h @@ -37,10 +37,8 @@ public: WarningCodeState warnings; - /** - * speed-density logic, calculated air flow in kg/h for tCharge Air-Interp. method - */ - float airFlow = 0; + // Estimated airflow based on whatever airmass model is active + float airflowEstimate = 0; float knockThreshold = 0; diff --git a/firmware/controllers/algo/fuel_math.cpp b/firmware/controllers/algo/fuel_math.cpp index b1e105f635..6a4be4ed58 100644 --- a/firmware/controllers/algo/fuel_math.cpp +++ b/firmware/controllers/algo/fuel_math.cpp @@ -156,6 +156,12 @@ static float getBaseFuelMass(int rpm) { engine->engineState.sd.airMassInOneCylinder = airmass.CylinderAirmass; engine->engineState.fuelingLoad = airmass.EngineLoadPercent; engine->engineState.ignitionLoad = getLoadOverride(airmass.EngineLoadPercent, engineConfiguration->ignOverrideMode); + + auto gramPerCycle = airmass.CylinderAirmass * engineConfiguration->specs.cylindersCount; + auto gramPerMs = rpm == 0 ? 0 : gramPerCycle / getEngineCycleDuration(rpm); + + // convert g/s -> kg/h + engine->engineState.airflowEstimate = gramPerMs * 3600000 /* milliseconds per hour */ / 1000 /* grams per kg */;; float baseFuelMass = engine->fuelComputer->getCycleFuel(airmass.CylinderAirmass, rpm, airmass.EngineLoadPercent); diff --git a/firmware/controllers/can/can_verbose.cpp b/firmware/controllers/can/can_verbose.cpp index 0a86c9fdf4..4019ba4e86 100644 --- a/firmware/controllers/can/can_verbose.cpp +++ b/firmware/controllers/can/can_verbose.cpp @@ -125,7 +125,7 @@ struct Fueling { static void populateFrame(Fueling& msg) { msg.cylAirmass = engine->engineState.sd.airMassInOneCylinder; - msg.estAirflow = engine->engineState.airFlow; + msg.estAirflow = engine->engineState.airflowEstimate; msg.fuel_pulse = engine->actualLastInjection[0]; } diff --git a/firmware/controllers/math/speed_density.cpp b/firmware/controllers/math/speed_density.cpp index 7e7f5cb0ee..dab5cd8349 100644 --- a/firmware/controllers/math/speed_density.cpp +++ b/firmware/controllers/math/speed_density.cpp @@ -55,7 +55,6 @@ temperature_t getTCharge(int rpm, float tps) { // And if the engine is stopped (0 rpm), then airFlow is also zero (avoiding NaN division) floatms_t airFlow = (rpm == 0) ? 0 : airMassForEngine * gramsPerMsToKgPerHour / getEngineCycleDuration(rpm); // just interpolate between user-specified min and max coefs, based on the max airFlow value - engine->engineState.airFlow = airFlow; engine->engineState.sd.Tcharge_coff = interpolateClamped(0.0, engineConfiguration->tChargeAirCoefMin, engineConfiguration->tChargeAirFlowMax, diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index d350dd78c1..5b71d188bc 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -1709,7 +1709,8 @@ end_struct #define INDICATOR_NAME_BRAKE_DOWN "brake: down" #define INDICATOR_NAME_AC_SWITCH "AC switch" -#define GAUGE_NAME_AIR_FLOW "MAF air flow" +#define GAUGE_NAME_AIR_FLOW_MEASURED "MAF sensor" +#define GAUGE_NAME_AIR_FLOW_ESTIMATE "MAF estimate" #define GAUGE_NAME_AIR_MASS "air mass" #define GAUGE_NAME_WARNING_LAST "warning: last" diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index 8a88cc5afa..3ee2d62005 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -462,9 +462,9 @@ enable2ndByteCanID = false columnLabel = "Voltage", "kg/hour" xAxis = -1, 6, 10 yAxis = -30, 1300, 10 - xBins = mafDecodingBins, MAFValue + xBins = mafDecodingBins, rawMaf yBins = mafDecoding - gauge = MAFGauge + gauge = rawMafGauge curve = iatFuelCorrCurve, "Intake air temperature fuel Multiplier" columnLabel = "Air Temp", "Multiplier" @@ -1030,10 +1030,9 @@ gaugeCategory = Sensors - Basic afr2Gauge = AFRValue2, @@GAUGE_NAME_AFR2@@, "", 10, 19.4, 12, 13, 15, 16, 2, 2 lambda1Gauge = lambdaValue, @@GAUGE_NAME_LAMBDA@@, "", 0.65, 1.2, 0.7, 0.75, 1.1, 1.15, 3, 2 lambda2Gauge = lambdaValue2, @@GAUGE_NAME_LAMBDA2@@, "", 0.65, 1.2, 0.7, 0.75, 1.1, 1.15, 3, 2 - MAFGauge = MAFValue, "Mass air flow", "V", 0, 5, 0, 1, 3, 4, 1, 1 VBattGauge = VBatt, "Battery", "V", 8, 21, 9, 10, 17, 19, 1, 1 MAPGauge = MAPValue, "MAP", "kPa", 0, 300, 10, 10, 200, 200, 0, 0 - massAirFlowValueGa = massAirFlowValue,"Mass air flow", "kg/hr", 0, 50, -999, -999, 999, 999, 1, 1 + massAirFlowValueGa = mafMeasured, @@GAUGE_NAME_AIR_FLOW_MEASURED@@, "kg/h", 0, 50, -999, -999, 999, 999, 1, 1 gaugeCategory = Sensors - Extra 1 @@ -1123,6 +1122,8 @@ gaugeCategory = Sensors - Raw rawWastegatePositionGauge = rawWastegatePosition,"Raw Wastegate Position","V", 0, 5, 0, 0, 5, 5, 3, 0 rawLowFuelPressureGauge = rawLowFuelPressure,"Raw fuel pressure (low) voltage","V", 0, 5, 0, 0, 5, 5, 3, 0 rawHighFuelPressureGauge = rawHighFuelPressure,"Raw fuel pressure (high) voltage","V", 0, 5, 0, 0, 5, 5, 3, 0 + rawMafGauge = rawMaf , "Raw MAF", "V", 0, 5, 0, 0, 5, 5, 3, 0 + gaugeCategory = Transmission desiredGearGauge = tcuDesiredGear, @@GAUGE_NAME_DESIRED_GEAR@@, "gear", -1, 10, -1, -1, 10, 10, 0, 0 diff --git a/unit_tests/tests/test_engine_math.cpp b/unit_tests/tests/test_engine_math.cpp index cc4fa5816e..26891172f7 100644 --- a/unit_tests/tests/test_engine_math.cpp +++ b/unit_tests/tests/test_engine_math.cpp @@ -38,6 +38,7 @@ TEST(misc, testEngineMath) { EngineTestHelper eth(FORD_ESCORT_GT); engineConfiguration->ambiguousOperationMode = FOUR_STROKE_CAM_SENSOR; + engineConfiguration->fuelAlgorithm = LM_SPEED_DENSITY; ASSERT_NEAR( 50, getOneDegreeTimeMs(600) * 180, EPS4D) << "600 RPM"; ASSERT_EQ( 5, getOneDegreeTimeMs(6000) * 180) << "6000 RPM"; @@ -64,9 +65,14 @@ TEST(misc, testEngineMath) { Sensor::setMockValue(SensorType::Clt, 90); Sensor::setMockValue(SensorType::Iat, 20); + Sensor::setMockValue(SensorType::Map, 100); + Sensor::setMockValue(SensorType::Tps1, 0); + engine->rpmCalculator.mockRpm = 1000; + // calc. airFlow using airMass, and find tCharge - ASSERT_FLOAT_EQ(59.1175f, getTCharge(/*RPM*/1000, /*TPS*/0)); - ASSERT_FLOAT_EQ(65.5625f/*kg/h*/, engine->engineState.airFlow); + engine->periodicFastCallback(); + ASSERT_NEAR(59.1175f, engine->engineState.sd.tCharge, EPS4D); + ASSERT_NEAR(56.9762f/*kg/h*/, engine->engineState.airflowEstimate, EPS4D); } TEST(misc, testIgnitionMapGenerator) {