""" This python script is used for direction detection. We design the direction detection for 3 wav files types which has 4, 6 and 8 channels. """ import os import numpy as np from scipy.io import wavfile from scipy.signal import butter, lfilter, freqz from scipy import signal import matplotlib import matplotlib.pyplot as plt offsetVector = [] """ The funtion butter_highpass, butter_highpass_filter and calculateResidues are shared Function offset is used for getAngle_for_eight """ def butter_highpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = signal.butter(order, normal_cutoff, btype='high', analog=False) return b, a def butter_highpass_filter(data, cutoff, fs, order=5): b, a = butter_highpass(cutoff, fs, order=order) y = signal.filtfilt(b, a, data) return y def calculateResidues(Chan1, Chan2, fs): S1 = butter_highpass_filter(Chan1, 100, fs, 7) S2 = butter_highpass_filter(Chan2, 100, fs, 7) index1 = -1 index2 = -1 index = -1 for i in range(len(S1)): if S1[i] > 0.03: index1 = i break for i in range(len(S2)): if S2[i] > 0.03: index2 = i break if (index1 < index2): index = index1 else: index = index2 residues = np.mean(np.square(S1[index:index + 401] - S2[index:index + 401])) # offsetVector.append( index1 ) return residues def do_iac(signal, pairs, fs): # signal = data / 32767 residuesVector = [] for offset in [5, -5]: # Computer overall cancellation error for this angle iterator = 0 residues = 0 for mic1, mic2 in pairs: Chan1 = signal[:, mic1] Chan2 = signal[:, mic2] S1 = Chan1 # butter_highpass_filter(Chan1 , 100 , fs , 7) S2 = Chan2 # butter_highpass_filter(Chan2 , 100 , fs , 7) index = -1 for i in range(len(S1)): if (S1[i] > 0.003 and i > 40): index = i break if (iterator == 0 or iterator == 4): a = S1[index - 15:index + 15] b = S2[index - 15:index + 15] residues += np.square(np.subtract(a, b)) elif (iterator == 1 or iterator == 3): a = S1[index - 15 + offset // 2:index + 15 + offset // 2] b = S2[index - 15:index + 15] residues += np.square(np.subtract(a, b)) elif (iterator == 2): a = S1[index - 15 + offset:index + 15 + offset] b = S2[index - 15:index + 15] residues += np.square(np.subtract(a, b)) elif (iterator == 5 or iterator == 7): a = S1[index - 15 - offset // 2:index + 15 - offset // 2] b = S2[index - 15:index + 15] residues += np.square(np.subtract(a, b)) elif (iterator == 6): a = S1[index - 15 - offset:index + 15 - offset] b = S2[index - 15:index + 15] residues += np.square(np.subtract(a, b)) iterator += 1 residuesVector.append(np.mean(residues)) return residuesVector[0] < residuesVector[1] def calculateResidues_eight(Chan1, Chan2, fs): S1 = Chan1 # butter_highpass_filter(Chan1 , 100 , fs , 7 ) S2 = Chan2 # butter_highpass_filter(Chan2 , 100 , fs , 7 ) index1 = -1 index2 = -1 index = -1 for i in range(len(S1)): if S1[i] > 0.01: index1 = i break for i in range(len(S2)): if S2[i] > 0.01: index2 = i break if (index1 < index2): index = index1 else: index = index2 residues = np.mean(np.square(S1[index:index + 401] - S2[index:index + 401])) return residues def getAngle_for_eight(data, fs): signal = data / 32767 for i in range(8): column = butter_highpass_filter(signal[:, i], 100, fs, 7) signal[:, i] = column pairs = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 0)] smallestResidues = 100 closestPair = (0, 0) offsetIndex = -1 for iter in range(8): chan1 = signal[:, pairs[iter][0]] chan2 = signal[:, pairs[iter][1]] residues = calculateResidues_eight(chan1, chan2, fs) if (residues < smallestResidues): smallestResidues = residues closestPair = (pairs[iter]) offsetIndex = iter if do_iac(signal, pairs, fs) == True: d1 = abs(offsetIndex - 4) d2 = abs((offsetIndex + 4) % 8 - 4) if (d1 < d2): pass else: closestPair = pairs[(offsetIndex + 4) % 8] mics = (closestPair[0] + 1, closestPair[1] + 1) return mics def getAngle_for_six(data, fs): signal = data / 32767 pairs = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)] smallestResidues = 100 closestPair = (0, 0) offsetIndex = -1 for iter in range(6): chan1 = signal[:, pairs[iter][0]] chan2 = signal[:, pairs[iter][1]] residues = calculateResidues(chan1, chan2, fs) if (residues < smallestResidues): smallestResidues = residues closestPair = (pairs[iter]) offsetIndex = iter """ if (offsetVector[offsetIndex] > offsetVector[(offsetIndex+3)%6] ): closestPair = pairs[(offsetIndex+3)%6] """ mics = (closestPair[0] + 1, closestPair[1] + 1) # print(offsetVector) return mics def getAngle_for_four(data, fs): signal = data / 32767 pairs = [(0, 1), (1, 2), (2, 3), (3, 0)] smallestResidues = 100 closestPair = (0, 0) offsetIndex = -1 for iter in range(4): chan1 = signal[:, pairs[iter][0]] chan2 = signal[:, pairs[iter][1]] residues = calculateResidues(chan1, chan2, fs) if (residues < smallestResidues): smallestResidues = residues closestPair = (pairs[iter]) offsetIndex = iter """ if (offsetVector[offsetIndex] > offsetVector[(offsetIndex+3)%6] ): closestPair = pairs[(offsetIndex+3)%6] """ mics = (closestPair[0] + 1, closestPair[1] + 1) # print(offsetVector) return mics def getDirection_Pair(closestPair, num_chan): """ :param closestPair: two closet pair, such as (0,1) :param num_chan: channel numbers, such as 8 :return: in above parameters, should be [7 0 1 2] """ pairs = [0, 0, 0, 0] pairs[1] = closestPair[0] - 1 pairs[2] = closestPair[1] - 1 pairs[0] = (pairs[1] - int(num_chan/2)) % num_chan pairs[3] = (pairs[2] + int(num_chan/2)) % num_chan return pairs