Start support for multi-bank closed loop fueling (#2184)
* cfg * cell * N banks * tests Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
parent
bef4482fb8
commit
571122d461
|
@ -139,7 +139,9 @@ void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
// todo: move this into slow callback, no reason for CLT corr to be here
|
// todo: move this into slow callback, no reason for CLT corr to be here
|
||||||
running.coolantTemperatureCoefficient = getCltFuelCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
|
running.coolantTemperatureCoefficient = getCltFuelCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
|
||||||
running.pidCorrection = fuelClosedLoopCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
|
// TODO: consume correction from the second bank
|
||||||
|
auto clResult = fuelClosedLoopCorrection(PASS_ENGINE_PARAMETER_SIGNATURE);
|
||||||
|
running.pidCorrection = clResult.banks[0];
|
||||||
|
|
||||||
// update fuel consumption states
|
// update fuel consumption states
|
||||||
fuelConsumption.update(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
fuelConsumption.update(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
|
@ -9,12 +9,24 @@
|
||||||
|
|
||||||
EXTERN_ENGINE;
|
EXTERN_ENGINE;
|
||||||
|
|
||||||
ClosedLoopFuelCellImpl cells[STFT_CELL_COUNT];
|
struct FuelingBank {
|
||||||
|
ClosedLoopFuelCellImpl cells[STFT_CELL_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
static FuelingBank banks[STFT_BANK_COUNT];
|
||||||
|
|
||||||
static Deadband<25> idleDeadband;
|
static Deadband<25> idleDeadband;
|
||||||
static Deadband<2> overrunDeadband;
|
static Deadband<2> overrunDeadband;
|
||||||
static Deadband<2> loadDeadband;
|
static Deadband<2> loadDeadband;
|
||||||
|
|
||||||
|
static SensorType getSensorForBankIndex(size_t index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0: return SensorType::Lambda1;
|
||||||
|
case 1: return SensorType::Lambda2;
|
||||||
|
default: return SensorType::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t computeStftBin(int rpm, float load, stft_s& cfg) {
|
size_t computeStftBin(int rpm, float load, stft_s& cfg) {
|
||||||
// Low RPM -> idle
|
// Low RPM -> idle
|
||||||
if (idleDeadband.lt(rpm, cfg.maxIdleRegionRpm * RPM_1_BYTE_PACKING_MULT))
|
if (idleDeadband.lt(rpm, cfg.maxIdleRegionRpm * RPM_1_BYTE_PACKING_MULT))
|
||||||
|
@ -66,12 +78,12 @@ static bool shouldCorrect(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldUpdateCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
bool shouldUpdateCorrection(SensorType sensor DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
const auto& cfg = CONFIG(stft);
|
const auto& cfg = CONFIG(stft);
|
||||||
|
|
||||||
// Pause (but don't reset) correction if the AFR is off scale.
|
// Pause (but don't reset) correction if the AFR is off scale.
|
||||||
// It's probably a transient and poorly tuned transient correction
|
// It's probably a transient and poorly tuned transient correction
|
||||||
auto afr = Sensor::get(SensorType::Lambda1).value_or(0) * 14.7f;
|
auto afr = Sensor::get(sensor).value_or(0) * 14.7f;
|
||||||
if (!afr || afr < (cfg.minAfr * 0.1f) || afr > (cfg.maxAfr * 0.1f)) {
|
if (!afr || afr < (cfg.minAfr * 0.1f) || afr > (cfg.maxAfr * 0.1f)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -79,9 +91,9 @@ bool shouldUpdateCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
ClosedLoopFuelResult fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
if (!shouldCorrect(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
if (!shouldCorrect(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
||||||
return 1.0f;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t binIdx = computeStftBin(GET_RPM(), getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE), CONFIG(stft));
|
size_t binIdx = computeStftBin(GET_RPM(), getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE), CONFIG(stft));
|
||||||
|
@ -92,14 +104,22 @@ float fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
||||||
}
|
}
|
||||||
#endif // EFI_TUNER_STUDIO
|
#endif // EFI_TUNER_STUDIO
|
||||||
|
|
||||||
auto& cell = cells[binIdx];
|
ClosedLoopFuelResult result;
|
||||||
|
|
||||||
|
for (int i = 0; i < STFT_BANK_COUNT; i++) {
|
||||||
|
auto& cell = banks[i].cells[binIdx];
|
||||||
|
|
||||||
|
SensorType sensor = getSensorForBankIndex(i);
|
||||||
|
|
||||||
// todo: push configuration at startup
|
// todo: push configuration at startup
|
||||||
cell.configure(&CONFIG(stft.cellCfgs[binIdx]));
|
cell.configure(&CONFIG(stft.cellCfgs[binIdx]), sensor);
|
||||||
|
|
||||||
if (shouldUpdateCorrection(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
if (shouldUpdateCorrection(sensor PASS_ENGINE_PARAMETER_SUFFIX)) {
|
||||||
cell.update(CONFIG(stft.deadband) * 0.001f, CONFIG(stftIgnoreErrorMagnitude) PASS_ENGINE_PARAMETER_SUFFIX);
|
cell.update(CONFIG(stft.deadband) * 0.001f, CONFIG(stftIgnoreErrorMagnitude) PASS_ENGINE_PARAMETER_SUFFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell.getAdjustment();
|
result.banks[i] = cell.getAdjustment();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "globalaccess.h"
|
#include "engine_ptr.h"
|
||||||
#include "engine_configuration_generated_structures.h"
|
#include "sensor.h"
|
||||||
|
#include "rusefi_generated.h"
|
||||||
|
|
||||||
float fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
struct stft_s;
|
||||||
|
|
||||||
|
struct ClosedLoopFuelResult {
|
||||||
|
ClosedLoopFuelResult() {
|
||||||
|
// Default is no correction, aka 1.0 multiplier
|
||||||
|
for (size_t i = 0; i < STFT_BANK_COUNT; i++) {
|
||||||
|
banks[i] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float banks[STFT_BANK_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
ClosedLoopFuelResult fuelClosedLoopCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
||||||
size_t computeStftBin(int rpm, float load, stft_s& cfg);
|
size_t computeStftBin(int rpm, float load, stft_s& cfg);
|
||||||
bool shouldUpdateCorrection(DECLARE_ENGINE_PARAMETER_SIGNATURE);
|
bool shouldUpdateCorrection(SensorType sensor DECLARE_ENGINE_PARAMETER_SUFFIX);
|
||||||
|
|
|
@ -49,7 +49,7 @@ float ClosedLoopFuelCellBase::getAdjustment() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
float ClosedLoopFuelCellImpl::getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
float ClosedLoopFuelCellImpl::getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
||||||
auto lambda = Sensor::get(SensorType::Lambda1);
|
auto lambda = Sensor::get(m_lambdaSensor);
|
||||||
|
|
||||||
// Failed sensor -> no error
|
// Failed sensor -> no error
|
||||||
if (!lambda) {
|
if (!lambda) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "globalaccess.h"
|
#include "engine_ptr.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
|
||||||
class ClosedLoopFuelCellBase {
|
class ClosedLoopFuelCellBase {
|
||||||
public:
|
public:
|
||||||
|
@ -28,12 +29,14 @@ struct stft_cell_cfg_s;
|
||||||
|
|
||||||
class ClosedLoopFuelCellImpl final : public ClosedLoopFuelCellBase {
|
class ClosedLoopFuelCellImpl final : public ClosedLoopFuelCellBase {
|
||||||
public:
|
public:
|
||||||
void configure(const stft_cell_cfg_s* configuration) {
|
void configure(const stft_cell_cfg_s* configuration, SensorType lambdaSensor) {
|
||||||
m_config = configuration;
|
m_config = configuration;
|
||||||
|
m_lambdaSensor = lambdaSensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const stft_cell_cfg_s *m_config = nullptr;
|
const stft_cell_cfg_s *m_config = nullptr;
|
||||||
|
SensorType m_lambdaSensor = SensorType::Invalid;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const override;
|
float getLambdaError(DECLARE_ENGINE_PARAMETER_SIGNATURE) const override;
|
||||||
|
|
|
@ -153,6 +153,7 @@ struct_no_prefix engine_configuration_s
|
||||||
#define PEDAL_TO_TPS_SIZE 8
|
#define PEDAL_TO_TPS_SIZE 8
|
||||||
|
|
||||||
#define STFT_CELL_COUNT 4
|
#define STFT_CELL_COUNT 4
|
||||||
|
#define STFT_BANK_COUNT 2
|
||||||
|
|
||||||
#define CAN_DEFAULT_BASE 0x200
|
#define CAN_DEFAULT_BASE 0x200
|
||||||
|
|
||||||
|
|
|
@ -88,11 +88,11 @@ TEST(ClosedLoopFuel, afrLimits) {
|
||||||
engineConfiguration->stft.maxAfr = 180; // 18.0 AFR
|
engineConfiguration->stft.maxAfr = 180; // 18.0 AFR
|
||||||
|
|
||||||
Sensor::setMockValue(SensorType::Lambda1, 0.1f);
|
Sensor::setMockValue(SensorType::Lambda1, 0.1f);
|
||||||
EXPECT_FALSE(shouldUpdateCorrection(PASS_ENGINE_PARAMETER_SIGNATURE));
|
EXPECT_FALSE(shouldUpdateCorrection(SensorType::Lambda1 PASS_ENGINE_PARAMETER_SUFFIX));
|
||||||
|
|
||||||
Sensor::setMockValue(SensorType::Lambda1, 1.0f);
|
Sensor::setMockValue(SensorType::Lambda1, 1.0f);
|
||||||
EXPECT_TRUE(shouldUpdateCorrection(PASS_ENGINE_PARAMETER_SIGNATURE));
|
EXPECT_TRUE(shouldUpdateCorrection(SensorType::Lambda1 PASS_ENGINE_PARAMETER_SUFFIX));
|
||||||
|
|
||||||
Sensor::setMockValue(SensorType::Lambda1, 2.0f);
|
Sensor::setMockValue(SensorType::Lambda1, 2.0f);
|
||||||
EXPECT_FALSE(shouldUpdateCorrection(PASS_ENGINE_PARAMETER_SIGNATURE));
|
EXPECT_FALSE(shouldUpdateCorrection(SensorType::Lambda1 PASS_ENGINE_PARAMETER_SUFFIX));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue