1

I'm doing a project that requires a sound sensor detecting a specific frequency range and triggering a buzzer/alarm. Currently, this is what I have for the sound sensor and buzzer

import RPi.GPIO as GPIO
import time

channel = 8
Buzzer = 11

GPIO.setmode(GPIO.BOARD)
GPIO.setup(channel, GPIO.IN)
GPIO.setup(Buzzer, GPIO.IN)
GPIO.setup(Buzzer, GPIO.OUT)

def on():
    GPIO.output(Buzzer, GPIO.LOW)

def off():
    GPIO.output(Buzzer, GPIO.HIGH)

def beep(x):
    on()
    time.sleep(x)
    off()
    time.sleep(x)

def loop():
    while True:
        beep(0.5)

def callback(channel):
    if GPIO.input(channel):

        print ("Sound Detected")
        GPIO.output(Buzzer, True)
        loop()

GPIO.add_event_detect(channel, GPIO.BOTH, bouncetime=300)
GPIO.add_event_callback(channel, callback)

while True:
    time.sleep(1)

def destroy():
    GPIO.output(Buzzer, GPIO.LOW)
    GPIO.output(Buzzer, GPIO.HIGH)
    beep(x)
    GPIO.cleanup()

if __name__ == '__main__':
    setup()
    try:
        loop()
    except KeyboardInterrupt:
        destroy()

Any suggestions would be a great help.

  • Could you identify the problem you are having or where you are stuck? This will allow someone to help you. If you are looking for code review I think that codereview.se may be more helpful. – crasic Oct 27 '17 at 5:34
  • How are you going to measure the frequency? Does your sound sensor return the frequency? – joan Oct 27 '17 at 10:40
  • @joan Hi Joan, I have a USB microphone. Can it be used to measure the frequency? No, my sound sensor only detects sound currently. – Justica Oct 27 '17 at 11:14
  • @crasic Hi, I'm sorry, am new to this.. I'm looking for a solution to detect a specific range of frequency which would trigger the buzzer. – Justica Oct 27 '17 at 11:14
2

Detecting Frequency is actually a very non-trivial thing to do.

I will describe two basic approaches, but there are others

  • Record an analog microphone signal and use Fourier Transform or other algorithm to extract the frequencies (Buffered Approach)
  • Use a sensor, or emulate that sensor in software to convert a sound signal (phase) to a frequency signal (Frequency Counter Approach)

I will only give descriptions and prototypes, because this is a very broad question, if there is something specific you would like me to elaborate, please feel free to leave a comment.


Buffered Approach

Use Libraries pyaudio to capture and record audio stream data into a file. You can do this, for example, every second or every 200 milli-seconds, whatever makes sense for you.

Use numpy, specifically numpy.fft to extract frequency measurements from the audio stream data.

The result of an fft is an array of frequency bins, that is the relative "power" of that frequency in your audio sample.

enter image description here

There are a few caveats, it is easy to feed an array into numpy.fft , it is a little harder to extract the result. You will have to use dimensional analysis to convert the numerical result into frequency bins in Hertz


Real Time Approach

Typically you would use some kind of sensor, which has dedicated electronics, to convert the sound into a frequency measurement.

These devices are known as "frequency counters", the fanciest of which can cost thousands of dollars and look like this.

enter image description here

We can implement a simple frequency counter on the raspberry pi, by using a phase counter.

Prototype of a simple (synchronous) counter

TICK_TIME = 1us
while (true)
   if zero_crossing
      # Extra divide by two because half-phase
      last_frequency = 1/( 2*(counter*TICK_TIME) )
      counter = 0
   else
      counter = counter+1
   sleep (TICK_TIME) 

Now, what this is doing is checking the value of the analog signal from an audio sensor, or, even simpler, an audio sensor that is filtered to produce 1 when the signal is above 0 and 0 when it the signal "flips".

We add up the number of times we see positive signal, when the signal flips we have an estimate of the wavelength (/2) and therefore we can estimate the frequency. Then we count the number of "negative" signals, so on and so forth

You can average these frequency measurements over some period of time to get a "cleaner" more stable signal

A good way to get this zero crossing signal is to use a type of comparator called a Schmitt Trigger.

enter image description here


An improvement on this approach is to use this input as an "interrupt" for the cpu.

Instead of checking every micro-second we can use the fact that the signal changes to issue an interrupt, and use the hardware to measure the time between interrupts.

Prototype Event Handler

last_time = time.time()
ff_interrupt_handler():
  current_time = time.time()
  dt = current_time - last_time
  last_frequency = 1/(2*dt)
  last_time = current_time 
  • Thank you for the answer. I am able to record an audio using the USB microphone and then convert it to a set of frequencies using FFT. However, I am unsure of how to combine that set of code with the one I posted above. To explain my project again, I would like my sound sensor to capture a specific frequency range between 300-400Hz. And then send a signal to trigger the buzzer. I am also unsure if I need to use a USB mic to capture the sound. – Justica Oct 30 '17 at 2:19
1

Break the problem down into parts. Google each part. Combine them to make your project.

First, you need to work out how to get sound from the microphone into Python. I found Python-SoundDevice and I'm sure there are many others.

Now you have a recording. Next, you need to convert this to a set of frequencies. The things you want to look for are (Fast) Fourier Transforms or maybe Discrete Cosine Transforms. The maths is quite advanced but you can get away without understanding all of it, probably. I would recommend you research this part quite thoroughly as it's really not simple. At least, I don't know of a simple way to explain it. Again there are many Python implementations - the Numpy one came to hand quickly,

Lastly, you need to decide whether there's enough of the required frequency in your sound. The frequency-domain data will contain many different frequencies. You want to check how loud your desired frequency is compared to the background noise, and use that to control your buzzer.

  • Thank you for your answer. I managed to convert the recording to a set of frequencies. However, I'm not sure how to streamline the code to only detect specific frequency range between 300-400Hz. Upon detecting this frequency, I want to trigger the buzzer. – Justica Oct 30 '17 at 2:22
  • That sounds like a different question. Please post it as a new question, with a minimal, complete, verifiable example of the code you have created. – Mark Smith Oct 30 '17 at 8:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.