rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
Functions | Variables
software_knock.cpp File Reference

Functions

chibios_rt::BinarySemaphore knockSem (true)
 
void onKnockSamplingComplete ()
 
void onStartKnockSampling (uint8_t cylinderNumber, float samplingSeconds, uint8_t channelIdx)
 
void initSoftwareKnock ()
 
static uint8_t toDb (const float &voltage)
 
static void processLastKnockEvent ()
 

Variables

static size_t spectrogramStartIndex = 0
 
static SpectrogramData spectrogramData0
 
static SpectrogramDataspectrogramData = &spectrogramData0
 
static NO_CACHE adcsample_t sampleBuffer [1800]
 
static int8_t currentCylinderNumber = 0
 
static int8_t channelNumber = 0
 
static efitick_t lastKnockSampleTime = 0
 
static Biquad knockFilter
 
static volatile bool knockIsSampling = false
 
static volatile bool knockNeedsProcess = false
 
static volatile size_t sampleCount = 0
 
static KnockThread kt
 

Function Documentation

◆ initSoftwareKnock()

void initSoftwareKnock ( )

Definition at line 91 of file software_knock.cpp.

91 {
93
94 float frequencyHz = 1000 * bore2frequency(engineConfiguration->cylinderBore);
95 frequencyHz = engineConfiguration->knockDetectionUseDoubleFrequency ? 2 * frequencyHz : frequencyHz;
96
99 }
100
101 knockFilter.configureBandpass(KNOCK_SAMPLE_RATE, frequencyHz, 3);
102
103 #ifdef KNOCK_SPECTROGRAM
105
106 // TODO: use big buffer
107 //buffer = getBigBuffer(BigBufferUser::KnockSpectrogram);
108 // if (!buffer) {
109 // engineConfiguration->enableKnockSpectrogram = false;
110 // return;
111 // }
112 //spectrogramData = buffer.get<SpectrogramData>();
113
115
116 int freqStartConst = START_SPECTRORGAM_FREQUENCY;
117 int minFreqDiff = freqStartConst;
118 int freqStart = 0;
119 float freqStep = 0;
120
121 for (size_t i = 0; i < FFT_SIZE/2; i++)
122 {
123 float freq = float(i * KNOCK_SAMPLE_RATE) / FFT_SIZE;
124 int min = abs(freq - freqStartConst);
125
126 // next after freq start index
127 if(i == spectrogramStartIndex + 1) {
128 freqStep = abs(freq - freqStart);
129 }
130
131 if(min < minFreqDiff) {
132 minFreqDiff = min;
134 freqStart = freq;
135 }
136 }
137
138 engine->module<KnockController>()->m_knockFrequencyStart = (uint16_t)freqStart;
140 }
141 #endif
142
143 // fun fact: we do not offer any ADC channel flexibility like we have for many other kinds of inputs
144 efiSetPadMode("knock ch1", KNOCK_PIN_CH1, PAL_MODE_INPUT_ANALOG);
145#if KNOCK_HAS_CH2
146 efiSetPadMode("knock ch2", KNOCK_PIN_CH2, PAL_MODE_INPUT_ANALOG);
147#endif
148 kt.start();
149 }
150}
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
void configureBandpass(float samplingFrequency, float centerFrequency, float Q)
Definition biquad.cpp:32
constexpr auto & module()
Definition engine.h:200
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
void blackmanharris(float *w, unsigned n, bool sflag)
Definition fft.hpp:188
m_knockFrequencyStep("Knock: Step Freq", SensorCategory.SENSOR_INPUTS, FieldType.INT, 1096, 1.0, 0.0, 0.0, "Hz")
m_knockFrequencyStart("Knock: Start Freq", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 1094, 1.0, 0.0, 0.0, "Hz")
static SpectrogramData * spectrogramData
static size_t spectrogramStartIndex
static Biquad knockFilter
static KnockThread kt
float window[FFT_SIZE]

Referenced by initHardware().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ knockSem()

chibios_rt::BinarySemaphore knockSem ( true  )

Referenced by onKnockSamplingComplete().

Here is the caller graph for this function:

◆ onKnockSamplingComplete()

void onKnockSamplingComplete ( )

