void spread_no_pad(fcomplex * data, int numdata, fcomplex * result, int numresult, int numbetween) /* Prepare the data array for correlation by spreading */ /* the input data array. */ /* Arguments: */ /* 'data' is the FFT array to be prepared */ /* 'numdata' is the number of complex points in 'data' */ /* 'result' is the prepped data array */ /* 'numresult' is the number of complex points in 'result' */ /* 'numbetween' is the number of interpolated pts per bin */ { spread_with_pad(data, numdata, result, numresult, numbetween, 0); }
void search_minifft(fcomplex * minifft, int numminifft, double min_orb_p, double max_orb_p, rawbincand * cands, int numcands, int numharmsum, int numbetween, double numfullfft, double timefullfft, double lorfullfft, presto_interptype interptype, presto_checkaliased checkaliased) /* This routine searches a short FFT (usually produced using the */ /* MiniFFT binary search method) and returns a candidte vector */ /* containing information about the best binary candidates found. */ /* The routine uses either interbinning or interpolation as well */ /* as harmonic summing during the search. */ /* Arguments: */ /* 'minifft' is the FFT to search (complex valued) */ /* 'numminifft' is the number of complex points in 'minifft' */ /* 'min_orb_p' is the minimum orbital period (s) to search */ /* 'max_orb_p' is the maximum orbital period (s) to search */ /* 'cands' is a pre-allocated vector of rawbincand type in which */ /* the sorted (in decreasing sigma) candidates are returned */ /* 'numcands' is the length of the 'cands' vector */ /* 'numharmsum' the number of harmonics to sum during the search */ /* 'numbetween' the points to interpolate per bin */ /* 'numfullfft' the number of points in the original long FFT */ /* 'timefullfft' the duration of the original time series (s) */ /* 'lorfullfft' the 1st bin of the long FFT that was miniFFT'd */ /* 'interptype' is either INTERBIN or INTERPOLATE. */ /* INTERBIN = (interbinning) is fast but less sensitive. */ /* NOTE: INTERBINNING is conducted by this routine! */ /* INTERPOLATE = (Fourier interpolation) is slower but more */ /* sensitive. */ /* NOTE: The interpolation is assumed to ALREADY have been */ /* completed by the calling function! The easiest */ /* way is by zero-padding to 2*numminifft and FFTing. */ /* If you use this method, make sure numminifft is the*/ /* original length rather than the interpolated */ /* length and also make sure numbetween is correct. */ /* 'checkaliased' is either CHECK_ALIASED or NO_CHECK_ALIASED. */ /* NO_CHECK_ALIASED = harmonic summing does not include */ /* aliased freqs making it faster but less sensitive. */ /* CHECK_ALIASED = harmonic summing includes aliased freqs */ /* making it slower but more sensitive. */ { int ii, jj, fftlen, offset, numtosearch = 0, lobin, hibin, numspread = 0; float powargr, powargi, *fullpows = NULL, *sumpows; double twobypi, minpow, minsig, dr, numindep; fcomplex *spread; /* Override the value of numbetween if interbinning */ if (interptype == INTERBIN) numbetween = 2; /* Prep some other values we will need */ dr = 1.0 / (double) numbetween; twobypi = 2.0 / PI; fftlen = numminifft * numbetween; for (ii = 0; ii < numcands; ii++) { cands[ii].mini_sigma = 0.0; cands[ii].mini_power = 0.0; } lobin = ceil(2 * numminifft * min_orb_p / timefullfft); if (lobin <= 0) lobin = 1; hibin = floor(2 * numminifft * max_orb_p / timefullfft); if (hibin >= 2 * numminifft) hibin = 2 * numminifft - 1; lobin *= numbetween; hibin *= numbetween; /* Spread and interpolate the fft */ numtosearch = (checkaliased == CHECK_ALIASED) ? 2 * fftlen : fftlen; numspread = numminifft * numbetween + 1; if (interptype == INTERPOLATE) { /* INTERPOLATE */ spread = minifft; } else { /* INTERBIN */ spread = gen_cvect(numspread); spread_with_pad(minifft, numminifft, spread, numspread, numbetween, 0); for (ii = 1; ii < fftlen; ii += 2) { spread[ii].r = twobypi * (spread[ii - 1].r - spread[ii + 1].r); spread[ii].i = twobypi * (spread[ii - 1].i - spread[ii + 1].i); } } spread[0].r = spread[fftlen].r = 1.0; spread[0].i = spread[fftlen].i = 0.0; fullpows = gen_fvect(numtosearch); fullpows[0] = 1.0; if (checkaliased == CHECK_ALIASED) fullpows[fftlen] = 1.0; /* used to be nyquist^2 */ /* The following wraps the data around the Nyquist freq such that */ /* we consider aliased frequencies as well (If CHECK_ALIASED). */ if (checkaliased == CHECK_ALIASED) for (ii = 1, jj = numtosearch - 1; ii < fftlen; ii++, jj--) fullpows[ii] = fullpows[jj] = POWER(spread[ii].r, spread[ii].i); else for (ii = 1; ii < numtosearch; ii++) fullpows[ii] = POWER(spread[ii].r, spread[ii].i); if (interptype == INTERBIN) vect_free(spread); /* Search the raw powers */ numindep = hibin - lobin + 1.0; minpow = power_for_sigma(MINRETURNSIG, 1, numindep); for (ii = lobin; ii < hibin; ii++) { if (fullpows[ii] > minpow) { cands[numcands - 1].mini_r = dr * (double) ii; cands[numcands - 1].mini_power = fullpows[ii]; cands[numcands - 1].mini_numsum = 1.0; cands[numcands - 1].mini_sigma = candidate_sigma(fullpows[ii], 1, numindep); minsig = percolate_rawbincands(cands, numcands); if (cands[numcands - 1].mini_power > minpow) minpow = cands[numcands - 1].mini_power; } } /* If needed, sum and search the harmonics */ if (numharmsum > 1) { sumpows = gen_fvect(numtosearch); memcpy(sumpows, fullpows, sizeof(float) * numtosearch); for (ii = 2; ii <= numharmsum; ii++) { offset = ii / 2; numindep = (hibin - lobin + 1.0) / (double) ii; if (cands[numcands - 1].mini_sigma < MINRETURNSIG) minsig = MINRETURNSIG; else minsig = cands[numcands - 1].mini_sigma; minpow = power_for_sigma(minsig, ii, numindep); for (jj = lobin * ii; jj < hibin; jj++) { sumpows[jj] += fullpows[(jj + offset) / ii]; if (sumpows[jj] > minpow) { cands[numcands - 1].mini_r = (dr * (double) jj) / ii; cands[numcands - 1].mini_power = sumpows[jj]; cands[numcands - 1].mini_numsum = (double) ii; cands[numcands - 1].mini_sigma = candidate_sigma(sumpows[jj], ii, numindep); minsig = percolate_rawbincands(cands, numcands); if (minsig > MINRETURNSIG) minpow = power_for_sigma(minsig, ii, numindep); } } } vect_free(sumpows); } vect_free(fullpows); /* Add the rest of the rawbincand data to the candidate array */ for (ii = 0; ii < numcands; ii++) { cands[ii].full_N = numfullfft; cands[ii].full_T = timefullfft; cands[ii].full_lo_r = lorfullfft; cands[ii].mini_N = 2 * numminifft; /* # of real points */ cands[ii].psr_p = timefullfft / (lorfullfft + numminifft); cands[ii].orb_p = timefullfft * cands[ii].mini_r / cands[ii].mini_N; } }
fftcand *search_fft(fcomplex * fft, int numfft, int lobin, int hibin, int numharmsum, int numbetween, presto_interptype interptype, float norm, float sigmacutoff, int *numcands, float *powavg, float *powvar, float *powmax) /* This routine searches a short FFT of 'numfft' complex freqs */ /* and returns a candidate vector of fftcand structures containing */ /* information about the best candidates found. */ /* The routine uses either interbinning or interpolation as well */ /* as harmonic summing during the search. */ /* The number of candidates returned is either 'numcands' if != 0, */ /* or is determined automatically by 'sigmacutoff' -- which */ /* takes into account the number of bins searched. */ /* The returned vector is sorted in order of decreasing power. */ /* Arguments: */ /* 'fft' is the FFT to search (complex valued) */ /* 'numfft' is the number of complex points in 'fft' */ /* 'lobin' is the lowest Fourier freq to search */ /* 'hibin' is the highest Fourier freq to search */ /* 'numharmsum' the number of harmonics to sum during the search */ /* 'numbetween' the points to interpolate per bin */ /* 'interptype' is either INTERBIN or INTERPOLATE. */ /* INTERBIN = (interbinning) is fast but less sensitive. */ /* NOTE: INTERBINNING is conducted by this routine! */ /* INTERPOLATE = (Fourier interpolation) is slower but more */ /* sensitive. */ /* NOTE: The interpolation is assumed to ALREADY have been */ /* completed by the calling function! The easiest */ /* way is by zero-padding to 2*numfft and FFTing. */ /* If you use this method, make sure numfft is the */ /* original length rather than the interpolated */ /* length and also make sure numbetween is correct. */ /* 'norm' is the normalization constant to multiply each power by */ /* 'sigmacutoff' if the number of candidates will be determined */ /* automatically, is the minimum Gaussian significance of */ /* candidates to keep -- taking into account the number of */ /* bins searched */ /* 'numcands' if !0, is the number of candates to return. */ /* if 0, is a return value giving the number of candidates. */ /* 'powavg' is a return value giving the average power level */ /* 'powvar' is a return value giving the power level variance */ /* 'powmax' is a return value giving the maximum power */ { int ii, jj, offset, numtosearch, dynamic = 0; int numspread = 0, nc = 0, startnc = 10; float powargr, powargi, *fullpows = NULL, *sumpows, ftmp; double twobypi, minpow = 0.0, tmpminsig = 0.0, dr, davg, dvar; fftcand *cands, newcand; fcomplex *spread; /* Override the value of numbetween if interbinning */ if (interptype == INTERBIN) numbetween = 2; norm = 1.0 / norm; *powmax = 0.0; /* Decide if we will manage the number of candidates */ if (*numcands > 0) startnc = *numcands; else { dynamic = 1; minpow = power_for_sigma(sigmacutoff, 1, hibin - lobin); } cands = (fftcand *) malloc(startnc * sizeof(fftcand)); for (ii = 0; ii < startnc; ii++) cands[ii].sig = 0.0; /* Prep some other values we will need */ dr = 1.0 / (double) numbetween; twobypi = 2.0 / PI; numtosearch = numfft * numbetween; /* Spread and interpolate the fft */ numspread = numfft * numbetween + 1; if (interptype == INTERPOLATE) { /* INTERPOLATE */ spread = fft; } else { /* INTERBIN */ spread = gen_cvect(numspread); spread_with_pad(fft, numfft, spread, numspread, numbetween, 0); for (ii = 1; ii < numtosearch; ii += 2) { spread[ii].r = twobypi * (spread[ii - 1].r - spread[ii + 1].r); spread[ii].i = twobypi * (spread[ii - 1].i - spread[ii + 1].i); } } spread[0].r = spread[numtosearch].r = 1.0; spread[0].i = spread[numtosearch].i = 0.0; /* First generate the original powers in order to */ /* calculate the statistics. Yes, this is inefficient... */ fullpows = gen_fvect(numtosearch); for (ii = lobin, jj = 0; ii < hibin; ii++, jj++) { ftmp = POWER(fft[ii].r, fft[ii].i) * norm; fullpows[jj] = ftmp; if (ftmp > *powmax) *powmax = ftmp; } avg_var(fullpows, hibin - lobin, &davg, &dvar); *powavg = davg; *powvar = dvar; fullpows[0] = 1.0; for (ii = 1; ii < numtosearch; ii++) fullpows[ii] = POWER(spread[ii].r, spread[ii].i) * norm; if (interptype == INTERBIN) vect_free(spread); /* Search the raw powers */ for (ii = lobin * numbetween; ii < hibin * numbetween; ii++) { if (fullpows[ii] > minpow) { newcand.r = dr * (double) ii; newcand.p = fullpows[ii]; newcand.sig = candidate_sigma(fullpows[ii], 1, hibin - lobin); newcand.nsum = 1; cands[startnc - 1] = newcand; tmpminsig = percolate_fftcands(cands, startnc); if (dynamic) { nc++; if (nc == startnc) { startnc *= 2; cands = (fftcand *) realloc(cands, startnc * sizeof(fftcand)); for (jj = nc; jj < startnc; jj++) cands[jj].sig = 0.0; } } else { minpow = cands[startnc - 1].p; if (nc < startnc) nc++; } } } /* If needed, sum and search the harmonics */ if (numharmsum > 1) { sumpows = gen_fvect(numtosearch); memcpy(sumpows, fullpows, sizeof(float) * numtosearch); for (ii = 2; ii <= numharmsum; ii++) { offset = ii / 2; if (dynamic) minpow = power_for_sigma(sigmacutoff, ii, hibin - lobin); else minpow = power_for_sigma(tmpminsig, ii, hibin - lobin); for (jj = lobin * numbetween; jj < numtosearch; jj++) { sumpows[jj] += fullpows[(jj + offset) / ii]; if (sumpows[jj] > minpow) { newcand.r = dr * (double) jj; newcand.p = sumpows[jj]; newcand.sig = candidate_sigma(sumpows[jj], ii, hibin - lobin); newcand.nsum = ii; cands[startnc - 1] = newcand; tmpminsig = percolate_fftcands(cands, startnc); if (dynamic) { nc++; if (nc == startnc) { startnc *= 2; cands = (fftcand *) realloc(cands, startnc * sizeof(fftcand)); for (jj = nc; jj < startnc; jj++) cands[jj].sig = 0.0; } } else { minpow = power_for_sigma(tmpminsig, ii, hibin - lobin); if (nc < startnc) nc++; } } } } vect_free(sumpows); } vect_free(fullpows); /* Chop off the unused parts of the dynamic array */ if (dynamic) cands = (fftcand *) realloc(cands, nc * sizeof(fftcand)); *numcands = nc; return cands; }