rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
knock_controller.cpp
Go to the documentation of this file.
1/*
2 * @file knock_logic.c
3 *
4 * @date Apr 04, 2021
5 * @author Andrey Gusakov
6 */
7
8#include "pch.h"
9#include "knock_logic.h"
10
11int getCylinderKnockBank(uint8_t cylinderNumber) {
12 // C/C++ can't index in to bit fields, we have to provide lookup ourselves
13 switch (cylinderNumber) {
14 case 0:
16 case 1:
18 case 2:
20 case 3:
22 case 4:
24 case 5:
26 case 6:
28 case 7:
30 case 8:
32 case 9:
34 case 10:
36 case 11:
38 default:
39 return 0;
40 }
41}
42
43void KnockControllerBase::onKnockSenseCompleted(uint8_t cylinderNumber, float dbv, efitick_t lastKnockTime) {
44 bool isKnock = dbv > m_knockThreshold;
45
46 // Per-cylinder peak detector
47 float cylPeak = peakDetectors[cylinderNumber].detect(dbv, lastKnockTime);
48 m_knockCyl[cylinderNumber] = roundf(cylPeak);
49
50 // All-cylinders peak detector
51 m_knockLevel = allCylinderPeakDetector.detect(dbv, lastKnockTime);
52
53 if (isKnock) {
55
56 auto baseTiming = engine->engineState.timingAdvance[cylinderNumber];
57
58 // TODO: 20 configurable? Better explanation why 20?
59 auto distToMinimum = baseTiming - (-20);
60
61 // percent -> ratio = divide by 100
62 auto retardFraction = engineConfiguration->knockRetardAggression * 0.01f;
63 auto retardAmount = distToMinimum * retardFraction;
64
65 // TODO: remove magic 30% m_maximumFuelTrim?
66 auto maximumFuelTrim = 0.3f;
67
68 auto trimFuelFraction = engineConfiguration->knockFuelTrimAggression * 0.01f;
69 float trimFuelPercent = clampF(0.f, (float)engineConfiguration->knockFuelTrim, maximumFuelTrim * 100.f);
70 float trimFuelAmountPercent = trimFuelPercent * trimFuelFraction;
71 float trimFuelAmount = trimFuelAmountPercent / 100.f;
72
73 {
74 // Adjust knock retard under lock
75 chibios_rt::CriticalSectionLocker csl;
76
77 auto newRetard = m_knockRetard + retardAmount;
78 m_knockRetard = clampF(0.f, newRetard, m_maximumRetard);
79
80 auto newFuelTrim = m_knockFuelTrimMultiplier + trimFuelAmount;
81 m_knockFuelTrimMultiplier = clampF(0.f, newFuelTrim, maximumFuelTrim);
82 }
83 }
84}
85
89
91 return m_knockCount;
92}
93
97
101
102 constexpr auto callbackPeriodSeconds = FAST_CALLBACK_PERIOD_MS / 1000.0f;
103
104 auto applyRetardAmount = engineConfiguration->knockRetardReapplyRate * callbackPeriodSeconds;
105 auto applyFuelAmount = engineConfiguration->knockFuelTrimReapplyRate * 0.01f * callbackPeriodSeconds;
106
107 // disable knock suppression then deceleration
109
110 {
111 // Adjust knock retard under lock
112 chibios_rt::CriticalSectionLocker csl;
113
114
115 if(TPSValue < engineConfiguration->knockSuppressMinTps) {
116 m_knockRetard = 0.0;
118 return;
119 }
120
121 // Reduce knock retard at the requested rate
122 float newRetard = m_knockRetard - applyRetardAmount;
123
124 // don't allow retard to go negative
125 if (newRetard < 0) {
126 m_knockRetard = 0;
127 } else {
128 m_knockRetard = newRetard;
129 }
130
131 // Reduce fuel trim at the requested rate
132 float newTrim = m_knockFuelTrimMultiplier - applyFuelAmount;
133
134 // don't allow trim to go negative
135 if (newTrim < 0) {
137 } else {
139 }
140 }
141}
142
144 return interpolate2d(
148 );
149}
150
159
160// This callback is to be implemented by the knock sense driver
161__attribute__((weak)) void onStartKnockSampling(uint8_t cylinderNumber, float samplingTimeSeconds, uint8_t channelIdx) {
162 UNUSED(cylinderNumber);
165}
166
167#if EFI_SOFTWARE_KNOCK
168static uint8_t cylinderNumberCopy;
169
170// Called when its time to start listening for knock
171// Does some math, then hands off to the driver to start any sampling hardware
172static void startKnockSampling(Engine* p_engine) {
173 // todo: why do we pass engine as parameter? is that for unit tests?
174 if (!p_engine->rpmCalculator.isRunning()) {
175 return;
176 }
177
178 // Convert sampling angle to time
179 float samplingSeconds = engine->rpmCalculator.oneDegreeUs * engineConfiguration->knockSamplingDuration / US_PER_SECOND_F;
180
181 // Look up which channel this cylinder uses
183
184 // Call the driver to begin sampling
186}
187
188#endif // EFI_SOFTWARE_KNOCK
189
190void Engine::onSparkFireKnockSense(uint8_t cylinderNumber, efitick_t nowNt) {
191#if EFI_SOFTWARE_KNOCK
192 cylinderNumberCopy = cylinderNumber;
193 scheduleByAngle(nullptr, nowNt,
194 /*angle*/engineConfiguration->knockDetectionWindowStart, action_s::make<startKnockSampling>(static_cast<Engine*>(engine)));
195#else
196 UNUSED(cylinderNumber);
197 UNUSED(nowNt);
198#endif
199}
uint16_t channel
Definition adc_inputs.h:104
typedef __attribute__
Ignition Mode.
EngineState engineState
Definition engine.h:344
RpmCalculator rpmCalculator
Definition engine.h:306
void onSparkFireKnockSense(uint8_t cylinderIndex, efitick_t nowNt)
angle_t timingAdvance[MAX_CYLINDER_COUNT]
float getKnockRetard() const
float getFuelTrimMultiplier() const
virtual float getMaximumRetard() const =0
uint32_t getKnockCount() const
void onFastCallback() override
PD peakDetectors[MAX_CYLINDER_COUNT]
Definition knock_logic.h:38
void onKnockSenseCompleted(uint8_t cylinderNumber, float dbv, efitick_t lastKnockTime)
virtual float getKnockThreshold() const =0
float getKnockThreshold() const override
float getMaximumRetard() const override
TValue detect(TValue currentValue, efitick_t nowNt)
Definition peak_detect.h:11
floatus_t oneDegreeUs
bool isRunning() const
static float getOrZero(SensorType type)
Definition sensor.h:83
static EngineAccessor engine
Definition engine.h:413
static constexpr persistent_config_s * config
static constexpr engine_configuration_s * engineConfiguration
float getIgnitionLoad()
float samplingTimeSeconds
float uint8_t channelIdx
static void startKnockSampling(Engine *p_engine)
int getCylinderKnockBank(uint8_t cylinderNumber)
UNUSED(samplingTimeSeconds)
static uint8_t cylinderNumberCopy
efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s const &action)
TPSValue("TPS", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 22, 0.01, 0.0, 0.0, "%")
void onStartKnockSampling(uint8_t cylinderNumber, float samplingSeconds, uint8_t channelIdx)
int8_t m_knockCyl[MAX_CYLINDER_COUNT]
scaled_channel< uint8_t, 1, 100 > maxKnockRetardRpmBins[KNOCK_TABLE_SIZE]
scaled_channel< uint8_t, 4, 1 > maxKnockRetardTable[KNOCK_TABLE_SIZE][KNOCK_TABLE_SIZE]
scaled_channel< int8_t, 2, 1 > knockBaseNoise[ENGINE_NOISE_CURVE_SIZE]