Detecting a beep with ESP32/micropython

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
happyday
Posts: 14
Joined: Sat Jan 21, 2017 12:11 pm

Detecting a beep with ESP32/micropython

Post by happyday » Sat Nov 23, 2019 12:04 pm

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.

User avatar
Kip
Posts: 31
Joined: Sat Dec 26, 2015 7:23 am

Re: Detecting a beep with ESP32/micropython

Post by Kip » Sat Nov 23, 2019 12:11 pm

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


User avatar
Kip
Posts: 31
Joined: Sat Dec 26, 2015 7:23 am

Re: Detecting a beep with ESP32/micropython

Post by Kip » Sat Nov 23, 2019 12:17 pm

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



User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Detecting a beep with ESP32/micropython

Post by pythoncoder » Sat Nov 23, 2019 6:33 pm

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.
Peter Hinch
Index to my micropython libraries.

Planet9
Posts: 7
Joined: Tue Nov 12, 2019 7:10 pm

Re: Detecting a beep with ESP32/micropython

Post by Planet9 » Sat Nov 23, 2019 9:11 pm

The Goertzel algorithm is quite efficient when searching for a single tone.
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


Post Reply