Detecting a beep with ESP32/micropython
Detecting a beep with ESP32/micropython
I want to use a cheap mic + ESP32 running micropython to detect a high frequency beep. I don't have a background in audio. Can someone please advise me how I can best do this? I assume there is something like read adc -> fft -> if at this frequency there is a beep...but i am not sure. Thank you.
Re: Detecting a beep with ESP32/micropython
Sounds like a fun project. If you know the frequency of the beep, you can use a sin curve fitting function and check if the amplitude > your threshold.
Sent from my Pixel 2 XL using Tapatalk
Sent from my Pixel 2 XL using Tapatalk
Re: Detecting a beep with ESP32/micropython
I made a fit_sin() function https://github.com/KipCrossing/SpecialMath for one of my projects that might be help. Just set your ADC sample rate to some multiple m of the frequency of the beep frequency and average your buffer into a list of size m for the function. Averaging will help reduce noise.
Sent from my Pixel 2 XL using Tapatalk
Sent from my Pixel 2 XL using Tapatalk
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Detecting a beep with ESP32/micropython
FFT is rather heavy-duty. You could look at FIR filters - this repo may provide general information but the code won't be of use as it's STM specific.
If the frequency of the beep is precisely controlled you could use synchronous detection. In any event you need a detection method with some degree of noise immunity.
If the frequency of the beep is precisely controlled you could use synchronous detection. In any event you need a detection method with some degree of noise immunity.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Detecting a beep with ESP32/micropython
The Goertzel algorithm is quite efficient when searching for a single tone.
It essentially calculates one FFT bin.
It essentially calculates one FFT bin.
Code: Select all
def goertzel(target_freq, sampling_freq, data):
'''
When searching for a specific signal tone the Goertzel algorithm can be more efficient than fft.
This routine returns magnitude of a single fft bin, which contains the target frequency.
Ideally, the sampling frequency should be an exact multiple of the target frequency (see fft window functions)
The bin width is sampling_freq / len(data).
E.g. 200 samples at 10kHz sampling freq gives 50Hz bin width. The bins would be:
Bin 0: -25 Hz to 25 Hz (centre: 0 Hz)
Bin 1: 25 Hz to 75 Hz (centre: 50 Hz)
Bin 2: 75 Hz to 125 Hz (centre: 100 Hz)
...etc
So, make sure your target frequency is a bin centre frequency and sampling_freq = n * target_freq
where n is any integer.
'''
#You can pre-calculate much of this stuff to save time if calling multiple times
numSamples = len(data)
scalingFactor = numSamples / 2.0
k = round(numSamples * target_freq / sampling_freq)
omega = 2.0 * math.pi * k / numSamples
sin_omega = math.sin(omega)
cos_omega = math.cos(omega)
coeff = 2.0 * cos_omega
q0=q1=q2=0
#The following loop calcs can be done sample-by-sample to spread CPU load if required, much like a filter.
for i in range(numSamples):
q0 = coeff * q1 - q2 + data[i]
q2 = q1
q1 = q0
real = (q1 - q2 * cos_omega) / scalingFactor
imag = (q2 * sin_omega) / scalingFactor
magnitude = math.sqrt(real*real + imag*imag)
return magnitude