Wednesday 7 July 2021

Sound activated recording and advanced filtering on Raspberry Pi

I'm making a Raspberry Pi bat detector using a USB-powered ultrasonic microphone. I want to be able to record bats while excluding insects and other non-bat noises. Recording needs to be sound-triggered to avoid filling the SD card too quickly and to aid with analysis. This website explains how to do this with SoX:

rec - c1 -r 192000 record.wav sinc 10k silence 1 0.1 1% trim 0 5

This records for 5 seconds after a trigger sound of at least 0.1 seconds and includes a 10kHz high pass filter. This is a good start, but what I'd really like is an advanced filter that excludes crickets and other non-bat noises. Insect and bat calls overlap in frequency so a high pass or band filter won't do.

The Elekon Batlogger does this with a period trigger that analyses zero crossings. From the Batlogger website:

The difference in sound production of bats (vocal cords) and insects (stridulation) affects the period continuity. The period trigger takes advantage of this: enter image description here

The trigger fires when ProdVal and DivVal are lower than the set limits, so if the values ​​are within the yellow range. (Values mean default values): ProdVal = 8, higher values ​​trigger easier DivVal = 20, higher values ​​trigger easier

Translated text from the image:

Bat: Tonal signal

Period constant => zero crossings / time = stable

Insects: scratching

Period constant => zero crossings / time = differs

MN => mean value of the number of periods per measurement interval

SD => standard deviation of the number of periods

Higher values trigger better even at low frequencies (also insects!) And vice versa

Is there a way to implement this (or something to the same effect) in Raspberry Pi OS? The language I'm most familiar with is R. Based on answers to this question it seems like R would be suitable for this problem, although if R isn't the best choice then I'm open to other suggestions.

I'd really appreciate some working code for recording audio and filtering as described above. My desired output is 5 second files that contain bat calls, not insects or noise. Needs to be efficient in terms of CPU / power use and needs to work on-the-fly.

Example recordings of bats and insects here.


UPDATE:

I've got a basic sound-activated script working in Python (based on this answer) but I'm not sure how to include an advanced filter in this:

import pyaudio
import wave
from array import array
 import time
 
FORMAT=pyaudio.paInt16
CHANNELS=1
RATE=44100
CHUNK=1024
RECORD_SECONDS=5

audio=pyaudio.PyAudio() 

stream=audio.open(format=FORMAT,channels=CHANNELS, 
                  rate=RATE,
                  input=True,
                  frames_per_buffer=CHUNK)

nighttime=True # I will expand this later

while nighttime:
     data=stream.read(CHUNK)
     data_chunk=array('h',data)
     vol=max(data_chunk)
     if(vol>=3000):
         print("recording triggered")
         frames=[]
         for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
             data = stream.read(CHUNK)
             frames.append(data)
         print("recording saved")
         # write to file
         words = ["RECORDING-", time.strftime("%Y%m%d-%H%M%S"), ".wav"]
         FILE_NAME= "".join(words) 
         wavfile=wave.open(FILE_NAME,'wb')
         wavfile.setnchannels(CHANNELS)
         wavfile.setsampwidth(audio.get_sample_size(FORMAT))
         wavfile.setframerate(RATE)
         wavfile.writeframes(b''.join(frames))
         wavfile.close()
     # check if still nighttime
     nighttime=True # I will expand this later
 
 stream.stop_stream()
 stream.close()
 audio.terminate()


from Sound activated recording and advanced filtering on Raspberry Pi

No comments:

Post a Comment