diff --git a/gsrp_smart_util.py b/gsrp_smart_util.py index ba9c0a63900f8ee7cb60636472beae5c95d2384a..a5463296616224a3cc9486d43e9b3c0200673f2b 100644 --- a/gsrp_smart_util.py +++ b/gsrp_smart_util.py @@ -90,9 +90,11 @@ def mul(mem1, mem2, cc, t_max, id1, id2, n_ind): # assume len(id2) == 1 idx1, idx2 = np.meshgrid(np.arange(len(mem1[0])), np.arange(len(mem2[0]))) idx1, idx2 = idx1.ravel(), idx2.ravel() - out_tij = np.concatenate((mem1[1][:, idx1], mem2[1][:, idx2]), axis=0) - mask = (np.abs(out_tij[:-1] - out_tij[-1:]) <= t_max).all(0) - out_tij = out_tij[:, mask] + out_tij = np.empty((len(id1) + 1, len(idx1)), mem1[1].dtype) + np.take(mem1[1], idx1, axis=1, out=out_tij[:-1]) + np.take(mem2[1], idx2, axis=1, out=out_tij[-1:]) + mask = reduce_all(np.abs(out_tij[:-1] - out_tij[-1:]) <= t_max) # Faster than numpy for large array + out_tij = np.compress(mask, out_tij, axis=1) idx1, idx2 = idx1[mask], idx2[mask] out_val = mem1[0][idx1] * mem2[0][idx2] tij_dep = out_tij[:-1] - out_tij[-1:] @@ -104,12 +106,19 @@ def mul(mem1, mem2, cc, t_max, id1, id2, n_ind): def mask_val(mem, val): mask = mem[0] >= val - return mem[0][mask], mem[1][:, mask] + return mem[0][mask], np.compress(mask, mem[1], axis=1) + + +def reduce_all(arr): + out = arr[0].copy() + for a in arr[1:]: + out &= a + return out def mask_lim(mem, tij_min, tij_max, t_max): - mask = ((tij_max - t_max <= mem[1]) & (mem[1] <= tij_min + t_max)).all(0) - return mem[0][mask], mem[1][:, mask] + mask = reduce_all((tij_max - t_max <= mem[1]) & (mem[1] <= tij_min + t_max)) # Faster than numpy for large array + return mem[0][mask], np.compress(mask, mem[1], axis=1) def constrained_argmax(mem, cc, tij_ind, curr_tij, used_tij, t_max, n_ind): @@ -134,7 +143,7 @@ def smart_gsrp(cc, n_ind, n_tot, t_max, tree, program, clean_list): if op == 'mem': if i == 0: memory[(0, j)] = mask_val((np.concatenate((cc[op.right, -t_max:], cc[op.right, :t_max + 1])), - np.arange(-t_max, t_max + 1)[np.newaxis]), val) + np.arange(-t_max, t_max + 1, dtype=np.int32)[np.newaxis]), val) else: memory[(i, j)] = mask_val(memory[(op.left, op.right)], val) else: # op == 'mul' @@ -153,7 +162,7 @@ def smart_gsrp(cc, n_ind, n_tot, t_max, tree, program, clean_list): except ValueError: # search of potential maxima ended outside of possible values tij_min, tij_max = memory[(i, j)][1].min(), memory[(i, j)][1].max() for k in range(j): - memory[(i, k)] = mask_lim(memory[(i, k)], tij_min, tij_max, t_max) + memory[(i, k)] = mask_lim(memory[(i, k)], tij_min, tij_max, t_max) # print('tdoa:', tij, 'val:', val, 'mem size:', (lambda x: f'{x} ({100 * x / (n_ind//(i+1)) / (2 * t_max + 1) ** (i+1)}%)')(sum(len(o[0].T) for o in memory.values()))) @@ -161,10 +170,4 @@ def smart_gsrp(cc, n_ind, n_tot, t_max, tree, program, clean_list): for p in clean_list[i]: del memory[p] - return val, tij - - - - - - + return np.log10(val), tij diff --git a/gsrp_tdoa_hyperres.py b/gsrp_tdoa_hyperres.py index 334868d830f540ed06fc7e2c0d4fa16fde2ec923..ff59caf669b567d50091b03ab69acd340e093555 100755 --- a/gsrp_tdoa_hyperres.py +++ b/gsrp_tdoa_hyperres.py @@ -78,10 +78,10 @@ def corr(data, pos, w_size, max_tdoa, decimate=1, mode='prepare', hyper=True): else: raise ValueError(f'Unknown mode {mode}') - tdoas = np.zeros((len(pos), num_channel_pairs + 1), np.float32) + tdoas = np.zeros((len(pos), num_channel_pairs + 2), np.float32) if hyper: # prepare hyper res - tdoas2 = np.zeros((len(pos), num_channel_pairs + 1), np.float32) + tdoas2 = np.zeros((len(pos), num_channel_pairs + 2), np.float32) poly = PolynomialFeatures(2) lin = LinearRegression() pipe = Pipeline([('poly', poly), ('lin', lin)]) @@ -98,8 +98,8 @@ def corr(data, pos, w_size, max_tdoa, decimate=1, mode='prepare', hyper=True): ).named_steps['lin'].coef_ der = np.zeros((num_channels - 1, num_channels - 1)) der[ind] = coef[4:] - poly_min = np.linalg.lstsq(der + der.T, -coef[1:4], rcond=None)[0] + mean - return pipe.predict(poly_min[np.newaxis]).item(), mat @ poly_min + poly_min = np.linalg.lstsq(der + der.T, -coef[1:4], rcond=None)[0] + return np.log10(pipe.predict(poly_min[np.newaxis]).item()), mat @ (poly_min + mean) cc = np.empty((num_channel_pairs, dw_size), np.float32) for i in trange(len(pos)): @@ -109,25 +109,27 @@ def corr(data, pos, w_size, max_tdoa, decimate=1, mode='prepare', hyper=True): fft = np.asarray(fft, dtype=np.complex64) cc[:] = irfft(fft[:, v2] * np.conj(fft[:, v1]), axis=0).T cc -= cc.min(-1, keepdims=True) + maxs = cc.max(1, keepdims=True) + cc /= maxs + maxs = np.log10(maxs.prod()) if mode == 'prepare': - tdoas[i, 0], index = c_corr.c_corr_at(cc, tausf) - tdoas[i, 1:] = ((tausf[:, index] + dw_size // 2) % dw_size) - dw_size // 2 + tdoas[i, :2], index = c_corr.c_corr_at(cc, tausf) + tdoas[i, 2:] = ((tausf[:, index] + dw_size // 2) % dw_size) - dw_size // 2 elif mode == 'on-the-fly': - tdoas[i, 0], tdoas[i, 1:] = c_corr.c_corr_all(cc, cc_size//2, num_channels - 1) + tdoas[i, :2], tdoas[i, 2:] = c_corr.c_corr_all(cc, cc_size//2, num_channels - 1) elif mode == 'smart': - maxs = cc.max(1, keepdims=True) - cc /= maxs - val, tdoas[i, 1:] = smart_gsrp(cc, num_channels - 1, num_channel_pairs, cc_size // 2, + tdoas[i, :2], tdoas[i, 2:] = smart_gsrp(cc, num_channels - 1, num_channel_pairs, cc_size // 2, tree, program, clean_list) - tdoas[i, 0] = np.log10(val * maxs.prod()) - cc *= maxs else: raise ValueError(f'Unknown mode {mode}') + tdoas[i, 1] += maxs if hyper: - tdoas2[i, 0], tdoas2[i, 1:] = _hyperres(tdoas[i, 1:], cc) - + tdoas2[i, :2], tdoas2[i, 2:] = _hyperres(tdoas[i, 2:], cc) + tdoas2[i, 1] += maxs + tdoas[:, :2] *= 20 if hyper: + tdoas2[:, :2] *= 20 return np.hstack((np.expand_dims(pos, -1), tdoas)), np.hstack((np.expand_dims(pos, -1), tdoas2)) else: return np.hstack((np.expand_dims(pos, -1), tdoas)) @@ -219,8 +221,9 @@ if __name__ == "__main__": parser.add_argument('infile', type=str, help='The sound file to process.') parser.add_argument('outfile', type=str, help='The text or npy file to write results to. Each row gives the ' - 'position (in samples), cross-correlation product, the independent ' - 'TDOAs (in samples), and TDOAs derived from the independent ones. ') + 'position (in samples), cross-correlation product in decibel ' + '(normalized and unormalized), the independent TDOAs (in samples), ' + 'and TDOAs derived from the independent ones.') group1 = parser.add_argument_group('Channels') group1.add_argument('-c', '--channels', type=intlist, default=None, @@ -257,7 +260,7 @@ if __name__ == "__main__": group4.add_argument('-e', '--erase', action='store_false', help='Erase existing outfile. If outfile exist and ' '--erase is not provide, the script will exit.') group4.add_argument('-n', '--no-hyperres', action='store_true', help='Disable the hyper resolution evalutation of ' - 'the TDOA') + 'the TDOA') group4.add_argument('-M', '--mode', choices={'prepare', 'on-the-fly', 'smart', 'auto'}, default='smart', help=f'R|How to explore the TDOA space (default: %(default)s).\n' f'{BColors.BOLD}prepare{BColors.ENDC} precomputes all the possible TDOA pairs and then '