Select Git revision
Classifier.cpp
1-BBP_detection.py 4.68 KiB
# -*- coding: utf-8 -*-
"""
Created on Sun Dec 24 10:41:58 2022
@author: Loïc
title: detection of BBP in audios
"""
#%% Packages importations
print("\rImportation of packages...", end="\r")
import os
from datetime import datetime
import numpy as np
import pandas as pd
from librosa import load
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from scipy.signal import find_peaks, correlate
from scipy.stats import linregress
print("Importation of packages done!")
#%% Parameters
# Paths
print("\rSetting up parameters...", end="\r")
audio_f = "./../Audio_data" # Path to recordings
csv_f = "./../CSV_data" # Path to data in csv
save_f = "./Results" # Path to results
# For functions
sr = 512000 # sample rate of the recordings
cut_low = 50000 # frequency cut in highpass
num_order = 1 # order of the highpass filter
sound_thresh = 1e-5 # arbitrary threshold used for noise detection
click_size = 100 # mean size of a click (observations) for rolling average
max_length = 500 # maximum length to consider a sound as a click
nfft = 8192 # it is high to estimate freq precisely (we dont need good time location)
hop_length = nfft//2 # if needed, reduce hop_length to be more precise in time
flip = 60 # if there are two many BBPs selected, uses more strict criteria
# soft criteria, we will have false positives but at least we detect all BBPs
mini_space = click_size*5 # minimal space between two clicks (avoids echoes)
ICI_space = int(0.020*sr) # maximal space between two clicks to be a BBP
nb_mini_clicks = 15 # minimal number of clicks to be a BBP
d_amp = 0.1 # max difference of amplitude between clicks of a BBP
irregularity = 2 # limit for irregularity in a BBP (the closer to 1, the better)
mean_nrg = 0.1 # max mean energy for clicks in BBP
print("Parameters ready to use!")
#%% Data
print("\rImportation of csv data", end="\r")
from BBPUtils import get_csv, butter_pass_filter, TeagerKaiser_operator, OLDget_BBPs
data_20_21, audio_paths = get_csv(csv_f, slash="/")
print("Importation of csv data complete!")
#%%## Detection of clicks in environnement #####
print("\nMain execution: Looking for clicks in recordings.")
BBP_all = np.empty((0,3)) # [idx file, sample position, idx BBP in file]
for file in range(len(audio_paths)):
print(f"\r\tExecution for file {file+1} on {len(audio_paths)}", end='\r')
# load signal
signal = load(os.path.join(audio_f, audio_paths[file][4:8], audio_paths[file]),
sr=None)[0]
signal_high = butter_pass_filter(signal, cut_low, sr,
num_order, mode='high')
tk_signal = np.abs(TeagerKaiser_operator(signal_high))
# load or find clicks
signal_peaks = find_peaks(tk_signal, prominence=sound_thresh, distance=mini_space,
width=[0,max_length])[0]
# security
if len(signal_peaks)==0:
# create empty list to avoid errors
signal_peaks = np.array([0])
# Compute ICI
peaks_selection = OLDget_BBPs(signal_peaks, ICI_space, nb_mini_clicks)
# security
if len(peaks_selection) > flip:
peaks_selection = OLDget_BBPs(signal_peaks, int(ICI_space/2), nb_mini_clicks)
# Apply selection criteria
d_amp_selection = np.array([np.mean(np.abs(tk_signal[selection[1:]]-tk_signal[selection[:-1]]))<d_amp
for selection in peaks_selection])
regularity = np.array([np.mean(np.abs(selection[1:]-selection[:-1])[1:]/np.abs(selection[1:]-selection[:-1])[:-1])<irregularity
for selection in peaks_selection])
nrg = np.array([np.mean(tk_signal[selection])< mean_nrg for selection in peaks_selection])
keeping = np.where(np.logical_and(d_amp_selection, regularity, nrg))[0]
# just to be sure, if linreg is negative then it is prbly a false positive (a click and its echoes (diminishing in amplitude))
linreg = np.array([linregress(tk_signal[selection],selection)[2]
for selection in peaks_selection])[keeping]
lengths = np.array([len(selection) for selection in peaks_selection])[keeping]
keeping = keeping[np.logical_or((linreg > -0.5),(lengths > 2*nb_mini_clicks))]
# save results
for i in keeping:
curr_BBP = np.append(peaks_selection[i][...,np.newaxis],
np.array([i]*len(peaks_selection[i]))[...,np.newaxis],
axis=1)
curr_BBP = np.append(np.array([file]*len(peaks_selection[i]))[...,np.newaxis],
curr_BBP, axis=1)
BBP_all = np.append(BBP_all, curr_BBP, axis=0)
np.save(os.path.join(save_f, datetime.now().strftime("%d-%m-%y_%Hh%M") + "_BBP_all.npy"),
BBP_all)