Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LFTandTSutils.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Reinhard Prix
3 * Copyright (C) 2009 Chris Messenger, Reinhard Prix, Pinkesh Patel, Xavier Siemens, Holger Pletsch
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with with program; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20
21#include "config.h"
22
23/* System includes */
24#include <stdio.h>
25
26/* LAL-includes */
27#include <lal/LFTandTSutils.h>
28#include <lal/SFTfileIO.h>
29#include <lal/LogPrintf.h>
30#include <lal/TimeSeries.h>
31#include <lal/ComplexFFT.h>
32#include <lal/ComputeFstat.h>
33#include <lal/SinCosLUT.h>
34#include <lal/Factorial.h>
35#include <lal/Window.h>
36
37/*---------- DEFINES ----------*/
38#define MYMAX(x,y) ( (x) > (y) ? (x) : (y) )
39#define MYMIN(x,y) ( (x) < (y) ? (x) : (y) )
40#define SQ(x) ((x)*(x))
41
42#define FINITE_OR_ONE(x) (((x) != 0) ? (x) : 1.0)
43#define cRELERR(x,y) ( cabsf( (x) - (y) ) / FINITE_OR_ONE( 0.5 * (cabsf(x) + cabsf(y)) ) )
44#define fRELERR(x,y) ( fabsf( (x) - (y) ) / FINITE_OR_ONE( 0.5 * (fabsf(x) + fabsf(y)) ) )
45#define OOTWOPI (1.0 / LAL_TWOPI) // 1/2pi
46#define OOPI (1.0 / LAL_PI) // 1/pi
47#define LD_SMALL4 (2.0e-4) // "small" number for REAL4: taken from Demod()
48/*---------- Global variables ----------*/
50
51/* ---------- local prototypes ---------- */
52
53/*---------- empty initializers ---------- */
54
55/* ---------- function definitions ---------- */
56
57/// \addtogroup LFTandTSutils_h
58/// @{
59
60/**
61 * Turn the given multi-IFO SFTvectors into one long Fourier transform (LFT) over the total observation time
62 */
63SFTtype *
64XLALSFTVectorToLFT( SFTVector *sfts, /**< input SFT vector (gets modified!) */
65 REAL8 upsampling /**< upsampling factor >= 1 */
66 )
67{
68 XLAL_CHECK_NULL( ( sfts != NULL ) && ( sfts->length > 0 ), XLAL_EINVAL );
69 XLAL_CHECK_NULL( upsampling >= 1, XLAL_EDOM, "Upsampling factor (%f) must be >= 1 \n", upsampling );
70
71 // ----- some useful SFT infos
72 SFTtype *firstSFT = &( sfts->data[0] );
73 UINT4 numBinsSFT = firstSFT->data->length;
74 REAL8 dfSFT = firstSFT->deltaF;
75 REAL8 Tsft = 1.0 / dfSFT;
76 REAL8 f0SFT = firstSFT->f0;
77
78 // ----- turn input SFTs into a complex (heterodyned) timeseries
81 REAL8 dt = lTS->deltaT;
82 UINT4 numSamples0 = lTS->data->length;
83 REAL8 Tspan0 = numSamples0 * dt;
84
85 // ---------- determine time-span of upsampled time-series
86 /* NOTE: Tspan MUST be an integer multiple of Tsft,
87 * in order for the frequency bins of the final FFT
88 * to be commensurate with the SFT bins.
89 * This is required so that fHet is an exact
90 * frequency-bin in both cases
91 */
92 UINT4 numSFTsFit = lround( ( Tspan0 * upsampling ) / Tsft );
93 REAL8 Tspan = numSFTsFit * Tsft;
94 UINT4 numSamples = lround( Tspan / dt );
95
96 // ----- enlarge TimeSeries container for zero-padding if neccessary
97 if ( numSamples > numSamples0 ) {
98 XLAL_CHECK_NULL( ( lTS->data->data = XLALRealloc( lTS->data->data, numSamples * sizeof( lTS->data->data[0] ) ) ) != NULL, XLAL_ENOMEM );
99 lTS->data->length = numSamples;
100 memset( lTS->data->data + numSamples0, 0, ( numSamples - numSamples0 ) * sizeof( lTS->data->data[0] ) ); /* set all new time-samples to zero */
101 }
102
103 /* translate this back into fmin for the LFT (counting down from DC==fHet) */
104 /* fHet = DC of our internal DFTs */
105 UINT4 NnegSFT = NhalfNeg( numBinsSFT );
106 REAL8 fHet = f0SFT + 1.0 * NnegSFT * dfSFT;
107
108 UINT4 NnegLFT = NhalfNeg( numSamples );
109 REAL8 f0LFT = fHet - NnegLFT / Tspan;
110
111 // ----- prepare output LFT ----------
112 SFTtype *outputLFT;
113 XLAL_CHECK_NULL( ( outputLFT = XLALCreateSFT( numSamples ) ) != NULL, XLAL_EFUNC );
114
115 // prepare LFT header
116 strcpy( outputLFT->name, firstSFT->name );
117 strncat( outputLFT->name, ":long Fourier transform", sizeof( outputLFT->name ) - 1 - strlen( outputLFT->name ) );
118 outputLFT->epoch = firstSFT->epoch;
119 outputLFT->f0 = f0LFT;
120 outputLFT->deltaF = 1.0 / Tspan;
121 outputLFT->sampleUnits = firstSFT->sampleUnits;
122
123 // ---------- FFT the long timeseries ----------
124 COMPLEX8FFTPlan *LFTplan;
125 XLAL_CHECK_NULL( ( LFTplan = XLALCreateForwardCOMPLEX8FFTPlan( numSamples, 0 ) ) != NULL, XLAL_EFUNC );
126 XLAL_CHECK_NULL( XLALCOMPLEX8VectorFFT( outputLFT->data, lTS->data, LFTplan ) == XLAL_SUCCESS, XLAL_EFUNC );
128 // apply proper normalization 'dt'
129 for ( UINT4 k = 0; k < outputLFT->data->length; k ++ ) {
130 outputLFT->data->data[k] *= dt;
131 }
132
133 /* cleanup memory */
136
137 return outputLFT;
138
139} // XLALSFTVectorToLFT()
140
141
142/**
143 * Turn the given SFTvector into one long time-series, properly dealing with gaps.
144 */
146XLALSFTVectorToCOMPLEX8TimeSeries( const SFTVector *sftsIn /**< [in] SFT vector */
147 )
148{
149 // check input sanity
150 XLAL_CHECK_NULL( ( sftsIn != NULL ) && ( sftsIn->length > 0 ), XLAL_EINVAL );
151
152 // create a local copy of the input SFTs, as they will be locally modified!
153 SFTVector *sfts;
154 XLAL_CHECK_NULL( ( sfts = XLALDuplicateSFTVector( sftsIn ) ) != NULL, XLAL_EFUNC );
155
156 /* define some useful shorthands */
157 UINT4 numSFTs = sfts->length;
158 SFTtype *firstSFT = &( sfts->data[0] );
159 SFTtype *lastSFT = &( sfts->data[numSFTs - 1] );
160 UINT4 numFreqBinsSFT = firstSFT->data->length;
161 REAL8 dfSFT = firstSFT->deltaF;
162 REAL8 Tsft = 1.0 / dfSFT;
163 REAL8 deltaT = Tsft / numFreqBinsSFT; // complex FFT: numSamplesSFT = numFreqBinsSFT
164 REAL8 f0SFT = firstSFT->f0;
165
166 /* if the start and end input pointers are NOT NULL then determine start and time-span of the final long time-series */
167 LIGOTimeGPS start = firstSFT->epoch;
168 LIGOTimeGPS end = lastSFT->epoch;
169 XLALGPSAdd( &end, Tsft );
170
171 /* determine output time span */
172 REAL8 Tspan;
174
175 UINT4 numSamples = lround( Tspan / deltaT );
176
177 /* determine the heterodyning frequency */
178 /* fHet = DC of our internal DFTs */
179 UINT4 NnegSFT = NhalfNeg( numFreqBinsSFT );
180 REAL8 fHet = f0SFT + 1.0 * NnegSFT * dfSFT;
181
182 /* ----- Prepare invFFT of SFTs: compute plan for FFTW */
183 COMPLEX8FFTPlan *SFTplan;
184 XLAL_CHECK_NULL( ( SFTplan = XLALCreateReverseCOMPLEX8FFTPlan( numFreqBinsSFT, 0 ) ) != NULL, XLAL_EFUNC );
185
186 /* ----- Prepare short time-series holding ONE invFFT of a single SFT */
189 XLAL_CHECK_NULL( ( sTS = XLALCreateCOMPLEX8TimeSeries( "short timeseries", &epoch, 0, deltaT, &emptyLALUnit, numFreqBinsSFT ) ) != NULL, XLAL_EFUNC );
190
191 /* ----- prepare long TimeSeries container ---------- */
193 XLAL_CHECK_NULL( ( lTS = XLALCreateCOMPLEX8TimeSeries( firstSFT->name, &start, fHet, deltaT, &emptyLALUnit, numSamples ) ) != NULL, XLAL_EFUNC );
194 memset( lTS->data->data, 0, numSamples * sizeof( *lTS->data->data ) ); /* set all time-samples to zero (in case there are gaps) */
195
196 /* ---------- loop over all SFTs and inverse-FFT them ---------- */
197 for ( UINT4 n = 0; n < numSFTs; n ++ ) {
198 SFTtype *thisSFT = &( sfts->data[n] );
199
200 /* find bin in long timeseries corresponding to starttime of *this* SFT */
201 REAL8 offset_n = XLALGPSDiff( &( thisSFT->epoch ), &start );
202 UINT4 bin0_n = lround( offset_n / deltaT ); /* round to closest bin */
203
204 REAL8 nudge_n = bin0_n * deltaT - offset_n; /* rounding error */
205 nudge_n = 1e-9 * round( nudge_n * 1e9 ); /* round to closest nanosecond */
206 /* nudge SFT into integer timestep bin if necessary */
207 XLAL_CHECK_NULL( XLALTimeShiftSFT( thisSFT, nudge_n ) == XLAL_SUCCESS, XLAL_EFUNC );
208
209 /* determine heterodyning phase-correction for this SFT */
210 REAL8 offset = XLALGPSDiff( &thisSFT->epoch, &start ); // updated value after time-shift
211 // fHet * Tsft is an integer by construction, because fHet was chosen as a frequency-bin of the input SFTs
212 // therefore we only need the remainder (offset % Tsft)
213 REAL8 offsetEff = fmod( offset, Tsft );
214 REAL8 hetCycles = fmod( fHet * offsetEff, 1 ); // heterodyning phase-correction for this SFT
215
216 if ( nudge_n != 0 ) {
217 XLALPrintInfo( "n = %d, offset_n = %g, nudge_n = %g, offset = %g, offsetEff = %g, hetCycles = %g\n",
218 n, offset_n, nudge_n, offset, offsetEff, hetCycles );
219 }
220
221 REAL4 hetCorrection_re, hetCorrection_im;
222 XLAL_CHECK_NULL( XLALSinCos2PiLUT( &hetCorrection_im, &hetCorrection_re, -hetCycles ) == XLAL_SUCCESS, XLAL_EFUNC );
223 COMPLEX8 hetCorrection = crectf( hetCorrection_re, hetCorrection_im );
224
225 /* Note: we also bundle the overall normalization of 'df' into the het-correction.
226 * This ensures that the resulting timeseries will have the correct normalization, according to
227 * x_l = invFT[sft]_l = df * sum_{k=0}^{N-1} xt_k * e^(i 2pi k l / N )
228 * where x_l is the l-th timestamp, and xt_k is the k-th frequency bin of the SFT.
229 * See the LAL-conventions on FFTs: http://www.ligo.caltech.edu/docs/T/T010095-00.pdf
230 * (the FFTw convention does not contain the factor of 'df', which is why we need to
231 * apply it ourselves)
232 *
233 */
234 hetCorrection *= dfSFT;
235
237 XLAL_CHECK_NULL( XLALCOMPLEX8VectorFFT( sTS->data, thisSFT->data, SFTplan ) == XLAL_SUCCESS, XLAL_EFUNC );
238
239 for ( UINT4 j = 0; j < sTS->data->length; j++ ) {
240 sTS->data->data[j] *= hetCorrection;
241 } // for j < numFreqBinsSFT
242
243 // copy the short (shifted) heterodyned timeseries into correct location within long timeseries
244 UINT4 binsLeft = numSamples - bin0_n;
245 UINT4 copyLen = MYMIN( numFreqBinsSFT, binsLeft ); /* make sure not to write past the end of the long TS */
246 memcpy( &lTS->data->data[bin0_n], sTS->data->data, copyLen * sizeof( lTS->data->data[0] ) );
247
248 } /* for n < numSFTs */
249
250 // cleanup memory
251 XLALDestroySFTVector( sfts );
254
255 return lTS;
256
257} // XLALSFTVectorToCOMPLEX8TimeSeries()
258
259
260/**
261 * Turn the given multiSFTvector into multiple long COMPLEX8TimeSeries, properly dealing with gaps.
262 * Memory allocation for the output MultiCOMPLEX8TimeSeries is done within this function.
263 *
264 */
266XLALMultiSFTVectorToCOMPLEX8TimeSeries( const MultiSFTVector *multisfts /**< [in] multi SFT vector */
267 )
268{
269 // check input sanity
270 XLAL_CHECK_NULL( ( multisfts != NULL ) && ( multisfts->length > 0 ), XLAL_EINVAL );
271 UINT4 numDetectors = multisfts->length;
272
273 /* allocate memory for the output structure */
276 XLAL_CHECK_NULL( ( out->data = XLALMalloc( numDetectors * sizeof( COMPLEX8TimeSeries * ) ) ) != NULL, XLAL_ENOMEM );
277 out->length = numDetectors;
278
279 /* loop over detectors */
280 for ( UINT4 X = 0; X < numDetectors; X++ ) {
281 XLAL_CHECK_NULL( ( out->data[X] = XLALSFTVectorToCOMPLEX8TimeSeries( multisfts->data[X] ) ) != NULL, XLAL_EFUNC );
282 }
283
284 return out;
285
286} // XLALMultiSFTVectorToCOMPLEX8TimeSeries()
287
288
289
290/**
291 * Change frequency-bin order from fftw-convention to a 'SFT'
292 * ie. from FFTW: f[0], f[1],...f[N/2], f[-(N-1)/2], ... f[-2], f[-1]
293 * to: f[-(N-1)/2], ... f[-1], f[0], f[1], .... f[N/2]
294 */
295int
297{
298 XLAL_CHECK( ( X != NULL ) && ( X->length > 0 ), XLAL_EINVAL );
299
300 UINT4 N = X -> length;
301 UINT4 Npos_and_DC = NhalfPosDC( N );
302 UINT4 Nneg = NhalfNeg( N );
303
304 /* allocate temporary storage for swap */
305 COMPLEX8 *tmp;
306 XLAL_CHECK( ( tmp = XLALMalloc( N * sizeof( *tmp ) ) ) != NULL, XLAL_ENOMEM );
307 memcpy( tmp, X->data, N * sizeof( *tmp ) );
308
309 /* Copy second half from FFTW: 'negative' frequencies */
310 memcpy( X->data, tmp + Npos_and_DC, Nneg * sizeof( *tmp ) );
311
312 /* Copy first half from FFTW: 'DC + positive' frequencies */
313 memcpy( X->data + Nneg, tmp, Npos_and_DC * sizeof( *tmp ) );
314
315 XLALFree( tmp );
316
317 return XLAL_SUCCESS;
318
319} // XLALReorderFFTWtoSFT()
320
321/**
322 * Change frequency-bin order from 'SFT' to fftw-convention
323 * ie. from f[-(N-1)/2], ... f[-1], f[0], f[1], .... f[N/2]
324 * to FFTW: f[0], f[1],...f[N/2], f[-(N-1)/2], ... f[-2], f[-1]
325 */
326int
328{
329 XLAL_CHECK( ( X != NULL ) && ( X->length > 0 ), XLAL_EINVAL );
330
331 UINT4 N = X->length;
332 UINT4 Npos_and_DC = NhalfPosDC( N );
333 UINT4 Nneg = NhalfNeg( N );
334
335 /* allocate temporary storage for swap */
336 COMPLEX8 *tmp;
337 XLAL_CHECK( ( tmp = XLALMalloc( N * sizeof( *tmp ) ) ) != NULL, XLAL_ENOMEM );
338
339 memcpy( tmp, X->data, N * sizeof( *tmp ) );
340
341 /* Copy second half of FFTW: 'negative' frequencies */
342 memcpy( X->data + Npos_and_DC, tmp, Nneg * sizeof( *tmp ) );
343
344 /* Copy first half of FFTW: 'DC + positive' frequencies */
345 memcpy( X->data, tmp + Nneg, Npos_and_DC * sizeof( *tmp ) );
346
347 XLALFree( tmp );
348
349 return XLAL_SUCCESS;
350
351} // XLALReorderSFTtoFFTW()
352
353/**
354 * Time-shift the given SFT by an amount of 'shift' seconds,
355 * using the frequency-domain expression
356 * \f$ \widetilde{y}(f) = \widetilde{x}(f) \, e^{i 2\pi\,f\,\tau} \f$ ,
357 * which shifts \f$ x(t) \f$ into \f$ y(t) = x(t + \tau) \f$
358 *
359 * NOTE: this <b>modifies</b> the SFT in place
360 */
361int
362XLALTimeShiftSFT( SFTtype *sft, /**< [in/out] SFT to time-shift */
363 REAL8 shift /**< time-shift \f$ \tau \f$ in seconds */
364 )
365{
366 XLAL_CHECK( ( sft != NULL ) && ( sft->data != NULL ), XLAL_EINVAL );
367
368 if ( shift == 0 ) {
369 return XLAL_SUCCESS;
370 }
371
372 for ( UINT4 k = 0; k < sft->data->length; k++ ) {
373 REAL8 fk = sft->f0 + k * sft->deltaF; /* frequency of k-th bin */
374 REAL8 shiftCyles = shift * fk;
375 REAL4 fact_re, fact_im; /* complex phase-shift factor e^(-2pi f tau) */
376 XLAL_CHECK( XLALSinCos2PiLUT( &fact_im, &fact_re, shiftCyles ) == XLAL_SUCCESS, XLAL_EFUNC );
377
378 COMPLEX8 fact = crectf( fact_re, fact_im );
379 sft->data->data[k] *= fact;
380
381 } /* for k < numBins */
382
383 /* adjust SFTs epoch to the shift */
384 XLALGPSAdd( &sft->epoch, shift );
385
386 return XLAL_SUCCESS;
387
388} // XLALTimeShiftSFT()
389
390/**
391 * Multi-detector wrapper for XLALFrequencyShiftCOMPLEX8TimeSeries
392 * NOTE: this <b>modifies</b> the MultiCOMPLEX8Timeseries in place
393 */
394int
395XLALFrequencyShiftMultiCOMPLEX8TimeSeries( MultiCOMPLEX8TimeSeries *x, /**< [in/out] timeseries to time-shift */
396 const REAL8 shift /**< [in] freq-shift in Hz */
397 )
398{
399 XLAL_CHECK( ( x != NULL ) && ( x->data != NULL ) && ( x->length > 0 ), XLAL_EINVAL );
400
401 if ( shift == 0 ) {
402 return XLAL_SUCCESS;
403 }
404
405 /* loop over detectors */
406 UINT4 numDetectors = x->length;
407 for ( UINT4 X = 0; X < numDetectors; X++ ) {
408 /* shift the frequency of each detector's data */
410 }
411
412 return XLAL_SUCCESS;
413
414} /* XLALFrequencyShiftMultiCOMPLEX8TimeSeries() */
415
416
417/**
418 * Freq-shift the given COMPLEX8Timeseries by an amount of 'shift' Hz,
419 * using the time-domain expression y(t) = x(t) * e^(-i 2pi df t),
420 * which shifts x(f) into y(f) = x(f + df)
421 *
422 * NOTE: this <b>modifies</b> the COMPLEX8TimeSeries in place
423 */
424int
425XLALFrequencyShiftCOMPLEX8TimeSeries( COMPLEX8TimeSeries *x, /**< [in/out] timeseries to time-shift */
426 const REAL8 shift /**< [in] freq-shift in Hz */
427 )
428{
429 XLAL_CHECK( ( x != NULL ) && ( x->data != NULL ), XLAL_EINVAL );
430
431 if ( shift == 0 ) {
432 return XLAL_SUCCESS;
433 }
434
435 /* get timeseries time-step */
436 REAL8 deltat = x->deltaT;
437
438 /* loop over COMPLEX8TimeSeries elements */
439 for ( UINT4 k = 0; k < x->data->length; k++ ) {
440 REAL8 tk = k * deltat; /* time of k-th bin */
441 REAL8 shiftCycles = shift * tk;
442 REAL4 fact_re, fact_im; /* complex phase-shift factor e^(-2pi f tau) */
443
444 /* use a sin/cos look-up-table for speed */
445 XLAL_CHECK( XLALSinCos2PiLUT( &fact_im, &fact_re, shiftCycles ) == XLAL_SUCCESS, XLAL_EFUNC );
446 COMPLEX8 fact = crectf( fact_re, fact_im );
447
448 x->data->data[k] *= fact;
449
450 } /* for k < numBins */
451
452 /* adjust timeseries heterodyne frequency to the shift */
453 x->f0 -= shift;
454
455 return XLAL_SUCCESS;
456
457} /* XLALFrequencyShiftCOMPLEX8TimeSeries() */
458
459
460/**
461 * Apply a spin-down correction to the complex8 timeseries
462 * using the time-domain expression y(t) = x(t) * e^(-i 2pi sum f_k * (t-tref)^(k+1)),
463 *
464 * NOTE: this <b>modifies</b> the input COMPLEX8TimeSeries in place
465 */
466int
467XLALSpinDownCorrectionMultiTS( MultiCOMPLEX8TimeSeries *multiTimeSeries, /**< [in/out] timeseries to time-shift */
468 const PulsarDopplerParams *doppler /**< parameter-space point to correct for */
469 )
470{
471 // check input sanity
472 XLAL_CHECK( ( multiTimeSeries != NULL ) && ( multiTimeSeries->data != NULL ) && ( multiTimeSeries->length > 0 ), XLAL_EINVAL );
473 XLAL_CHECK( doppler != NULL, XLAL_EINVAL );
474
475 UINT4 numDetectors = multiTimeSeries->length;
476
477 LIGOTimeGPS *epoch = &( multiTimeSeries->data[0]->epoch );
478 UINT4 numSamples = multiTimeSeries->data[0]->data->length;
479
480 REAL8 dt = multiTimeSeries->data[0]->deltaT;
481
482 /* determine number of spin down's and check if sensible */
483 UINT4 nspins = PULSAR_MAX_SPINS - 1;
484 while ( ( nspins > 0 ) && ( doppler->fkdot[nspins] == 0 ) ) {
485 nspins--;
486 }
487
488 /* apply spin derivitive correction to resampled timeseries */
489 REAL8 tk = XLALGPSDiff( epoch, &( doppler->refTime ) );
490 for ( UINT4 k = 0; k < numSamples; k++ ) {
491 REAL8 tk_pow_jp1 = tk;
492 REAL8 cycles_k = 0;
493 for ( UINT4 j = 1; j <= nspins; j++ ) {
494 tk_pow_jp1 *= tk;
495 /* compute fractional number of cycles the spin-derivitive has added since the reftime */
496 cycles_k += LAL_FACT_INV[j + 1] * doppler->fkdot[j] * tk_pow_jp1;
497 } // for j < nspins
498
499 REAL4 cosphase, sinphase;
500 XLAL_CHECK( XLALSinCos2PiLUT( &sinphase, &cosphase, -cycles_k ) == XLAL_SUCCESS, XLAL_EFUNC );
501 COMPLEX8 em2piphase = crectf( cosphase, sinphase );
502
503 /* loop over detectors */
504 for ( UINT4 X = 0; X < numDetectors; X++ ) {
505 multiTimeSeries->data[X]->data->data[k] *= em2piphase;
506 } // for X < numDetectors
507
508 tk += dt;
509
510 } // for k < numSamples
511
512 return XLAL_SUCCESS;
513
514} // XLALSpinDownCorrectionMultiTS()
515
516
517/* ===== Object creation/destruction functions ===== */
518
519/**
520 * Destroy a MultiCOMPLEX8TimeSeries structure.
521 * Note, this is "NULL-robust" in the sense that it will not crash
522 * on NULL-entries anywhere in this struct, so it can be used
523 * for failure-cleanup even on incomplete structs
524 */
525void
527{
528 if ( ! multiTimes ) {
529 return;
530 }
531 if ( multiTimes->data != NULL ) {
532 UINT4 numDetectors = multiTimes->length;
533 for ( UINT4 X = 0; X < numDetectors; X ++ ) {
534 XLALDestroyCOMPLEX8TimeSeries( multiTimes->data[X] );
535 } // for X < numDetectors
536 XLALFree( multiTimes->data );
537 } // if multiTimes->data
538
539 XLALFree( multiTimes );
540
541 return;
542
543} // XLALDestroyMultiCOMPLEX8TimeSeries()
544
545
546/**
547 * Duplicates a MultiCOMPLEX8TimeSeries structure.
548 * Allocates memory and copies contents.
549 */
552{
553 XLAL_CHECK_NULL( multiTimes != NULL, XLAL_EINVAL );
554 XLAL_CHECK_NULL( multiTimes->length > 0, XLAL_EINVAL );
555
556 UINT4 numDetectors = multiTimes->length;
557
558 // ----- prepare memory for multicomplex8timeseries container
560 XLAL_CHECK_NULL( ( out = XLALCalloc( 1, sizeof( *out ) ) ) != NULL, XLAL_ENOMEM );
561 out->length = numDetectors;
562 XLAL_CHECK_NULL( ( out->data = XLALCalloc( numDetectors, sizeof( *out->data ) ) ) != NULL, XLAL_ENOMEM );
563
564 // ----- copy each of the numDet complex8timeseries contents
565 for ( UINT4 X = 0; X < numDetectors; X ++ ) {
566 XLAL_CHECK_NULL( ( out->data[X] = XLALDuplicateCOMPLEX8TimeSeries( multiTimes->data[X] ) ) != NULL, XLAL_EFUNC );
567 }
568
569 return out;
570
571} // XLALDuplicateMultiCOMPLEX8TimeSeries()
572
573/**
574 * Duplicates a COMPLEX8TimeSeries structure.
575 * Allocates memory and copies contents.
576 */
579{
580 XLAL_CHECK_NULL( ttimes != NULL, XLAL_EINVAL );
581 XLAL_CHECK_NULL( ( ttimes->data != NULL ) && ( ttimes->data->length > 0 ) && ( ttimes->data->data != NULL ), XLAL_EINVAL );
582
584 XLAL_CHECK_NULL( ( out = XLALCalloc( 1, sizeof( *out ) ) ) != NULL, XLAL_ENOMEM );
585
586 // copy header info [including data-pointer, will be reset]
587 memcpy( out, ttimes, sizeof( *ttimes ) );
588
589 UINT4 numBins = ttimes->data->length;
591
592 // copy contents of COMPLEX8 vector
593 memcpy( out->data->data, ttimes->data->data, numBins * sizeof( ttimes->data->data[0] ) );
594
595 return out;
596
597} // XLALDuplicateCOMPLEX8TimeSeries()
598
599/**
600 * Copies a MultiCOMPLEX8TimeSeries structure, output must be allocated of identical size as input!
601 */
602int
604 MultiCOMPLEX8TimeSeries *multiTimesIn
605 )
606{
607 XLAL_CHECK( multiTimesIn != NULL, XLAL_EINVAL );
608 XLAL_CHECK( multiTimesOut != NULL, XLAL_EINVAL );
609
610 UINT4 numDetectors = multiTimesIn->length;
611 XLAL_CHECK( multiTimesOut->length == numDetectors, XLAL_EINVAL );
612
613 // ----- copy each of the numDet complex8timeseries contents
614 for ( UINT4 X = 0; X < numDetectors; X ++ ) {
615 XLAL_CHECK( XLALCopyCOMPLEX8TimeSeries( multiTimesOut->data[X], multiTimesIn->data[X] ) == XLAL_SUCCESS, XLAL_EFUNC );
616 }
617
618 return XLAL_SUCCESS;
619
620} // XLALCopyMultiCOMPLEX8TimeSeries()
621
622/**
623 * Copies a COMPLEX8TimeSeries structure, output must be allocated of identical size as input!
624 */
625int
627 COMPLEX8TimeSeries *ts_in
628 )
629{
630 XLAL_CHECK( ts_out != NULL, XLAL_EINVAL );
631 XLAL_CHECK( ts_in != NULL, XLAL_EINVAL );
632
633 UINT4 numSamples = ts_in->data->length;
634 XLAL_CHECK( ts_out->data->length == numSamples, XLAL_EINVAL );
635
636 COMPLEX8Vector *tmp = ts_out->data;
637
638 // copy header info [including data-pointer, will be restored]
639 ( *ts_out ) = ( *ts_in );
640 ts_out->data = tmp;
641
642 // copy contents of COMPLEX8 vector
643 memcpy( ts_out->data->data, ts_in->data->data, numSamples * sizeof( ts_out->data->data[0] ) );
644
645 return XLAL_SUCCESS;
646
647} // XLALCopyCOMPLEX8TimeSeries()
648
649
650/** Compare two COMPLEX8 vectors using various different comparison metrics
651 */
652int
653XLALCompareCOMPLEX8Vectors( VectorComparison *result, ///< [out] return comparison results
654 const COMPLEX8Vector *x, ///< [in] first input vector
655 const COMPLEX8Vector *y, ///< [in] second input vector
656 const VectorComparison *tol ///< [in] accepted tolerances on comparisons, or NULL for no check
657 )
658{
659 XLAL_CHECK( result != NULL, XLAL_EINVAL );
660 XLAL_CHECK( x != NULL, XLAL_EINVAL );
661 XLAL_CHECK( y != NULL, XLAL_EINVAL );
662 XLAL_CHECK( x->data != NULL, XLAL_EINVAL );
663 XLAL_CHECK( y->data != NULL, XLAL_EINVAL );
664 XLAL_CHECK( x->length > 0, XLAL_EINVAL );
665 XLAL_CHECK( x->length == y->length, XLAL_EINVAL );
666
667 REAL8 x_L1 = 0, x_L2 = 0;
668 REAL8 x_L2sq = 0;
669 REAL8 y_L1 = 0, y_L2 = 0;
670 REAL8 y_L2sq = 0;
671 REAL8 diff_L1 = 0, diff_L2 = 0;
672 COMPLEX16 scalar = 0;
673
674 REAL8 maxAbsx = 0, maxAbsy = 0;
675 COMPLEX8 x_atMaxAbsx = 0, y_atMaxAbsx = 0;
676 COMPLEX8 x_atMaxAbsy = 0, y_atMaxAbsy = 0;
677
678
679 UINT4 numSamples = x->length;
680 for ( UINT4 i = 0; i < numSamples; i ++ ) {
681 COMPLEX16 x_i = x->data[i];
682 COMPLEX16 y_i = y->data[i];
683 REAL8 xAbs2_i = x_i * conj( x_i );
684 REAL8 yAbs2_i = y_i * conj( y_i );
685 REAL8 xAbs_i = sqrt( xAbs2_i );
686 REAL8 yAbs_i = sqrt( yAbs2_i );
687 XLAL_CHECK( isfinite( xAbs_i ), XLAL_EFPINVAL, "non-finite element: x(%d) = %g + I %g\n", i, creal( x_i ), cimag( x_i ) );
688 XLAL_CHECK( isfinite( yAbs_i ), XLAL_EFPINVAL, "non-finite element: y(%d) = %g + I %g\n", i, creal( y_i ), cimag( y_i ) );
689
690 REAL8 absdiff = cabs( x_i - y_i );
691 diff_L1 += absdiff;
692 diff_L2 += SQ( absdiff );
693
694 x_L1 += xAbs_i;
695 y_L1 += yAbs_i;
696 x_L2sq += xAbs2_i;
697 y_L2sq += yAbs2_i;
698
699 scalar += x_i * conj( y_i );
700
701 if ( xAbs_i > maxAbsx ) {
702 maxAbsx = xAbs_i;
703 x_atMaxAbsx = x_i;
704 y_atMaxAbsx = y_i;
705 }
706 if ( yAbs_i > maxAbsy ) {
707 maxAbsy = yAbs_i;
708 x_atMaxAbsy = x_i;
709 y_atMaxAbsy = y_i;
710 }
711
712 } // for i < numSamples
713
714 // complete L2 norms by taking sqrt
715 x_L2 = sqrt( x_L2sq );
716 y_L2 = sqrt( y_L2sq );
717 diff_L2 = sqrt( diff_L2 );
718 REAL8 sinAngle2 = ( x_L2sq * y_L2sq - scalar * conj( scalar ) ) / FINITE_OR_ONE( x_L2sq * y_L2sq );
719 REAL8 angle = asin( sqrt( fabs( sinAngle2 ) ) );
720
721 // compute and return comparison results
722 result->relErr_L1 = diff_L1 / FINITE_OR_ONE( 0.5 * ( x_L1 + y_L1 ) );
723 result->relErr_L2 = diff_L2 / FINITE_OR_ONE( 0.5 * ( x_L2 + y_L2 ) );
724 result->angleV = angle;
725
726 result->relErr_atMaxAbsx = cRELERR( x_atMaxAbsx, y_atMaxAbsx );
727 result->relErr_atMaxAbsy = cRELERR( x_atMaxAbsy, y_atMaxAbsy );;
728
730
731 return XLAL_SUCCESS;
732
733} // XLALCompareCOMPLEX8Vectors()
734
735/** Compare two REAL4 vectors using various different comparison metrics
736 */
737int
738XLALCompareREAL4Vectors( VectorComparison *result, ///< [out] return comparison results
739 const REAL4Vector *x, ///< [in] first input vector
740 const REAL4Vector *y, ///< [in] second input vector
741 const VectorComparison *tol ///< [in] accepted tolerances on comparisons, or NULL for no check
742 )
743{
744 XLAL_CHECK( result != NULL, XLAL_EINVAL );
745 XLAL_CHECK( x != NULL, XLAL_EINVAL );
746 XLAL_CHECK( y != NULL, XLAL_EINVAL );
747 XLAL_CHECK( x->data != NULL, XLAL_EINVAL );
748 XLAL_CHECK( y->data != NULL, XLAL_EINVAL );
749 XLAL_CHECK( x->length > 0, XLAL_EINVAL );
750 XLAL_CHECK( x->length == y->length, XLAL_EINVAL );
751
752 REAL8 x_L1 = 0, x_L2 = 0;
753 REAL8 x_L2sq = 0;
754 REAL8 y_L1 = 0, y_L2 = 0;
755 REAL8 y_L2sq = 0;
756 REAL8 diff_L1 = 0, diff_L2 = 0;
757 REAL8 scalar = 0;
758
759 REAL4 maxAbsx = 0, maxAbsy = 0;
760 REAL4 x_atMaxAbsx = 0, y_atMaxAbsx = 0;
761 REAL4 x_atMaxAbsy = 0, y_atMaxAbsy = 0;
762
763 UINT4 numSamples = x->length;
764 for ( UINT4 i = 0; i < numSamples; i ++ ) {
765 REAL8 x_i = x->data[i];
766 REAL8 y_i = y->data[i];
767 XLAL_CHECK( isfinite( x_i ), XLAL_EFPINVAL, "non-finite element: x(%d) = %g\n", i, x_i );
768 XLAL_CHECK( isfinite( y_i ), XLAL_EFPINVAL, "non-finite element: y(%d) = %g\n", i, y_i );
769 REAL8 xAbs_i = fabs( x_i );
770 REAL8 yAbs_i = fabs( y_i );
771 REAL8 xAbs2_i = SQ( x_i );
772 REAL8 yAbs2_i = SQ( y_i );
773
774 REAL8 absdiff = fabs( x_i - y_i );
775 diff_L1 += absdiff;
776 diff_L2 += SQ( absdiff );
777
778 x_L1 += xAbs_i;
779 y_L1 += yAbs_i;
780 x_L2sq += xAbs2_i;
781 y_L2sq += yAbs2_i;
782
783 scalar += x_i * y_i;
784
785 if ( xAbs_i > maxAbsx ) {
786 maxAbsx = xAbs_i;
787 x_atMaxAbsx = x_i;
788 y_atMaxAbsx = y_i;
789 }
790 if ( yAbs_i > maxAbsy ) {
791 maxAbsy = yAbs_i;
792 x_atMaxAbsy = x_i;
793 y_atMaxAbsy = y_i;
794 }
795
796 } // for i < numSamples
797
798 // complete L2 norms by taking sqrt
799 x_L2 = sqrt( x_L2sq );
800 y_L2 = sqrt( y_L2sq );
801 diff_L2 = sqrt( diff_L2 );
802
803 // compute and return comparison results
804 result->relErr_L1 = diff_L1 / FINITE_OR_ONE( 0.5 * ( x_L1 + y_L1 ) );
805 result->relErr_L2 = diff_L2 / FINITE_OR_ONE( 0.5 * ( x_L2 + y_L2 ) );
806 REAL8 sinAngle2 = ( x_L2sq * y_L2sq - SQ( scalar ) ) / FINITE_OR_ONE( x_L2sq * y_L2sq );
807 result->angleV = asin( sqrt( fabs( sinAngle2 ) ) );
808 result->relErr_atMaxAbsx = fRELERR( x_atMaxAbsx, y_atMaxAbsx );
809 result->relErr_atMaxAbsy = fRELERR( x_atMaxAbsy, y_atMaxAbsy );;
810
812
813 return XLAL_SUCCESS;
814
815} // XLALCompareREAL4Vectors()
816
817/** Check VectorComparison result against specified tolerances,
818 * to allow for standardized comparison and reporting.
819 */
820int
821XLALCheckVectorComparisonTolerances( const VectorComparison *result, ///< [in] comparison result from XLALCompareREAL4Vectors() or XLALCompareCOMPLEX8Vectors()
822 const VectorComparison *tol ///< [in] accepted tolerances on comparisons: if NULL=> always accept the result
823 )
824{
825 XLAL_CHECK( result != NULL, XLAL_EINVAL );
826
828 if ( tol != NULL ) {
829 localTol = ( *tol );
830 }
831
832 const char *names[5] = { "relErr_L1", "relErr_L2", "angleV", "relErr_atMaxAbsx", "relErr_atMaxAbsy" };
833 const REAL4 results[5] = { result->relErr_L1, result->relErr_L2, result->angleV, result->relErr_atMaxAbsx, result->relErr_atMaxAbsy };
834 const REAL4 tols[5] = { localTol.relErr_L1, localTol.relErr_L2, localTol.angleV, localTol.relErr_atMaxAbsx, localTol.relErr_atMaxAbsy };
835
836 BOOLEAN failed = 0;
837
838 for ( size_t i = 0; i < XLAL_NUM_ELEM( names ); ++i ) {
839
840 if ( results[i] > tols[i] ) {
841 failed = 1;
842 }
843
844 if ( lalDebugLevel & LALINFO ) {
845 XLALPrintError( "%-16s = %.1e (%.1e): %s\n", names[i], results[i], tols[i],
846 ( results[i] > tols[i] ) ? "FAILED. Exceeded tolerance." : "OK." );
847 }
848
849 }
850
851 if ( failed ) {
852 XLAL_ERROR( XLAL_ETOL, "FAILED. Exceeded at least one tolerance level.\n" );
853 }
854
855 XLALPrintInfo( "OK.\n" );
856
857 return XLAL_SUCCESS;
858
859} // XLALCheckVectorComparisonTolerances()
860
861/** Interpolate a given regularly-spaced COMPLEX8 timeseries 'ts_in = x_in(j * dt)' onto new samples
862 * 'y_out(t_out)' using *windowed* Shannon sinc interpolation, windowed to (2*Dterms+1) terms, namely
863 * \f[
864 * \newcommand{\Dterms}{\mathrm{Dterms}}
865 * \f]
866 *
867 * \f{equation}{
868 * x(t) = \sum_{j = j^* - \Dterms}^{j^* + \Dterms} x_j \, w_j \, \frac{\sin(\pi\delta_j)}{\pi\delta_j}\,,\quad\text{with}\quad
869 * \delta_j \equiv \frac{t - t_j}{\Delta t}\,,
870 * \f}
871 * where \f$ j^* \equiv \mathrm{round}(t / \Delta t) \f$ , and
872 * where \f$ w_j \f$ is the window used (here: Hamming)
873 *
874 * In order to implement this more efficiently, we observe that \f$ \sin(\pi\delta_j) = (-1)^{(j-j0)}\sin(\pi\delta_{j0}) \f$ for integer \f$ j \f$ ,
875 * and therefore
876 *
877 * \f{equation}{
878 * x(t) = \frac{\sin(\pi\,\delta_{j0})}{\pi} \, \sum_{j = j^* - \Dterms}^{j^* + \Dterms} (-1)^{(j-j0)}\frac{x_j \, w_j}{\delta_j}\,,
879 * \f}
880 *
881 * NOTE: Using Dterms=0 corresponds to closest-bin interpolation
882 *
883 * NOTE2: samples *outside* the original timespan are returned as 0
884 *
885 * NOTE3: we're using a Hamming window of length L = 2*Dterms + 1, which has a pass-band wiggle of delta_p ~ 0.0022,
886 * and a transition bandwidth of (4/L) * Bandwidth.
887 * You need to make sure to include sufficient effective sidebands to the input timeseries, so that the transition band can
888 * be safely ignored or 'cut out' at the end
889 */
890int
891XLALSincInterpolateCOMPLEX8TimeSeries( COMPLEX8Vector *y_out, ///< [out] output series of interpolated y-values [must be same size as t_out]
892 const REAL8Vector *t_out, ///< [in] output time-steps to interpolate input to
893 const COMPLEX8TimeSeries *ts_in,///< [in] regularly-spaced input timeseries
894 UINT4 Dterms ///< [in] window sinc kernel sum to +-Dterms around max
895 )
896{
897 XLAL_CHECK( y_out != NULL, XLAL_EINVAL );
898 XLAL_CHECK( t_out != NULL, XLAL_EINVAL );
899 XLAL_CHECK( ts_in != NULL, XLAL_EINVAL );
900 XLAL_CHECK( y_out->length == t_out->length, XLAL_EINVAL );
901
902 UINT4 numSamplesOut = t_out->length;
903 UINT4 numSamplesIn = ts_in->data->length;
904 REAL8 dt = ts_in->deltaT;
905 REAL8 tmin = XLALGPSGetREAL8( &( ts_in->epoch ) ); // time of first bin in input timeseries
906
908 UINT4 winLen = 2 * Dterms + 1;
909 XLAL_CHECK( ( win = XLALCreateHammingREAL8Window( winLen ) ) != NULL, XLAL_EFUNC );
910
911 const REAL8 oodt = 1.0 / dt;
912
913 for ( UINT4 l = 0; l < numSamplesOut; l ++ ) {
914 REAL8 t = t_out->data[l] - tmin; // measure time since start of input timeseries
915
916 // samples outside of input timeseries are returned as 0
917 if ( ( t < 0 ) || ( t > ( numSamplesIn - 1 ) * dt ) ) { // avoid any extrapolations!
918 y_out->data[l] = 0;
919 continue;
920 }
921
922 REAL8 t_by_dt = t * oodt;
923 INT8 jstar = lround( t_by_dt ); // bin closest to 't', guaranteed to be in [0, numSamples-1]
924
925 if ( fabs( t_by_dt - jstar ) < LD_SMALL4 ) { // avoid numerical problems near peak
926 y_out->data[l] = ts_in->data->data[jstar]; // known analytic solution for exact bin
927 continue;
928 }
929
930 INT4 jStart0 = jstar - Dterms;
931 UINT4 jEnd0 = jstar + Dterms;
932 UINT4 jStart = MYMAX( jStart0, 0 );
933 UINT4 jEnd = MYMIN( jEnd0, numSamplesIn - 1 );
934
935 REAL4 delta_jStart = ( t_by_dt - jStart );
936 REAL4 sin0, cos0;
937 XLALSinCosLUT( &sin0, &cos0, LAL_PI * delta_jStart );
938 REAL4 sin0oopi = sin0 * OOPI;
939
940 COMPLEX8 y_l = 0;
941 REAL8 delta_j = delta_jStart;
942 for ( UINT8 j = jStart; j <= jEnd; j ++ ) {
943 COMPLEX8 Cj = win->data->data[j - jStart0] * sin0oopi / delta_j;
944
945 y_l += Cj * ts_in->data->data[j];
946
947 sin0oopi = -sin0oopi; // sin-term flips sign every step
948 delta_j --;
949 } // for j in [j* - Dterms, ... ,j* + Dterms]
950
951 y_out->data[l] = y_l;
952
953 } // for l < numSamplesOut
954
956
957 return XLAL_SUCCESS;
958
959} // XLALSincInterpolateCOMPLEX8TimeSeries()
960
961/** Interpolate a given regularly-spaced COMPLEX8 frequency-series 'fs_in = x_in( k * df)' onto new samples
962 * 'y_out(f_out)' using (complex) Sinc interpolation (obtained from Dirichlet kernel in large-N limit), truncated to (2*Dterms+1) terms, namely
963 *
964 * \f{equation}{
965 * \widetilde{x}(f) = \sum_{k = k^* - \Delta k}^{k^* + \Delta k} \widetilde{x}_k \, \frac{ 1 - e^{-i 2\pi\,\delta_k} }{ i 2\pi\,\delta_k}\,,
966 * \f}
967 * where \f$ k^* \equiv \mathrm{round}(f / \Delta f) \f$ , and \f$ \delta_k \equiv \frac{f - f_k}{\Delta f} \f$ .
968 *
969 * In order to implement this more efficiently, we observe that \f$ e^{-i 2\pi\,\delta_k} = e^{-i 2\pi\,\delta_{k*}} \f$ for integer \f$ k \f$ , and therefore
970 * \f{equation}{
971 * \widetilde{x}(f) = \frac{\sin(2\pi\delta_{k*}) + i(\cos(2\pi\delta_{k*}) - 1)}{2\pi} \sum_{k = k^* - \Delta k}^{k^* + \Delta k} \frac{\widetilde{x}_k}{\delta_k}\,,
972 * \f}
973 *
974 * NOTE: Using Dterms=0 corresponds to closest-bin interpolation
975 *
976 * NOTE2: frequencies *outside* the original frequency band are returned as 0
977 */
978int
979XLALSincInterpolateCOMPLEX8FrequencySeries( COMPLEX8Vector *y_out, ///< [out] output series of interpolated y-values [must be alloc'ed already]
980 const REAL8Vector *f_out, ///< [in] output frequency-values to interpolate input to
981 const COMPLEX8FrequencySeries *fs_in, ///< [in] regularly-spaced input frequency-series
982 UINT4 Dterms ///< [in] truncate interpolation kernel sum to +-Dterms around max
983 )
984{
985 XLAL_CHECK( y_out != NULL, XLAL_EINVAL );
986 XLAL_CHECK( f_out != NULL, XLAL_EINVAL );
987 XLAL_CHECK( fs_in != NULL, XLAL_EINVAL );
988
989 UINT4 numBinsOut = f_out->length;
990 XLAL_CHECK( y_out->length == numBinsOut, XLAL_EINVAL );
991
992 UINT4 numBinsIn = fs_in->data->length;
993 REAL8 df = fs_in->deltaF;
994 REAL8 fMin = fs_in->f0; // frequency of first input bin
995
996 const REAL8 oodf = 1.0 / df;
997
998 for ( UINT4 l = 0; l < numBinsOut; l ++ ) {
999 REAL8 f = f_out->data[l] - fMin; // measure frequency from lowest input bin
1000
1001 // bins outside of input frequency-series are returned as 0
1002 if ( ( f < 0 ) || ( f > ( numBinsIn - 1 ) * df ) ) { // avoid any extrapolations!
1003 y_out->data[l] = 0;
1004 continue;
1005 }
1006
1007 INT8 kstar = lround( f * oodf ); // bin closest to 't', guaranteed to be in [0, numBins-1]
1008
1009 if ( fabs( f - kstar * df ) < 1e-6 ) { // avoid numerical problems near peak
1010 y_out->data[l] = fs_in->data->data[kstar]; // known analytic solution for exact bin
1011 continue;
1012 }
1013
1014 UINT8 k0 = MYMAX( kstar - Dterms, 0 );
1015 UINT8 k1 = MYMIN( kstar + Dterms, numBinsIn - 1 );
1016
1017 REAL4 delta_kstar = ( f - kstar * df ) * oodf; // in [-0.5, 0.5]
1018 REAL4 sin2pidelta, cos2pidelta;
1019 XLALSinCos2PiLUTtrimmed( &sin2pidelta, &cos2pidelta, delta_kstar + 1.0f );
1020
1021 COMPLEX8 prefact = OOTWOPI * ( sin2pidelta + I * ( cos2pidelta - 1.0f ) );
1022
1023 COMPLEX8 y_l = 0;
1024 REAL4 delta_k = delta_kstar + Dterms;
1025 for ( UINT8 k = k0; k <= k1; k ++ ) {
1026 y_l += fs_in->data->data[k] / delta_k;
1027 delta_k --;
1028 } // for k in [k* - Dterms, ... ,k* + Dterms]
1029
1030 y_out->data[l] = prefact * y_l;
1031
1032 } // for l < numBinsOut
1033
1034 return XLAL_SUCCESS;
1035
1036} // XLALSincInterpolateCOMPLEX8FrequencySeries()
1037
1038
1039/** (Complex)Sinc-interpolate an input SFT to an output SFT.
1040 * This is a simple convenience wrapper to XLALSincInterpolateCOMPLEX8FrequencySeries()
1041 * for the special case of interpolating onto new SFT frequency bins
1042 */
1043SFTtype *
1044XLALSincInterpolateSFT( const SFTtype *sft_in, ///< [in] input SFT
1045 REAL8 f0Out, ///< [in] new start frequency
1046 REAL8 dfOut, ///< [in] new frequency step-size
1047 UINT4 numBinsOut, ///< [in] new number of bins
1048 UINT4 Dterms ///< [in] truncate interpolation kernel sum to +-Dterms around max
1049 )
1050{
1051 XLAL_CHECK_NULL( sft_in != NULL, XLAL_EINVAL );
1052 XLAL_CHECK_NULL( dfOut > 0, XLAL_EINVAL );
1053 XLAL_CHECK_NULL( numBinsOut > 0, XLAL_EINVAL );
1054
1055 // setup frequency vector
1056 REAL8Vector *f_out;
1057 XLAL_CHECK_NULL( ( f_out = XLALCreateREAL8Vector( numBinsOut ) ) != NULL, XLAL_EFUNC );
1058 for ( UINT4 k = 0; k < numBinsOut; k ++ ) {
1059 f_out->data[k] = f0Out + k * dfOut;
1060 } // for k < numBinsOut
1061
1062 SFTtype *out;
1063 XLAL_CHECK_NULL( ( out = XLALCalloc( 1, sizeof( *out ) ) ) != NULL, XLAL_EFUNC );
1064 ( *out ) = ( *sft_in ); // copy header
1065 out->f0 = f0Out;
1066 out->deltaF = dfOut;
1067 XLAL_CHECK_NULL( ( out->data = XLALCreateCOMPLEX8Vector( numBinsOut ) ) != NULL, XLAL_EFUNC );
1068
1070
1071 XLALDestroyREAL8Vector( f_out );
1072
1073 return out;
1074
1075} // XLALSincInterpolateSFT()
1076
1077
1078/**
1079 * Interpolate frequency-series to newLen frequency-bins.
1080 * This is using DFT-interpolation (derived from zero-padding).
1081 */
1084 UINT4 refineby,
1085 UINT4 Dterms
1086 )
1087{
1088 UINT4 newLen, oldLen, l;
1089 COMPLEX8Vector *ret = NULL;
1090
1091 if ( !in ) {
1092 return NULL;
1093 }
1094
1095 oldLen = in->length;
1096 newLen = oldLen * refineby;
1097
1098 /* the following are used to speed things up in the innermost loop */
1099 if ( ( ret = XLALCreateCOMPLEX8Vector( newLen ) ) == NULL ) {
1100 return NULL;
1101 }
1102
1103 for ( l = 0; l < newLen; l++ ) {
1104
1105 REAL8 kappa_l_k;
1106 REAL8 remain, kstarREAL;
1107 UINT4 kstar, kmin, kmax, k;
1108 REAL8 sink, coskm1;
1109 REAL8 Yk_re, Yk_im, Xd_re, Xd_im;
1110
1111 kstarREAL = 1.0 * l / refineby;
1112 kstar = lround( kstarREAL ); /* round to closest bin */
1113 kstar = MYMIN( kstar, oldLen - 1 ); /* stay within the old SFT index-bounds */
1114 remain = kstarREAL - kstar;
1115
1116 /* boundaries for innermost loop */
1117 kmin = MYMAX( 0, ( INT4 )kstar - ( INT4 )Dterms );
1118 kmax = MYMIN( oldLen, kstar + Dterms );
1119
1120 Yk_re = Yk_im = 0;
1121 if ( fabs( remain ) > 1e-5 ) { /* denominater doens't vanish */
1122 /* Optimization: sin(2pi*kappa(l,k)) = sin(2pi*kappa(l,0) and idem for cos */
1123 sink = sin( LAL_TWOPI * remain );
1124 coskm1 = cos( LAL_TWOPI * remain ) - 1.0;
1125
1126 /* ---------- innermost loop: k over 2*Dterms around kstar ---------- */
1127 for ( k = kmin; k < kmax; k++ ) {
1128 REAL8 Plk_re, Plk_im;
1129
1130 Xd_re = crealf( in->data[k] );
1131 Xd_im = cimagf( in->data[k] );
1132
1133 kappa_l_k = kstarREAL - k;
1134
1135 Plk_re = sink / kappa_l_k;
1136 Plk_im = coskm1 / kappa_l_k;
1137
1138 Yk_re += Plk_re * Xd_re - Plk_im * Xd_im;
1139 Yk_im += Plk_re * Xd_im + Plk_im * Xd_re;
1140
1141 } /* hotloop over Dterms */
1142 } else { /* kappa -> 0: Plk = 2pi delta(k, l) */
1143 Yk_re = LAL_TWOPI * crealf( in->data[kstar] );
1144 Yk_im = LAL_TWOPI * cimagf( in->data[kstar] );
1145 }
1146
1147 ret->data[l] = crectf( OOTWOPI * Yk_re, OOTWOPI * Yk_im );
1148
1149 } /* for l < newlen */
1150
1151 return ret;
1152
1153} /* XLALrefineCOMPLEX8Vector() */
1154
1155/// @}
int j
int k
#define MYMIN(x, y)
Definition: LFTandTSutils.c:39
#define LD_SMALL4
Definition: LFTandTSutils.c:47
static LALUnit emptyLALUnit
Definition: LFTandTSutils.c:49
#define OOPI
Definition: LFTandTSutils.c:46
#define cRELERR(x, y)
Definition: LFTandTSutils.c:43
#define MYMAX(x, y)
Definition: LFTandTSutils.c:38
#define SQ(x)
Definition: LFTandTSutils.c:40
#define fRELERR(x, y)
Definition: LFTandTSutils.c:44
#define FINITE_OR_ONE(x)
Definition: LFTandTSutils.c:42
#define OOTWOPI
Definition: LFTandTSutils.c:45
REAL8 tol
const char * names[]
int l
double e
coeffs k0
coeffs k1
COMPLEX8FFTPlan * XLALCreateReverseCOMPLEX8FFTPlan(UINT4 size, int measurelvl)
COMPLEX8FFTPlan * XLALCreateForwardCOMPLEX8FFTPlan(UINT4 size, int measurelvl)
int XLALCOMPLEX8VectorFFT(COMPLEX8Vector *_LAL_RESTRICT_ output, const COMPLEX8Vector *_LAL_RESTRICT_ input, const COMPLEX8FFTPlan *plan)
void XLALDestroyCOMPLEX8FFTPlan(COMPLEX8FFTPlan *plan)
static const REAL8 LAL_FACT_INV[]
#define LAL_PI
#define LAL_TWOPI
unsigned char BOOLEAN
#define XLAL_NUM_ELEM(x)
uint64_t UINT8
double complex COMPLEX16
double REAL8
#define XLAL_INIT_DECL(var,...)
int64_t INT8
#define crectf(re, im)
uint32_t UINT4
float complex COMPLEX8
int32_t INT4
float REAL4
#define lalDebugLevel
LALINFO
void * XLALMalloc(size_t n)
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
SFTtype * XLALSFTVectorToLFT(SFTVector *sfts, REAL8 upsampling)
Turn the given multi-IFO SFTvectors into one long Fourier transform (LFT) over the total observation ...
Definition: LFTandTSutils.c:64
int XLALReorderFFTWtoSFT(COMPLEX8Vector *X)
Change frequency-bin order from fftw-convention to a 'SFT' ie.
MultiCOMPLEX8TimeSeries * XLALMultiSFTVectorToCOMPLEX8TimeSeries(const MultiSFTVector *multisfts)
Turn the given multiSFTvector into multiple long COMPLEX8TimeSeries, properly dealing with gaps.
int XLALSincInterpolateCOMPLEX8TimeSeries(COMPLEX8Vector *y_out, const REAL8Vector *t_out, const COMPLEX8TimeSeries *ts_in, UINT4 Dterms)
Interpolate a given regularly-spaced COMPLEX8 timeseries 'ts_in = x_in(j * dt)' onto new samples 'y_o...
#define NhalfNeg(N)
Definition: LFTandTSutils.h:47
int XLALFrequencyShiftMultiCOMPLEX8TimeSeries(MultiCOMPLEX8TimeSeries *x, const REAL8 shift)
Multi-detector wrapper for XLALFrequencyShiftCOMPLEX8TimeSeries NOTE: this modifies the MultiCOMPLEX8...
int XLALTimeShiftSFT(SFTtype *sft, REAL8 shift)
Time-shift the given SFT by an amount of 'shift' seconds, using the frequency-domain expression ,...
int XLALFrequencyShiftCOMPLEX8TimeSeries(COMPLEX8TimeSeries *x, const REAL8 shift)
Freq-shift the given COMPLEX8Timeseries by an amount of 'shift' Hz, using the time-domain expression ...
COMPLEX8TimeSeries * XLALSFTVectorToCOMPLEX8TimeSeries(const SFTVector *sftsIn)
Turn the given SFTvector into one long time-series, properly dealing with gaps.
int XLALCopyMultiCOMPLEX8TimeSeries(MultiCOMPLEX8TimeSeries *multiTimesOut, MultiCOMPLEX8TimeSeries *multiTimesIn)
Copies a MultiCOMPLEX8TimeSeries structure, output must be allocated of identical size as input!
int XLALCheckVectorComparisonTolerances(const VectorComparison *result, const VectorComparison *tol)
Check VectorComparison result against specified tolerances, to allow for standardized comparison and ...
int XLALReorderSFTtoFFTW(COMPLEX8Vector *X)
Change frequency-bin order from 'SFT' to fftw-convention ie.
int XLALCompareREAL4Vectors(VectorComparison *result, const REAL4Vector *x, const REAL4Vector *y, const VectorComparison *tol)
Compare two REAL4 vectors using various different comparison metrics.
int XLALCompareCOMPLEX8Vectors(VectorComparison *result, const COMPLEX8Vector *x, const COMPLEX8Vector *y, const VectorComparison *tol)
Compare two COMPLEX8 vectors using various different comparison metrics.
COMPLEX8TimeSeries * XLALDuplicateCOMPLEX8TimeSeries(COMPLEX8TimeSeries *ttimes)
Duplicates a COMPLEX8TimeSeries structure.
int XLALSpinDownCorrectionMultiTS(MultiCOMPLEX8TimeSeries *multiTimeSeries, const PulsarDopplerParams *doppler)
Apply a spin-down correction to the complex8 timeseries using the time-domain expression y(t) = x(t) ...
MultiCOMPLEX8TimeSeries * XLALDuplicateMultiCOMPLEX8TimeSeries(MultiCOMPLEX8TimeSeries *multiTimes)
Duplicates a MultiCOMPLEX8TimeSeries structure.
#define NhalfPosDC(N)
Definition: LFTandTSutils.h:46
int XLALCopyCOMPLEX8TimeSeries(COMPLEX8TimeSeries *ts_out, COMPLEX8TimeSeries *ts_in)
Copies a COMPLEX8TimeSeries structure, output must be allocated of identical size as input!
SFTtype * XLALSincInterpolateSFT(const SFTtype *sft_in, REAL8 f0Out, REAL8 dfOut, UINT4 numBinsOut, UINT4 Dterms)
(Complex)Sinc-interpolate an input SFT to an output SFT.
int XLALSincInterpolateCOMPLEX8FrequencySeries(COMPLEX8Vector *y_out, const REAL8Vector *f_out, const COMPLEX8FrequencySeries *fs_in, UINT4 Dterms)
Interpolate a given regularly-spaced COMPLEX8 frequency-series 'fs_in = x_in( k * df)' onto new sampl...
COMPLEX8Vector * XLALrefineCOMPLEX8Vector(const COMPLEX8Vector *in, UINT4 refineby, UINT4 Dterms)
Interpolate frequency-series to newLen frequency-bins.
void XLALDestroyMultiCOMPLEX8TimeSeries(MultiCOMPLEX8TimeSeries *multiTimes)
Destroy a MultiCOMPLEX8TimeSeries structure.
#define PULSAR_MAX_SPINS
maximal number of spin-parameters (Freq + spindowns) we can handle
SFTtype * XLALCreateSFT(UINT4 numBins)
XLAL function to create one SFT-struct.
Definition: SFTtypes.c:152
SFTVector * XLALDuplicateSFTVector(const SFTVector *sftsIn)
Create a complete copy of an SFT vector.
Definition: SFTtypes.c:328
void XLALDestroySFTVector(SFTVector *vect)
XLAL interface to destroy an SFTVector.
Definition: SFTtypes.c:300
int XLALSinCosLUT(REAL4 *sinx, REAL4 *cosx, REAL8 x)
Calculate sin(x) and cos(x) to roughly 1e-7 precision using a lookup-table and Taylor-expansion.
Definition: SinCosLUT.c:83
int XLALSinCos2PiLUT(REAL4 *sin2pix, REAL4 *cos2pix, REAL8 x)
Calculate sin(2*pi*x) and cos(2*pi*x) to roughly 1e-7 precision using a lookup-table and Taylor-expan...
Definition: SinCosLUT.c:97
int XLALSinCos2PiLUTtrimmed(REAL4 *s, REAL4 *c, REAL8 x)
A function that uses the lookup tables to evaluate sin and cos values of 2*Pi*x, but relies on x bein...
Definition: SinCosLUT.c:112
COMPLEX8TimeSeries * XLALCreateCOMPLEX8TimeSeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaT, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX8TimeSeries(COMPLEX8TimeSeries *series)
COMPLEX8Vector * XLALCreateCOMPLEX8Vector(UINT4 length)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
REAL8Window * XLALCreateHammingREAL8Window(UINT4 length)
void XLALDestroyREAL8Window(REAL8Window *window)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_NULL(assertion,...)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFPINVAL
XLAL_EFUNC
XLAL_ETOL
XLAL_EDOM
XLAL_EINVAL
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
REAL8 XLALGPSGetREAL8(const LIGOTimeGPS *epoch)
REAL8 XLALGPSDiff(const LIGOTimeGPS *t1, const LIGOTimeGPS *t0)
list y
end
n
out
int N
size_t numDetectors
CHAR name[LALNameLength]
COMPLEX8Sequence * data
A vector of COMPLEX8FrequencySeries.
COMPLEX8FrequencySeries * data
Pointer to the data array.
UINT4 length
Number of elements in array.
LIGOTimeGPS epoch
COMPLEX8Sequence * data
COMPLEX8 * data
Multi-IFO container for COMPLEX8 resampled timeseries.
Definition: LFTandTSutils.h:52
COMPLEX8TimeSeries ** data
array of COMPLEX8TimeSeries (pointers)
Definition: LFTandTSutils.h:57
UINT4 length
number of IFOs
Definition: LFTandTSutils.h:56
A collection of SFT vectors – one for each IFO in a multi-IFO search.
Definition: SFTfileIO.h:179
UINT4 length
number of ifos
Definition: SFTfileIO.h:183
SFTVector ** data
sftvector for each ifo
Definition: SFTfileIO.h:184
Type containing the 'Doppler-parameters' affecting the time-evolution of the phase.
PulsarSpins fkdot
Intrinsic spins: [Freq, f1dot, f2dot, ... ] where fkdot = d^kFreq/dt^k.
LIGOTimeGPS refTime
Reference time of pulsar parameters (in SSB!)
REAL8 * data
Struct holding the results of comparing two floating-point vectors (real-valued or complex),...
Definition: LFTandTSutils.h:64
REAL4 relErr_L2
relative error between vectors using L2 norm
Definition: LFTandTSutils.h:66
REAL4 angleV
angle between the two vectors, according to
Definition: LFTandTSutils.h:67
REAL4 relErr_L1
relative error between vectors using L1 norm
Definition: LFTandTSutils.h:65
REAL4 relErr_atMaxAbsy
single-sample relative error at maximum |sample-value| of second vector 'x'
Definition: LFTandTSutils.h:69
REAL4 relErr_atMaxAbsx
single-sample relative error at maximum |sample-value| of first vector 'x'
Definition: LFTandTSutils.h:68
enum @1 epoch
double deltaT
double df