Definition at line 41 of file software_knock.cpp.

41 {
42 knockNeedsProcess = true;
43
44 // Notify the processing thread that it's time to process this sample
45 chSysLockFromISR();
46 knockSem.signalI();
47 chSysUnlockFromISR();
48}
chibios_rt::BinarySemaphore knockSem(true)
static volatile bool knockNeedsProcess

Referenced by knockCompletionCallback(), and knockCompletionCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ onStartKnockSampling()

void onStartKnockSampling ( uint8_t  cylinderNumber,
float  samplingSeconds,
uint8_t  channelIdx 
)

Definition at line 50 of file software_knock.cpp.

50 {
52 return;
53 }
54
55 // Cancel if ADC isn't ready
56 if (!((KNOCK_ADC.state == ADC_READY) ||
57 (KNOCK_ADC.state == ADC_ERROR))) {
58 return;
59 }
60
61 // If there's pending processing, skip this event
63 return;
64 }
65
66 // Convert sampling time to number of samples
67 constexpr int sampleRate = KNOCK_SAMPLE_RATE;
68 sampleCount = 0xFFFFFFFE & static_cast<size_t>(clampF(100, samplingSeconds * sampleRate, efi::size(sampleBuffer)));
69
70 // Select the appropriate conversion group - it will differ depending on which sensor this cylinder should listen on
71 auto conversionGroup = getKnockConversionGroup(channelIdx);
72
73 //current chanel number for spectrum TS plugin
75
76 // Stash the current cylinder's number so we can store the result appropriately
77 currentCylinderNumber = cylinderNumber;
78
79 adcStartConversionI(&KNOCK_ADC, conversionGroup, sampleBuffer, sampleCount);
81}
const ADCConversionGroup * getKnockConversionGroup(uint8_t channelIdx)
efitick_t getTimeNowNt()
Definition efitime.cpp:19
float uint8_t channelIdx
static int8_t channelNumber
static volatile size_t sampleCount
static NO_CACHE adcsample_t sampleBuffer[1800]
static efitick_t lastKnockSampleTime
static int8_t currentCylinderNumber

Referenced by startKnockSampling().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ processLastKnockEvent()

static void processLastKnockEvent ( )
static

Definition at line 160 of file software_knock.cpp.

160 {
161 if (!knockNeedsProcess) {
162 return;
163 }
164
165 float sumSq = 0;
166
167 // todo: reduce magic constants. engineConfiguration->adcVcc?
168 constexpr float ratio = 3.3f / 4095.0f;
169
170 size_t localCount = sampleCount;
171
172 // Prepare the steady state at vcc/2 so that there isn't a step
173 // when samples begin
174 // todo: reduce magic constants. engineConfiguration->adcVcc?
176
177 // Compute the sum of squares
178 for (size_t i = 0; i < localCount; i++) {
179 float volts = ratio * sampleBuffer[i];
180
181 float filtered = knockFilter.filter(volts);
182 if (i == localCount - 1 && engineConfiguration->debugMode == DBG_KNOCK) {
185 }
186
187 sumSq += filtered * filtered;
188 }
189
190 // take a local copy
191 auto lastKnockTime = lastKnockSampleTime;
192
193 // We're done with inspecting the buffer, another sample can be taken
194 knockNeedsProcess = false;
195
196#ifdef KNOCK_SPECTROGRAM
199
202 } else {
204 }
205
206 auto* spectrum = &engine->module<KnockController>()->m_knockSpectrum[0];
207 for(uint8_t i = 0; i < COMPRESSED_SPECTRUM_PROTOCOL_SIZE; ++i) {
208
209 uint8_t startIndex = spectrogramStartIndex + (i * 4);
210
211 uint8_t a = toDb(fft::amplitude(spectrogramData->fftBuffer[startIndex]));
212 uint8_t b = toDb(fft::amplitude(spectrogramData->fftBuffer[startIndex + 1]));
213 uint8_t c = toDb(fft::amplitude(spectrogramData->fftBuffer[startIndex + 2]));
214 uint8_t d = toDb(fft::amplitude(spectrogramData->fftBuffer[startIndex + 3]));
215
216 uint32_t compressed = uint32_t(a << 24 | b << 16 | c << 8 | d);
217
218 {
219 chibios_rt::CriticalSectionLocker csl;
220 spectrum[i] = compressed;
221 }
222 }
223
224 uint16_t compressedChannelCyl = uint16_t(channelNumber << 8 | currentCylinderNumber);
225
226 {
227 chibios_rt::CriticalSectionLocker csl;
228 engine->module<KnockController>()->m_knockSpectrumChannelCyl = compressedChannelCyl;
229 }
230 }
231
232#endif
233
234 // mean of squares (not yet root)
235 float meanSquares = sumSq / localCount;
236
237 // RMS
238 float db = 10 * log10(meanSquares);
239
240 // clamp to reasonable range
241 db = clampF(-100, db, 100);
242
243 engine->module<KnockController>()->onKnockSenseCompleted(currentCylinderNumber, db, lastKnockTime);
244}
float filter(float input)
Definition biquad.cpp:74
void cookSteadyState(float steadyStateInput)
Definition biquad.cpp:84
TunerStudioOutputChannels outputChannels
Definition engine.h:109
float amplitude(const complex_type &fft)
Definition fft.hpp:133
bool fft_adc_sample_filtered(Biquad &knockFilter, float *w, float ratio, float sensitivity, const adcsample_t *data_in, complex_type *data_out, const size_t size)
Definition fft.hpp:98
bool fft_adc_sample(float *w, float ratio, float sensitivity, const adcsample_t *data_in, complex_type *data_out, const size_t size)
Definition fft.hpp:88
@ KnockAnalyzer
m_knockSpectrumChannelCyl("Knock: ChannelAndCylNumber", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 1092, 1.0, 0.0, 0.0, "compressed N + N")
static uint8_t toDb(const float &voltage)
fft::complex_type fftBuffer[FFT_SIZE]
Here is the call graph for this function:

