def rakeOneForcingFilters(self, sources, interferers, R_n, epsilon=5e-3): ''' Compute the time-domain filters of a beamformer with unit response towards multiple sources. ''' dist_mat = distance(self.R, sources.images) s_time = dist_mat / constants.get('c') s_dmp = 1./(4*np.pi*dist_mat) dist_mat = distance(self.R, interferers.images) i_time = dist_mat / constants.get('c') i_dmp = 1./(4*np.pi*dist_mat) # compute offset needed for decay of sinc by epsilon offset = np.maximum(s_dmp.max(), i_dmp.max())/(np.pi*self.Fs*epsilon) t_min = np.minimum(s_time.min(), i_time.min()) t_max = np.maximum(s_time.max(), i_time.max()) # adjust timing s_time -= t_min - offset i_time -= t_min - offset Lh = np.ceil((t_max - t_min + 2*offset)*float(self.Fs)) # the channel matrix K = sources.images.shape[1] Lg = self.Lg off = (Lg - Lh)/2 L = self.Lg + Lh - 1 H = np.zeros((Lg*self.M, 2*L)) As = np.zeros((Lg*self.M, K)) for r in np.arange(self.M): # build constraint matrix hs = u.lowPassDirac(s_time[r,:,np.newaxis], s_dmp[r,:,np.newaxis], self.Fs, Lh)[:,::-1] As[r*Lg+off:r*Lg+Lh+off,:] = hs.T # build interferer RIR matrix hx = u.lowPassDirac(s_time[r,:,np.newaxis], s_dmp[r,:,np.newaxis], self.Fs, Lh).sum(axis=0) H[r*Lg:(r+1)*Lg,:L] = u.convmtx(hx, Lg).T # build interferer RIR matrix hq = u.lowPassDirac(i_time[r,:,np.newaxis], i_dmp[r,:,np.newaxis], self.Fs, Lh).sum(axis=0) H[r*Lg:(r+1)*Lg,L:] = u.convmtx(hq, Lg).T ones = np.ones((K,1)) # We first assume the sample are uncorrelated K_x = np.dot(H[:,:L], H[:,:L].T) K_nq = np.dot(H[:,L:], H[:,L:].T) + R_n # Compute the TD filters K_nq_inv = np.linalg.inv(K_x+K_nq) C = np.dot(K_nq_inv, As) B = np.linalg.inv(np.dot(As.T, C)) g_val = np.dot(C, np.dot(B, ones)) self.filters = g_val.reshape((self.M,Lg)) # compute and return SNR A = np.dot(g_val.T, H[:,:L]) num = np.dot(A, A.T) denom = np.dot(np.dot(g_val.T, K_nq), g_val) return num/denom
def buildRIRMatrix(mics, sources, Lg, Fs, epsilon=5e-3, unit_damping=False): """ A function to build the channel matrix for many sources and microphones mics is a dim-by-M ndarray where each column is the position of a microphone sources is a list of SoundSource objects Lg is the length of the beamforming filters Fs is the sampling frequency epsilon determines how long the sinc is let to decay. Defaults to epsilon=5e-3 unit_damping determines if the wall damping parameters are used or not. Default to false. returns the RIR matrix H = -------------------- | H_{11} H_{12} ... | ... | -------------------- where H_{ij} is channel matrix between microphone i and source j. H is of type (M*Lg)x((Lg+Lh-1)*S) where Lh is the channel length (determined by epsilon), and M, S are the number of microphones, sources, respectively. """ from beamforming import distance from utilities import lowPassDirac, convmtx from scipy.linalg import toeplitz # set the boundaries of RIR filter for given epsilon d_min = np.inf d_max = 0.0 dmp_max = 0.0 for s in xrange(len(sources)): dist_mat = distance(mics, sources[s].images) if unit_damping == True: dmp_max = np.maximum((1.0 / (4 * np.pi * dist_mat)).max(), dmp_max) else: dmp_max = np.maximum((sources[s].damping[np.newaxis, :] / (4 * np.pi * dist_mat)).max(), dmp_max) d_min = np.minimum(dist_mat.min(), d_min) d_max = np.maximum(dist_mat.max(), d_max) t_max = d_max / constants.get("c") t_min = d_min / constants.get("c") offset = dmp_max / (np.pi * Fs * epsilon) # RIR length Lh = int((t_max - t_min + 2 * offset) * float(Fs)) # build the channel matrix L = Lg + Lh - 1 H = np.zeros((Lg * mics.shape[1], len(sources) * L)) for s in xrange(len(sources)): for r in np.arange(mics.shape[1]): dist = sources[s].distance(mics[:, r]) time = dist / constants.get("c") - t_min + offset if unit_damping == True: dmp = 1.0 / (4 * np.pi * dist) else: dmp = sources[s].damping / (4 * np.pi * dist) h = lowPassDirac(time[:, np.newaxis], dmp[:, np.newaxis], Fs, Lh).sum(axis=0) H[r * Lg : (r + 1) * Lg, s * L : (s + 1) * L] = convmtx(h, Lg).T return H
def buildRIRMatrix(mics, sources, Lg, Fs, epsilon=5e-3, unit_damping=False): ''' A function to build the channel matrix for many sources and microphones mics is a dim-by-M ndarray where each column is the position of a microphone sources is a list of SoundSource objects Lg is the length of the beamforming filters Fs is the sampling frequency epsilon determines how long the sinc is let to decay. Defaults to epsilon=5e-3 unit_damping determines if the wall damping parameters are used or not. Default to false. returns the RIR matrix H = -------------------- | H_{11} H_{12} ... | ... | -------------------- where H_{ij} is channel matrix between microphone i and source j. H is of type (M*Lg)x((Lg+Lh-1)*S) where Lh is the channel length (determined by epsilon), and M, S are the number of microphones, sources, respectively. ''' from beamforming import distance from utilities import lowPassDirac, convmtx from scipy.linalg import toeplitz # set the boundaries of RIR filter for given epsilon d_min = np.inf d_max = 0. dmp_max = 0. for s in xrange(len(sources)): dist_mat = distance(mics, sources[s].images) if unit_damping == True: dmp_max = np.maximum((1. / (4 * np.pi * dist_mat)).max(), dmp_max) else: dmp_max = np.maximum((sources[s].damping[np.newaxis, :] / (4 * np.pi * dist_mat)).max(), dmp_max) d_min = np.minimum(dist_mat.min(), d_min) d_max = np.maximum(dist_mat.max(), d_max) t_max = d_max / constants.get('c') t_min = d_min / constants.get('c') offset = dmp_max / (np.pi * Fs * epsilon) # RIR length Lh = int((t_max - t_min + 2 * offset) * float(Fs)) # build the channel matrix L = Lg + Lh - 1 H = np.zeros((Lg * mics.shape[1], len(sources) * L)) for s in xrange(len(sources)): for r in np.arange(mics.shape[1]): dist = sources[s].distance(mics[:, r]) time = dist / constants.get('c') - t_min + offset if unit_damping == True: dmp = 1. / (4 * np.pi * dist) else: dmp = sources[s].damping / (4 * np.pi * dist) h = lowPassDirac(time[:, np.newaxis], dmp[:, np.newaxis], Fs, Lh).sum(axis=0) H[r * Lg:(r + 1) * Lg, s * L:(s + 1) * L] = convmtx(h, Lg).T return H