Avik GhoshMario De Los Santos
Published

Correlations in Animal Movement and Communication (CAMC)

CAMC will build a large dataset for Machine Learning specialists to find possible correlations between animal speech and movement.

IntermediateShowcase (no instructions)140
Correlations in Animal Movement and Communication (CAMC)

Things used in this project

Hardware components

Radxa Zero
This was the SBC that was used to work on the project. Generally, any SBC will work! Radxa seems to have some of the best support among Raspberry Pi Competitors. An RPi would be recommended but acquiring a new one nowadays is difficult. Also, because this project is a proof of concept, keeping GPIO pins would be suggested for future versions that can be expanded to carry more sensor data.
×1
Samson Go Mic
Any microphone can be used! This was simply the microphone I had at home. USB-A microphones are recommended because of the necessary USB-C to A hub that will be used.
×1
Micro HDMI to HDMI cable
×1
A Monitor
Any monitor can be used for the initial setup. If not possible, borrowing a monitor would be perfectly fine because, after the setup, the project can be worked on remotely.
×1
USB C Hub
There is only one USB C port on the Radxa Zero apart from power. Using a USB C hub allows the user to utilize a keyboard and mouse.
×1
Seeed Studio PCB Board From Seeed Fusion
×1

Software apps and online services

Debian Buster
balena Etcher
IotFlows

Story

Read more

Schematics

PCB Board with Microphones

This would be attached to the Radxa Zero to allow the user to record audio, in place of a USB Microphone. Thanks again to Mario De Los Santos for helping me create it!

Code

Audio Processing File

Python
The project is entirely contained in this file. Installing the modules and adding the directory system ensures this program should run on its own. Look into the bash system to run the program in the background; the first StackOverFlow answer should be enough!
#!/usr/bin/env python3
# getting ThinkDSP module for Digital Signal Processing
import os

if not os.path.exists('thinkdsp.py'):
    os.system(
        "wget 'https://github.com/AllenDowney/ThinkDSP/raw/master/code/thinkdsp.py'")

# import modules and methods needed
import sounddevice as sd  # allows users to record from microphones
from scipy.io.wavfile import write  # allows users to write out a .wav file
# allows users to run multiple functions at once
from multiprocessing import Process
import time  # allows users to store time data with the recording
import thinkdsp  # allows users to run the DSP section of the code
import numpy as np  # allows users to run rapid calculations
import subprocess  # allows users to run shell commands
import geocoder  # allows users to find their GPS coordinates

# global variables
AudioRec = 0
fileNum = 0

# setup recording
duration = 0.1
fs = 44100
sd.default.samplerate = fs
sd.default.channels = 2

'''
This function will actually record the last 0.1 seconds and save it as a .wav file. 
It's numbered progressively. In most cases, the recording would not be saved. 
'''


def recording():
    global duration
    global fs
    global fileNum

    myRec = sd.rec(int(duration * fs), dtype=np.int16)
    sd.wait()

    write("wav_files/recording" + str(fileNum) + ".wav",
          sd.default.samplerate, myRec.astype(np.int16))


'''
This function will check the recording that was saved by recording(). This function
will call storeRecording() if the recording passes the minimum amplitude threshold.
'''


def checkRecording():
    global fileNum

    # reading the actual saved by recording()
    rec = thinkdsp.read_wave("wav_files/recording" + str(fileNum - 1) + ".wav")

    # instantly delete it because it isn't needed after the data is stored in rec
    rm = "rm wav_files/recording" + str(fileNum - 1) + ".wav"
    subprocess.call(rm, shell=True)

    # implementation of the low pass filter on the absolute value of the samples
    ys_copy = np.abs(rec.ys)
    for i in np.argwhere(ys_copy < 0.2):
        ys_copy[i] = 0.000001

    # taking the average amplitude of only the values that are above the threshold
    cond = ys_copy > 0.000001
    extracted = np.extract(cond, ys_copy)
    score = np.sum(extracted) / extracted.size

    # minimum average amplitude before the program will store the 7 seconds of recording/data
    if score > 0.6:
        print("Score passed!")
        storeRecording()