◆ toDb()

static uint8_t toDb ( const float voltage)
static

Definition at line 153 of file software_knock.cpp.

153 {
154 float db = 200 * log10(voltage*voltage) + 40; // best scaling for view
155 db = clampF(0, db, 255);
156 return uint8_t(db);
157}

Referenced by processLastKnockEvent().

Here is the caller graph for this function:

Variable Documentation

◆ channelNumber

int8_t channelNumber = 0
static

Definition at line 31 of file software_knock.cpp.

Referenced by onStartKnockSampling(), and processLastKnockEvent().

◆ currentCylinderNumber

int8_t currentCylinderNumber = 0
static

Definition at line 30 of file software_knock.cpp.

Referenced by onStartKnockSampling(), and processLastKnockEvent().

◆ knockFilter

Biquad knockFilter
static

◆ knockIsSampling

volatile bool knockIsSampling = false
static

Definition at line 35 of file software_knock.cpp.

◆ knockNeedsProcess

volatile bool knockNeedsProcess = false
static

◆ kt

KnockThread kt
static

Definition at line 89 of file software_knock.cpp.

Referenced by initSoftwareKnock().

◆ lastKnockSampleTime

efitick_t lastKnockSampleTime = 0
static

Definition at line 32 of file software_knock.cpp.

Referenced by onStartKnockSampling(), and processLastKnockEvent().

◆ sampleBuffer

NO_CACHE adcsample_t sampleBuffer[1800]
static

Definition at line 29 of file software_knock.cpp.

Referenced by onStartKnockSampling(), and processLastKnockEvent().

◆ sampleCount

volatile size_t sampleCount = 0
static

Definition at line 37 of file software_knock.cpp.

Referenced by onStartKnockSampling(), and processLastKnockEvent().

◆ spectrogramData

SpectrogramData* spectrogramData = &spectrogramData0
static

Definition at line 20 of file software_knock.cpp.

Referenced by initSoftwareKnock(), and processLastKnockEvent().

◆ spectrogramData0

SpectrogramData spectrogramData0
static

Definition at line 19 of file software_knock.cpp.

◆ spectrogramStartIndex

size_t spectrogramStartIndex = 0
static

Definition at line 18 of file software_knock.cpp.

Referenced by initSoftwareKnock(), and processLastKnockEvent().

Go to the source code of this file.