35static unsigned _N = 0;
36static double *siga_loc =
nullptr;
37static double *sigb_loc =
nullptr;
38static double *lags_loc =
nullptr;
39static fftw_complex *ffta =
nullptr;
40static fftw_complex *fftb =
nullptr;
41static fftw_complex *xspec =
nullptr;
42static double *xcorr =
nullptr;
44static fftw_plan pa =
nullptr;
45static fftw_plan pb =
nullptr;
46static fftw_plan px =
nullptr;
55 if (xspec) fftw_free(xspec);
56 if (fftb) fftw_free(fftb);
57 if (ffta) fftw_free(ffta);
59 if (lags_loc) free(lags_loc);
60 if (xcorr) free(xcorr);
61 if (sigb_loc) free(sigb_loc);
62 if (siga_loc) free(siga_loc);
64 xspec =
nullptr; fftb =
nullptr; ffta =
nullptr;
65 lags_loc =
nullptr; xcorr =
nullptr; sigb_loc =
nullptr; siga_loc =
nullptr;
71 siga_loc = calloc(_N,
sizeof(
double));
72 sigb_loc = calloc(_N,
sizeof(
double));
73 xcorr = calloc(_N + 1,
sizeof(
double));
74 lags_loc = calloc(_N,
sizeof(
double));
79 ffta = fftw_alloc_complex(_N);
80 fftb = fftw_alloc_complex(_N);
81 xspec = fftw_alloc_complex(_N);
93 if (pa) fftw_destroy_plan(pa);
94 if (pb) fftw_destroy_plan(pb);
95 if (px) fftw_destroy_plan(px);
96 pa =
nullptr; pb =
nullptr; px =
nullptr;
120 pa = fftw_plan_dft_r2c_1d(_N, siga_loc, ffta, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
121 pb = fftw_plan_dft_r2c_1d(_N, sigb_loc, fftb, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
122 px = fftw_plan_dft_c2r_1d(_N, xspec, xcorr, FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
167static void _fftshift(
const double *in,
double *out,
unsigned N)
170 unsigned half = (unsigned)floor((
double)N / 2.0);
173 memcpy(out, &in[half],
sizeof(
double) * (N - half));
176 memcpy(&out[N - half], in,
sizeof(
double) * half);
188 double *max,
unsigned *maxi)
190 assert(a !=
nullptr);
194 double best_v = a[0];
196 for (
unsigned i = 1; i < N; i++) {
226 unsigned margin,
int weightfunc,
231 static unsigned last_N = 0;
232 static double *hann_win =
nullptr;
233 static double *t_ref =
nullptr;
234 static double *t_sig =
nullptr;
244 hann_win = malloc(N *
sizeof(
double));
245 assert(hann_win !=
nullptr);
248 t_ref = malloc(N *
sizeof(
double));
249 assert(t_ref !=
nullptr);
251 t_sig = malloc(N *
sizeof(
double));
252 assert(t_sig !=
nullptr);
258 for (
unsigned i = 0; i < N; i++) {
259 t_ref[i] = sigs[0][i] * hann_win[i];
263 for (
unsigned i = 0; i < M - 1; i++) {
265 for (
unsigned j = 0; j < N; j++) {
266 t_sig[j] = sigs[i + 1][j] * hann_win[j];
268 outdelays[i] =
MD_get_delay(t_ref, t_sig, N,
nullptr, margin, weightfunc);
291 double *ent,
unsigned margin,
int weightfunc)
296 MD_gcc(siga, sigb, N, lags_loc, weightfunc);
299 unsigned center = (unsigned)ceil((
double)N / 2.0);
306 if (center + m >= N) {
307 m = (N - 1) - center;
311 unsigned start = center - m;
312 unsigned len = 2 * m + 1;
316 _max_index(lags_loc + start, len, &peak_val, &peak_i);
319 if (ent !=
nullptr) {
320 *ent =
MD_entropy(lags_loc + start, len,
true);
324 return (
int)(peak_i) - (
int)(m);
340void MD_gcc(
const double *siga,
const double *sigb,
unsigned N,
341 double *lagvals,
int weightfunc)
346 memcpy(siga_loc, siga, _N *
sizeof(
double));
347 memcpy(sigb_loc, sigb, _N *
sizeof(
double));
366 unsigned num_bins = _N / 2 + 1;
368 switch (weightfunc) {
370 for (
unsigned i = 0; i < num_bins; i++) {
371 double complex cs = fftb[i] * conj(ffta[i]);
373 xspec[i] = cs / (cabs(cs) + DBL_MIN);
378 for (
unsigned i = 0; i < num_bins; i++) {
379 double complex cs = fftb[i] * conj(ffta[i]);
380 xspec[i] = cs / (double)_N;
A mini library of DSP (Digital Signal Processing) routines.
@ PHAT
Phase Transform weighting (sharper peaks, more robust to noise)
void MD_Gen_Hann_Win(double *out, unsigned n)
Generate a Hanning (Hann) window of length n.
double MD_entropy(const double *a, unsigned N, bool clip)
Compute the normalized entropy of a distribution.
static void _xcorr_malloc(void)
Allocate all buffers needed for cross-correlation of length _N.
static void _xcorr_free(void)
Free all dynamically allocated FFT buffers.
static void _fftshift(const double *in, double *out, unsigned N)
Shift an FFT output so that the zero-lag is in the middle.
static void _xcorr_setup(void)
Allocate buffers and create FFTW plans for signals of length _N.
static void _xcorr_teardown(void)
Destroy existing FFTW plans and free all buffers.
static void _gcc_setup(unsigned N)
Ensure the cached FFT setup matches the requested signal length.
void MD_gcc(const double *siga, const double *sigb, unsigned N, double *lagvals, int weightfunc)
Compute the Generalized Cross-Correlation between two signals.
void MD_get_multiple_delays(const double **sigs, unsigned M, unsigned N, unsigned margin, int weightfunc, int *outdelays)
Estimate delays between a reference signal and several other signals.
void md_gcc_teardown(void)
Tear down the GCC-PHAT FFT cache and reset its cached length.
static void _max_index(const double *a, unsigned N, double *max, unsigned *maxi)
Find the index and value of the maximum element in an array.
int MD_get_delay(const double *siga, const double *sigb, unsigned N, double *ent, unsigned margin, int weightfunc)
Estimate the delay (in samples) between two signals.
Internal header for cross-file dependencies within the minidsp module.