2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file map_averaging.cpp
|
|
|
|
*
|
2017-06-21 23:23:42 -07:00
|
|
|
* In order to have best MAP estimate possible, we real MAP value at a relatively high frequency
|
|
|
|
* and average the value within a specified angle position window for each cylinder
|
|
|
|
*
|
2015-07-10 06:01:56 -07:00
|
|
|
* @date Dec 11, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "pch.h"
|
2020-11-05 14:44:16 -08:00
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "os_access.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_MAP_AVERAGING
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#include "map_averaging.h"
|
|
|
|
#include "trigger_central.h"
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SENSOR_CHART
|
2015-09-12 16:01:20 -07:00
|
|
|
#include "sensor_chart.h"
|
2015-09-13 09:01:42 -07:00
|
|
|
#endif /* EFI_SENSOR_CHART */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#define FAST_MAP_CHART_SKIP_FACTOR 16
|
|
|
|
|
2016-09-06 21:02:11 -07:00
|
|
|
/**
|
|
|
|
* this instance does not have a real physical pin - it's only used for engine sniffer
|
|
|
|
*/
|
2015-07-10 06:01:56 -07:00
|
|
|
static NamedOutputPin mapAveragingPin("map");
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Running counter of measurements per revolution
|
|
|
|
*/
|
2015-09-06 18:02:46 -07:00
|
|
|
static volatile int measurementsPerRevolutionCounter = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* Number of measurements in previous shaft revolution
|
|
|
|
*/
|
2015-09-06 18:02:46 -07:00
|
|
|
static volatile int measurementsPerRevolution = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
2017-06-21 23:23:42 -07:00
|
|
|
* Running MAP accumulator - sum of all measurements within averaging window
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2018-02-06 13:21:41 -08:00
|
|
|
static volatile float mapAdcAccumulator = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* Running counter of measurements to consider for averaging
|
|
|
|
*/
|
|
|
|
static volatile int mapMeasurementsCounter = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* v_ for Voltage
|
|
|
|
*/
|
|
|
|
static float v_averagedMapValue;
|
|
|
|
|
2021-10-04 04:50:17 -07:00
|
|
|
// allow smoothing up to number of cylinders
|
|
|
|
#define MAX_MAP_BUFFER_LENGTH (MAX_CYLINDER_COUNT)
|
2017-06-22 01:21:35 -07:00
|
|
|
// in MAP units, not voltage!
|
|
|
|
static float averagedMapRunningBuffer[MAX_MAP_BUFFER_LENGTH];
|
2017-08-06 13:29:14 -07:00
|
|
|
int mapMinBufferLength = 0;
|
2017-06-22 01:21:35 -07:00
|
|
|
static int averagedMapBufIdx = 0;
|
2021-11-24 11:26:41 -08:00
|
|
|
static adcsample_t fastestRawAdc;
|
2017-06-22 01:21:35 -07:00
|
|
|
|
2017-06-21 23:23:42 -07:00
|
|
|
/**
|
|
|
|
* here we have averaging start and averaging end points for each cylinder
|
|
|
|
*/
|
2021-07-06 17:14:08 -07:00
|
|
|
static scheduling_s startTimers[MAX_CYLINDER_COUNT][2];
|
|
|
|
static scheduling_s endTimers[MAX_CYLINDER_COUNT][2];
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* that's a performance optimization: let's not bother averaging
|
|
|
|
* if we are outside of of the window
|
|
|
|
*/
|
2016-01-11 14:01:33 -08:00
|
|
|
static bool isAveraging = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-04-23 05:12:44 -07:00
|
|
|
static void endAveraging(void *arg);
|
|
|
|
|
|
|
|
static void startAveraging(scheduling_s *endAveragingScheduling) {
|
2019-02-23 09:33:49 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6649, getCurrentRemainingStack() > 128, "lowstck#9");
|
2019-10-14 13:04:28 -07:00
|
|
|
|
2020-11-19 03:56:02 -08:00
|
|
|
{
|
|
|
|
// with locking we will have a consistent state
|
|
|
|
chibios_rt::CriticalSectionLocker csl;
|
|
|
|
mapAdcAccumulator = 0;
|
|
|
|
mapMeasurementsCounter = 0;
|
|
|
|
isAveraging = true;
|
2019-10-14 06:09:08 -07:00
|
|
|
}
|
|
|
|
|
2017-04-21 16:23:20 -07:00
|
|
|
mapAveragingPin.setHigh();
|
2020-04-23 05:12:44 -07:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
scheduleByAngle(endAveragingScheduling, getTimeNowNt(), engine->engineState.mapAveragingDuration,
|
2021-11-16 01:15:29 -08:00
|
|
|
endAveraging);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if HAL_USE_ADC
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* This method is invoked from ADC callback.
|
|
|
|
* @note This method is invoked OFTEN, this method is a potential bottle-next - the implementation should be
|
|
|
|
* as fast as possible
|
|
|
|
*/
|
2018-02-06 12:58:57 -08:00
|
|
|
void mapAveragingAdcCallback(adcsample_t adcValue) {
|
2021-11-24 11:26:41 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6650, getCurrentRemainingStack() > 128, "lowstck#9a");
|
|
|
|
|
|
|
|
fastestRawAdc = adcValue;
|
2021-11-17 00:54:21 -08:00
|
|
|
if (!isAveraging && engine->sensorChartMode != SC_MAP) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SENSOR_CHART && EFI_ANALOG_SENSORS
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engine->sensorChartMode == SC_MAP) {
|
2021-11-24 11:26:41 -08:00
|
|
|
measurementsPerRevolutionCounter++;
|
|
|
|
if (measurementsPerRevolutionCounter % FAST_MAP_CHART_SKIP_FACTOR == 0) {
|
2015-07-10 06:01:56 -07:00
|
|
|
float voltage = adcToVoltsDivided(adcValue);
|
2021-10-04 15:33:10 -07:00
|
|
|
float currentPressure = convertMap(voltage).value_or(0);
|
2015-09-06 20:01:28 -07:00
|
|
|
scAddData(
|
2021-11-20 03:59:02 -08:00
|
|
|
engine->triggerCentral.getCurrentEnginePhase(getTimeNowNt()).value_or(0),
|
2015-09-06 20:01:28 -07:00
|
|
|
currentPressure);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2015-09-06 18:02:46 -07:00
|
|
|
}
|
2015-09-13 09:01:42 -07:00
|
|
|
#endif /* EFI_SENSOR_CHART */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-11-24 11:26:41 -08:00
|
|
|
/* Calculates the average values from the ADC samples.*/
|
|
|
|
if (isAveraging) {
|
2020-11-19 03:56:02 -08:00
|
|
|
// with locking we will have a consistent state
|
|
|
|
chibios_rt::CriticalSectionLocker csl;
|
|
|
|
mapAdcAccumulator += adcValue;
|
|
|
|
mapMeasurementsCounter++;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-09-30 20:05:58 -07:00
|
|
|
static void endAveraging(void*) {
|
2019-10-14 06:09:08 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
2020-11-19 03:56:02 -08:00
|
|
|
chibios_rt::CriticalSectionLocker csl;
|
2019-10-14 06:09:08 -07:00
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
isAveraging = false;
|
|
|
|
// with locking we would have a consistent state
|
2019-04-12 19:07:03 -07:00
|
|
|
#if HAL_USE_ADC
|
2018-02-10 03:02:48 -08:00
|
|
|
if (mapMeasurementsCounter > 0) {
|
|
|
|
v_averagedMapValue = adcToVoltsDivided(mapAdcAccumulator / mapMeasurementsCounter);
|
2021-10-04 14:18:08 -07:00
|
|
|
|
|
|
|
SensorResult mapValue = convertMap(v_averagedMapValue);
|
|
|
|
|
|
|
|
// Skip update if conversion invalid
|
|
|
|
if (mapValue) {
|
|
|
|
averagedMapRunningBuffer[averagedMapBufIdx] = mapValue.Value;
|
|
|
|
// increment circular running buffer index
|
|
|
|
averagedMapBufIdx = (averagedMapBufIdx + 1) % mapMinBufferLength;
|
|
|
|
// find min. value (only works for pressure values, not raw voltages!)
|
|
|
|
float minPressure = averagedMapRunningBuffer[0];
|
|
|
|
for (int i = 1; i < mapMinBufferLength; i++) {
|
|
|
|
if (averagedMapRunningBuffer[i] < minPressure)
|
|
|
|
minPressure = averagedMapRunningBuffer[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
onMapAveraged(minPressure, getTimeNowNt());
|
2018-02-10 03:02:48 -08:00
|
|
|
}
|
|
|
|
} else {
|
2019-01-11 06:24:24 -08:00
|
|
|
warning(CUSTOM_UNEXPECTED_MAP_VALUE, "No MAP values");
|
2017-06-22 01:21:35 -07:00
|
|
|
}
|
2019-10-14 06:09:08 -07:00
|
|
|
#endif
|
2017-04-21 16:23:20 -07:00
|
|
|
mapAveragingPin.setLow();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
static void applyMapMinBufferLength() {
|
2017-08-06 14:05:57 -07:00
|
|
|
// check range
|
2021-11-17 00:54:21 -08:00
|
|
|
mapMinBufferLength = maxI(minI(engineConfiguration->mapMinBufferLength, MAX_MAP_BUFFER_LENGTH), 1);
|
2017-08-06 14:05:57 -07:00
|
|
|
// reset index
|
|
|
|
averagedMapBufIdx = 0;
|
|
|
|
// fill with maximum values
|
|
|
|
for (int i = 0; i < mapMinBufferLength; i++) {
|
|
|
|
averagedMapRunningBuffer[i] = FLT_MAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
2019-10-14 06:09:08 -07:00
|
|
|
void postMapState(TunerStudioOutputChannels *tsOutputChannels) {
|
2018-02-06 13:21:41 -08:00
|
|
|
tsOutputChannels->debugFloatField1 = v_averagedMapValue;
|
|
|
|
tsOutputChannels->debugFloatField2 = engine->engineState.mapAveragingDuration;
|
2021-10-05 16:59:07 -07:00
|
|
|
tsOutputChannels->debugFloatField3 = Sensor::getOrZero(SensorType::MapFast);
|
2018-02-06 13:21:41 -08:00
|
|
|
tsOutputChannels->debugIntField1 = mapMeasurementsCounter;
|
2021-11-24 11:26:41 -08:00
|
|
|
tsOutputChannels->debugIntField1 = fastestRawAdc;
|
2018-02-06 13:21:41 -08:00
|
|
|
}
|
2019-10-14 06:09:08 -07:00
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
2018-02-06 13:21:41 -08:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void refreshMapAveragingPreCalc() {
|
2020-09-03 16:29:15 -07:00
|
|
|
int rpm = GET_RPM();
|
2018-02-06 12:47:19 -08:00
|
|
|
if (isValidRpm(rpm)) {
|
|
|
|
MAP_sensor_config_s * c = &engineConfiguration->map;
|
2021-02-16 06:32:16 -08:00
|
|
|
angle_t start = interpolate2d(rpm, c->samplingAngleBins, c->samplingAngle);
|
2019-11-04 06:20:00 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_MAP_START_ASSERT, !cisnan(start), "start");
|
2018-02-06 12:47:19 -08:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
angle_t offsetAngle = engine->triggerCentral.triggerFormDetails.eventAngles[engineConfiguration->mapAveragingSchedulingAtIndex];
|
2019-07-06 17:45:47 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_MAP_AVG_OFFSET, !cisnan(offsetAngle), "offsetAngle");
|
2018-02-06 12:47:19 -08:00
|
|
|
|
2021-03-20 05:40:36 -07:00
|
|
|
for (size_t i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
2021-11-16 01:15:29 -08:00
|
|
|
angle_t cylinderOffset = getEngineCycle(engine->getOperationMode()) * i / engineConfiguration->specs.cylindersCount;
|
2019-11-04 06:20:00 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_MAP_CYL_OFFSET, !cisnan(cylinderOffset), "cylinderOffset");
|
2019-10-14 03:18:08 -07:00
|
|
|
// part of this formula related to specific cylinder offset is never changing - we can
|
|
|
|
// move the loop into start-up calculation and not have this loop as part of periodic calculation
|
|
|
|
// todo: change the logic as described above in order to reduce periodic CPU usage?
|
2018-02-06 12:47:19 -08:00
|
|
|
float cylinderStart = start + cylinderOffset - offsetAngle + tdcPosition();
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(cylinderStart, "cylinderStart", CUSTOM_ERR_6562);
|
2018-02-06 12:47:19 -08:00
|
|
|
engine->engineState.mapAveragingStart[i] = cylinderStart;
|
|
|
|
}
|
2021-02-16 06:32:16 -08:00
|
|
|
engine->engineState.mapAveragingDuration = interpolate2d(rpm, c->samplingWindowBins, c->samplingWindow);
|
2018-02-06 12:47:19 -08:00
|
|
|
} else {
|
2021-03-20 05:40:36 -07:00
|
|
|
for (size_t i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
2018-02-06 12:47:19 -08:00
|
|
|
engine->engineState.mapAveragingStart[i] = NAN;
|
|
|
|
}
|
|
|
|
engine->engineState.mapAveragingDuration = NAN;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* Shaft Position callback used to schedule start and end of MAP averaging
|
|
|
|
*/
|
2020-10-03 23:09:12 -07:00
|
|
|
void mapAveragingTriggerCallback(
|
2021-11-16 01:15:29 -08:00
|
|
|
uint32_t index, efitick_t edgeTimestamp) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2015-07-10 06:01:56 -07:00
|
|
|
// this callback is invoked on interrupt thread
|
2021-11-17 00:54:21 -08:00
|
|
|
if (index != (uint32_t)engineConfiguration->mapAveragingSchedulingAtIndex)
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
|
2020-09-03 16:29:15 -07:00
|
|
|
int rpm = GET_RPM();
|
2017-05-25 20:23:03 -07:00
|
|
|
if (!isValidRpm(rpm)) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
2017-05-25 20:23:03 -07:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-10-16 08:04:27 -07:00
|
|
|
ScopePerf perf(PE::MapAveragingTriggerCallback);
|
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engineConfiguration->mapMinBufferLength != mapMinBufferLength) {
|
2021-11-16 01:15:29 -08:00
|
|
|
applyMapMinBufferLength();
|
2017-06-22 01:21:35 -07:00
|
|
|
}
|
|
|
|
|
2015-09-06 18:02:46 -07:00
|
|
|
measurementsPerRevolution = measurementsPerRevolutionCounter;
|
|
|
|
measurementsPerRevolutionCounter = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-10-03 23:09:12 -07:00
|
|
|
// todo: this could be pre-calculated
|
2021-11-17 00:54:21 -08:00
|
|
|
int samplingCount = engineConfiguration->measureMapOnlyInOneCylinder ? 1 : engineConfiguration->specs.cylindersCount;
|
2018-01-24 06:14:30 -08:00
|
|
|
|
|
|
|
for (int i = 0; i < samplingCount; i++) {
|
2021-11-17 00:54:21 -08:00
|
|
|
angle_t samplingStart = engine->engineState.mapAveragingStart[i];
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
angle_t samplingDuration = engine->engineState.mapAveragingDuration;
|
2020-10-03 23:09:12 -07:00
|
|
|
// todo: this assertion could be moved out of trigger handler
|
2019-06-27 19:23:18 -07:00
|
|
|
assertAngleRange(samplingDuration, "samplingDuration", CUSTOM_ERR_6563);
|
2015-09-06 20:01:28 -07:00
|
|
|
if (samplingDuration <= 0) {
|
2017-05-29 16:23:15 -07:00
|
|
|
warning(CUSTOM_MAP_ANGLE_PARAM, "map sampling angle should be positive");
|
2015-09-06 20:01:28 -07:00
|
|
|
return;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2015-09-06 20:01:28 -07:00
|
|
|
angle_t samplingEnd = samplingStart + samplingDuration;
|
2018-02-06 13:21:41 -08:00
|
|
|
|
|
|
|
if (cisnan(samplingEnd)) {
|
|
|
|
// todo: when would this happen?
|
|
|
|
warning(CUSTOM_ERR_6549, "no map angles");
|
|
|
|
return;
|
2015-09-06 20:01:28 -07:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-10-03 23:09:12 -07:00
|
|
|
// todo: pre-calculate samplingEnd for each cylinder
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(samplingEnd, "samplingEnd", CUSTOM_ERR_6563);
|
2018-02-06 13:21:41 -08:00
|
|
|
// only if value is already prepared
|
2019-10-14 03:18:08 -07:00
|
|
|
int structIndex = getRevolutionCounter() % 2;
|
2021-06-25 07:43:58 -07:00
|
|
|
|
|
|
|
scheduling_s *starTimer = &startTimers[i][structIndex];
|
|
|
|
scheduling_s *endTimer = &endTimers[i][structIndex];
|
|
|
|
|
2019-10-14 03:18:08 -07:00
|
|
|
// at the moment we schedule based on time prediction based on current RPM and angle
|
|
|
|
// we are loosing precision in case of changing RPM - the further away is the event the worse is precision
|
2018-02-06 13:21:41 -08:00
|
|
|
// todo: schedule this based on closest trigger event, same as ignition works
|
2021-06-25 07:43:58 -07:00
|
|
|
scheduleByAngle(starTimer, edgeTimestamp, samplingStart,
|
2021-11-16 01:15:29 -08:00
|
|
|
{ startAveraging, endTimer });
|
2018-02-06 13:21:41 -08:00
|
|
|
}
|
2019-01-31 08:57:15 -08:00
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-11-15 04:02:34 -08:00
|
|
|
static void showMapStats() {
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("per revolution %d", measurementsPerRevolution);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void initMapAveraging() {
|
2020-07-31 14:41:42 -07:00
|
|
|
#if !EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
addConsoleAction("faststat", showMapStats);
|
2019-12-23 20:25:08 -08:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
applyMapMinBufferLength();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* EFI_MAP_AVERAGING */
|