int main ( void ) { const char *fn = __func__; //LALStatus status = empty_status; SFTtype *mySFT; LIGOTimeGPS epoch = { 731210229, 0 }; REAL8 dFreq = 1.0 / 1800.0; REAL8 f0 = 150.0 - 2.0 * dFreq; /* init data array */ COMPLEX8 vals[] = { crectf( -1.249241e-21, 1.194085e-21 ), crectf( 2.207420e-21, 2.472366e-22 ), crectf( 1.497939e-21, 6.593609e-22 ), crectf( 3.544089e-20, -9.365807e-21 ), crectf( 1.292773e-21, -1.402466e-21 ) }; UINT4 numBins = sizeof ( vals ) / sizeof(vals[0] ); if ( (mySFT = XLALCreateSFT ( numBins )) == NULL ) { XLALPrintError ("%s: Failed to create test-SFT using XLALCreateSFT(), xlalErrno = %d\n", fn, xlalErrno ); return XLAL_EFAILED; } /* init header */ strcpy ( mySFT->name, "H1;testSFTRngmed" ); mySFT->epoch = epoch; mySFT->f0 = f0; mySFT->deltaF = dFreq; /* we simply copy over these data-values into the SFT */ UINT4 iBin; for ( iBin = 0; iBin < numBins; iBin ++ ) mySFT->data->data[iBin] = vals[iBin]; /* get memory for running-median vector */ REAL8FrequencySeries rngmed; INIT_MEM ( rngmed ); XLAL_CHECK ( (rngmed.data = XLALCreateREAL8Vector ( numBins )) != NULL, XLAL_EFUNC, "Failed XLALCreateREAL8Vector ( %d )", numBins ); // ---------- Test running-median PSD estimation in simple blocksize cases // ------------------------------------------------------------ // TEST 1: odd blocksize = 3 // ------------------------------------------------------------ UINT4 blockSize3 = 3; /* reference result for 3-bin block running-median computed in octave: octave> sft = [ \ -1.249241e-21 + 1.194085e-21i, \ 2.207420e-21 + 2.472366e-22i, \ 1.497939e-21 + 6.593609e-22i, \ 3.544089e-20 - 9.365807e-21i, \ 1.292773e-21 - 1.402466e-21i \ ]; octave> periodo = abs(sft).^2; octave> m1 = median ( periodo(1:3) ); m2 = median ( periodo(2:4) ); m3 = median ( periodo (3:5 ) ); octave> rngmed = [ m1, m1, m2, m3, m3 ]; octave> printf ("rngmedREF3 = { %.16g, %.16g, %.16g, %.16g, %.16g };\n", rngmed ); rngmedREF3[] = { 2.986442063306e-42, 2.986442063306e-42, 4.933828992779561e-42, 3.638172910684999e-42, 3.638172910684999e-42 }; */ REAL8 rngmedREF3[] = { 2.986442063306e-42, 2.986442063306e-42, 4.933828992779561e-42, 3.638172910684999e-42, 3.638172910684999e-42 }; /* compute running median */ XLAL_CHECK ( XLALSFTtoRngmed ( &rngmed, mySFT, blockSize3 ) == XLAL_SUCCESS, XLAL_EFUNC, "XLALSFTtoRngmed() failed."); /* get median->mean bias correction, needed for octave-reference results, to make * them comparable to the bias-corrected results from LALSFTtoRngmed() */ REAL8 medianBias3 = XLALRngMedBias ( blockSize3 ); XLAL_CHECK ( xlalErrno == 0, XLAL_EFUNC, "XLALRngMedBias() failed."); BOOLEAN pass = 1; const CHAR *passStr; printf ("%4s %22s %22s %8s <%g\n", "Bin", "rngmed(LAL)", "rngmed(Octave)", "relError", tol); for (iBin=0; iBin < numBins; iBin ++ ) { REAL8 rngmedVAL = rngmed.data->data[iBin]; REAL8 rngmedREF = rngmedREF3[iBin] / medianBias3; // apply median-bias correction REAL8 relErr = REL_ERR ( rngmedREF, rngmedVAL ); if ( relErr > tol ) { pass = 0; passStr = "fail"; } else { passStr = "OK."; } printf ("%4d %22.16g %22.16g %8.1g %s\n", iBin, rngmedVAL, rngmedREF, relErr, passStr ); } /* for iBin < numBins */ // ------------------------------------------------------------ // TEST 2: even blocksize = 4 // ------------------------------------------------------------ UINT4 blockSize4 = 4; /* reference result for 4-bin block running-median computed in octave: octave> m1 = median ( periodo(1:4) ); m2 = median ( periodo(2:5) ); octave> rngmed = [ m1, m1, m1, m2, m2 ]; octave> printf ("rngmedREF4[] = { %.16g, %.16g, %.16g, %.16g, %.16g };\n", rngmed ); rngmedREF4[] = { 3.96013552804278e-42, 3.96013552804278e-42, 3.96013552804278e-42, 4.28600095173228e-42, 4.28600095173228e-42 }; */ REAL8 rngmedREF4[] = { 3.96013552804278e-42, 3.96013552804278e-42, 3.96013552804278e-42, 4.28600095173228e-42, 4.28600095173228e-42 }; /* compute running median */ XLAL_CHECK ( XLALSFTtoRngmed ( &rngmed, mySFT, blockSize4 ) == XLAL_SUCCESS, XLAL_EFUNC, "XLALSFTtoRngmed() failed."); /* get median->mean bias correction, needed for octave-reference results, to make * them comparable to the bias-corrected results from LALSFTtoRngmed() */ REAL8 medianBias4 = XLALRngMedBias ( blockSize4 ); XLAL_CHECK ( xlalErrno == 0, XLAL_EFUNC, "XLALRngMedBias() failed."); printf ("%4s %22s %22s %8s <%g\n", "Bin", "rngmed(LAL)", "rngmed(Octave)", "relError", tol); for (iBin=0; iBin < numBins; iBin ++ ) { REAL8 rngmedVAL = rngmed.data->data[iBin]; REAL8 rngmedREF = rngmedREF4[iBin] / medianBias4; // apply median-bias correction REAL8 relErr = REL_ERR ( rngmedREF, rngmedVAL ); if ( relErr > tol ) { pass = 0; passStr = "fail"; } else { passStr = "OK."; } printf ("%4d %22.16g %22.16g %8.1g %s\n", iBin, rngmedVAL, rngmedREF, relErr, passStr ); } /* for iBin < numBins */ /* free memory */ XLALDestroyREAL8Vector ( rngmed.data ); XLALDestroySFT ( mySFT ); LALCheckMemoryLeaks(); if ( !pass ) { printf ("Test failed! Difference exceeded tolerance.\n"); return XLAL_EFAILED; } else { printf ("Test passed.\n"); return XLAL_SUCCESS; } } /* main() */
/** * Unit-Test for function XLALSFTVectorToLFT(). * Generates random data (timeseries + corresponding SFTs), * then feeds the SFTs into XLALSFTVectorToLFT() * and checks correctness of output Fourier transform by * comparing to FT of original real-valued timeseries. * * \note This indirectly also checks XLALSFTVectorToCOMPLEX8TimeSeries() * which is used by XLALSFTVectorToLFT(). * * returns XLAL_SUCCESS on success, XLAL-error otherwise */ int test_XLALSFTVectorToLFT ( void ) { // ----- generate real-valued random timeseries and corresponding SFTs REAL4TimeSeries *tsR4 = NULL; SFTVector *sfts0 = NULL; XLAL_CHECK ( XLALgenerateRandomData ( &tsR4, &sfts0 ) == XLAL_SUCCESS, XLAL_EFUNC ); UINT4 numSamplesR4 = tsR4->data->length; REAL8 dt_R4 = tsR4->deltaT; REAL8 TspanR4 = numSamplesR4 * dt_R4; // ----- consider only the frequency band [3Hz, 4Hz] REAL8 out_fMin = 3; REAL8 out_Band = 1; SFTVector *sftsBand; XLAL_CHECK ( (sftsBand = XLALExtractBandFromSFTVector ( sfts0, out_fMin, out_Band )) != NULL, XLAL_EFUNC ); XLALDestroySFTVector ( sfts0 ); // ----- 1) compute FFT on original REAL4 timeseries ----- REAL4FFTPlan *planR4; XLAL_CHECK ( (planR4 = XLALCreateForwardREAL4FFTPlan ( numSamplesR4, 0 )) != NULL, XLAL_EFUNC ); SFTtype *lft0; XLAL_CHECK ( (lft0 = XLALCreateSFT ( numSamplesR4/2+1 )) != NULL, XLAL_EFUNC ); XLAL_CHECK ( XLALREAL4ForwardFFT ( lft0->data, tsR4->data, planR4 ) == XLAL_SUCCESS, XLAL_EFUNC ); strcpy ( lft0->name, tsR4->name ); lft0->f0 = 0; lft0->epoch = tsR4->epoch; REAL8 dfLFT = 1.0 / TspanR4; lft0->deltaF = dfLFT; // ----- extract frequency band of interest SFTtype *lftR4 = NULL; XLAL_CHECK ( XLALExtractBandFromSFT ( &lftR4, lft0, out_fMin, out_Band ) == XLAL_SUCCESS, XLAL_EFUNC ); for ( UINT4 k=0; k < lftR4->data->length; k ++ ) { lftR4->data->data[k] *= dt_R4; } // ----- 2) compute LFT directly from SFTs ---------- SFTtype *lftSFTs0; XLAL_CHECK ( (lftSFTs0 = XLALSFTVectorToLFT ( sftsBand, 1 )) != NULL, XLAL_EFUNC ); XLALDestroySFTVector ( sftsBand ); // ----- re-extract frequency band of interest SFTtype *lftSFTs = NULL; XLAL_CHECK ( XLALExtractBandFromSFT ( &lftSFTs, lftSFTs0, out_fMin, out_Band ) == XLAL_SUCCESS, XLAL_EFUNC ); if ( lalDebugLevel & LALINFO ) { // ----- write debug output XLAL_CHECK ( XLALdumpREAL4TimeSeries ( "TS_R4.dat", tsR4 ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK ( write_SFTdata ("LFT_R4T.dat", lftR4 ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK ( write_SFTdata ("LFT_SFTs.dat", lftSFTs ) == XLAL_SUCCESS, XLAL_EFUNC ); } // end: debug output // ========== compare resulting LFTs ========== VectorComparison XLAL_INIT_DECL(tol0); XLALPrintInfo ("Comparing LFT with itself: should give 0 for all measures\n"); XLAL_CHECK ( XLALCompareSFTs ( lftR4, lftR4, &tol0 ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK ( XLALCompareSFTs ( lftSFTs, lftSFTs, &tol0 ) == XLAL_SUCCESS, XLAL_EFUNC ); VectorComparison XLAL_INIT_DECL(tol); tol.relErr_L1 = 4e-2; tol.relErr_L2 = 5e-2; tol.angleV = 5e-2; // rad tol.relErr_atMaxAbsx = 1.2e-2; tol.relErr_atMaxAbsy = 1.2e-2; XLALPrintInfo ("Comparing LFT from REAL4-timeseries, to LFT from heterodyned COMPLEX8-timeseries:\n"); XLAL_CHECK ( XLALCompareSFTs ( lftR4, lftSFTs, &tol ) == XLAL_SUCCESS, XLAL_EFUNC ); // ---------- free memory ---------- XLALDestroyREAL4TimeSeries ( tsR4 ); XLALDestroyREAL4FFTPlan ( planR4 ); XLALDestroySFT ( lft0 ); XLALDestroySFT ( lftR4 ); XLALDestroySFT ( lftSFTs ); XLALDestroySFT ( lftSFTs0 ); return XLAL_SUCCESS; } // test_XLALSFTVectorToLFT()
/** * Turn the given multi-IFO SFTvectors into one long Fourier transform (LFT) over the total observation time */ SFTtype * XLALSFTVectorToLFT ( SFTVector *sfts, /**< input SFT vector (gets modified!) */ REAL8 upsampling /**< upsampling factor >= 1 */ ) { XLAL_CHECK_NULL ( (sfts != NULL) && (sfts->length > 0), XLAL_EINVAL ); XLAL_CHECK_NULL ( upsampling >= 1, XLAL_EDOM, "Upsampling factor (%f) must be >= 1 \n", upsampling ); // ----- some useful SFT infos SFTtype *firstSFT = &(sfts->data[0]); UINT4 numBinsSFT = firstSFT->data->length; REAL8 dfSFT = firstSFT->deltaF; REAL8 Tsft = 1.0 / dfSFT; REAL8 f0SFT = firstSFT->f0; // ----- turn input SFTs into a complex (heterodyned) timeseries COMPLEX8TimeSeries *lTS; XLAL_CHECK_NULL ( (lTS = XLALSFTVectorToCOMPLEX8TimeSeries ( sfts )) != NULL, XLAL_EFUNC ); REAL8 dt = lTS->deltaT; UINT4 numSamples0 = lTS->data->length; REAL8 Tspan0 = numSamples0 * dt; // ---------- determine time-span of upsampled time-series /* NOTE: Tspan MUST be an integer multiple of Tsft, * in order for the frequency bins of the final FFT * to be commensurate with the SFT bins. * This is required so that fHet is an exact * frequency-bin in both cases */ UINT4 numSFTsFit = lround ( (Tspan0 * upsampling) / Tsft ); REAL8 Tspan = numSFTsFit * Tsft; UINT4 numSamples = lround ( Tspan / dt ); // ----- enlarge TimeSeries container for zero-padding if neccessary if ( numSamples > numSamples0 ) { XLAL_CHECK_NULL ( (lTS->data->data = XLALRealloc ( lTS->data->data, numSamples * sizeof(lTS->data->data[0]) )) != NULL, XLAL_ENOMEM ); lTS->data->length = numSamples; memset ( lTS->data->data + numSamples0, 0, (numSamples - numSamples0) * sizeof(lTS->data->data[0])); /* set all new time-samples to zero */ } /* translate this back into fmin for the LFT (counting down from DC==fHet) */ /* fHet = DC of our internal DFTs */ UINT4 NnegSFT = NhalfNeg ( numBinsSFT ); REAL8 fHet = f0SFT + 1.0 * NnegSFT * dfSFT; UINT4 NnegLFT = NhalfNeg ( numSamples ); REAL8 f0LFT = fHet - NnegLFT / Tspan; // ----- prepare output LFT ---------- SFTtype *outputLFT; XLAL_CHECK_NULL ( (outputLFT = XLALCreateSFT ( numSamples )) != NULL, XLAL_EFUNC ); // prepare LFT header strcpy ( outputLFT->name, firstSFT->name ); strncat ( outputLFT->name, ":long Fourier transform", sizeof(outputLFT->name) - 1 - strlen(outputLFT->name)); outputLFT->epoch = firstSFT->epoch; outputLFT->f0 = f0LFT; outputLFT->deltaF = 1.0 / Tspan; outputLFT->sampleUnits = firstSFT->sampleUnits; // ---------- FFT the long timeseries ---------- COMPLEX8FFTPlan *LFTplan; XLAL_CHECK_NULL ( (LFTplan = XLALCreateForwardCOMPLEX8FFTPlan( numSamples, 0 )) != NULL, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALCOMPLEX8VectorFFT( outputLFT->data, lTS->data, LFTplan ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL ( XLALReorderFFTWtoSFT (outputLFT->data) == XLAL_SUCCESS, XLAL_EFUNC ); // apply proper normalization 'dt' for ( UINT4 k = 0; k < outputLFT->data->length; k ++ ) { outputLFT->data->data[k] *= dt; } /* cleanup memory */ XLALDestroyCOMPLEX8TimeSeries ( lTS ); XLALDestroyCOMPLEX8FFTPlan ( LFTplan ); return outputLFT; } // XLALSFTVectorToLFT()