'''
Function that's called by checkRecording() if the program determines some loud sound 
has been heard. This stores the GPS data, the time data, and the data necessary to 
actually restore the .wav files. 
'''


def storeRecording():
    print("\nStoring right now!\n")
    global AudioRec
    global fileNum

    # This is the system to have a saved system to access the number for the audio file
    # the text file will be constantly updated and saved in order to make the program
    # not have overlapping file names after the program is paused.
    f = open("sampleNumber.txt", "r")
    if f.mode == 'r':
        contents = f.read()
    sampleNum = int(contents)
    f.close()

    # list where GPS data will be saved
    GPS_data = []
    g = geocoder.ip('me')

    # stores the initial coordinates based on ip address of device
    GPS_data.append(g.latlng)

    time_data = time.localtime()
    current_time = time.strftime("%H:%M:%S", time_data)

    duration = 7
    my_rec = sd.rec(int(duration * fs), dtype=np.int16)
    sd.wait()  # waits until the recording is complete before moving on

    # stores the final coordinates after the recording
    GPS_data.append(g.latlng)

    # writing out the .wav file makes the saving a much simpler process
    write("sample" + str(sampleNum) + ".wav", fs, my_rec)

    # create the file that would store the data
    create_file = "touch text_files/file" + str(sampleNum) + ".txt"
    subprocess.call(create_file, shell=True)

    audio = thinkdsp.read_wave("sample" + str(sampleNum) + ".wav")
    ys = ""  # string that will contain all the samples in the audio recording
    ts = ""  # string that will contain all the time stamps for the samples in ys

    for i in audio.ys:
        ys += str(i) + ", "
    for i in audio.ts:
        ts += str(i) + ", "

    txt = open("saved_folder/file" + str(sampleNum) + ".txt", "w")

    # final GPS data that will be stored in the .txt file
    g = geocoder.ip('me')
    GPS_data.append(g.latlng)

    # write all the data into the file
    n = txt.write(str(ys) + "\n" + str(ts) + "\n" +
                  str(GPS_data) + "\n" + str(time_data) + "\n")
    txt.close()

    delete_old = "rm sample" + str(sampleNum) + ".wav"
    subprocess.call(delete_old, shell=True)

    print("\nRecording stored\n")
    print(sampleNum)

    # increment the sample number for the next time the recording data will be stored
    f = open("sampleNumber.txt", "w")
    f.write(str(sampleNum + 1))
    f.close()
    subprocess.call("clear", shell=True)


# THis is the first recording. This allows the first call of checkRecording() to not
# return errors from the lack of an audio file to analyze
recording()
fileNum += 1

# clears the shell so the program looks nicer
subprocess.call("clear", shell=True)


'''
The below lines are a core part of the project. Multiprocessing is a module
that allows users to run multiple functions at the same time. As the board records
the next 0.1 seconds, checkRecording() runs - allowing the board to analyze the last 0.1 
seconds of recording. If you think on the topic a little more, you could realize that 
this means there should be almost no time in which the recording is not analyzed - almost
immediately after it has been recording. Because realtime audio processing must be extremely fast 
(and Python not being known for its speed exactly), this allows for a much simpler program
that has much less need to be optimized. 
'''
while (True):
    if __name__ == '__main__':
        p1 = Process(target=recording)
        p2 = Process(target=checkRecording)
        p1.start()
        p2.start()

        p1.join()
        p2.join()
        fileNum += 1  # the fileNum is increased because the next recording needs a new name

Credits

Avik Ghosh

Avik Ghosh

1 project • 1 follower
Mario De Los Santos

Mario De Los Santos

4 projects • 14 followers
Having fun with electronics and programming. Seeed CC

Comments