00001 /* 00002 * Copyright (C) 2004, 2005 Reinhard Prix 00003 * Copyright (C) 2004, 2005 Greg Mendell 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with with program; see the file COPYING. If not, write to the 00017 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00018 * MA 02111-1307 USA 00019 */ 00020 00021 /** 00022 * \defgroup moduleGeneratePulsarSignal Pulsar-signal generation 00023 * \ingroup inject 00024 * \brief Pulsar signal-generation routines for hardware- and software-injections. 00025 * 00026 00027 * \par Description 00028 * 00029 * - The main function LALGeneratePulsarSignal() generates a fake 00030 * pulsar-signal, either for an isolated or a binary pulsar. It returns a 00031 * time-series with the generated signal as received by the detector. 00032 * 00033 * - The time-series can then be turned into a vector of short time-base FFTs 00034 * (the so-called "SFTs") by using the function LALSignalToSFTs(). 00035 * These SFTs are the data-format used by most frequency-domain pulsar codes, 00036 * therefore these functions can be directly used in a Monte-Carlo 00037 * injection driver. 00038 * 00039 * This module also contains a few more general-purpose helper-functions: 00040 * 00041 * 00042 * - Namely, LALConvertSSB2GPS() and LALConvertGPS2SSB() 00043 * which convert arrival times for a given source (not necessarily a 00044 * pulsar!) the detector ("GPS") and the solar-system barycenter ("SSB"). 00045 * NOTE: only the source-location (<tt>params->pulsar.position</tt>), the 00046 * detector-site (<tt>params->site</tt>) and the ephemeris-data 00047 * (<tt>params->ephemerides</tt>)are used from the 00048 * PulsarSignalParams structure. 00049 * 00050 * 00051 * \par Algorithm: 00052 * 00053 * LALGeneratePulsarSignal() is basically a wrapper for the two 00054 * LAL-functions GenerateSpinOrbitCW() to produce the source-signal, 00055 * and LALSimulateCoherentGW() to turn it into a time-series at the detector. 00056 * 00057 * LALSignalToSFTs() uses LALForwardRealFFT() appropriately on the input-timeseries to 00058 * produce the required output-SFTs ( v2-normalization! ). 00059 * 00060 * 00061 * \note 00062 * 00063 * LALSignalToSFTs() currently enforces the constraint of 00064 * <tt>Tsft * Band</tt> being an integer, so that the number of 00065 * time-samples per SFT is even. This follows <tt>makefakedata_v2</tt>. 00066 * 00067 * Furthermore, if the timestamps for SFT-creation passed to 00068 * LALSignalToSFTs() do not fit exactly on a time-step of the 00069 * input time-series, it will be "nudged" to the closest one. 00070 * If <tt>lalDebugLevel>0</tt> a warning will be printed about this. 00071 * The user could also see this effect in the actual timestamps of the 00072 * SFTs returned. 00073 * 00074 * 00075 * The FFTW-"plan" is currently created using the \c ESTIMATE flag, 00076 * which is fast but only yields an approximate plan. Better results 00077 * might be achieved by using \c MEASURE and an appropriate buffering 00078 * of the resulting plan (which doesnt change provided the SFT-length is 00079 * the same). Measuring the plan takes longer but might lead to 00080 * substantial speedups for many FFTs, which seems the most likely situation. 00081 * 00082 * 00083 * 00084 * \par Use of LALFastGeneratePulsarSFTs() 00085 * 00086 The functions LALComputeSkyAndZeroPsiAMResponse() and LALFastGeneratePulsarSFTs() 00087 use approximate analytic formulas to generate SFTs. This should be significantly 00088 faster than LALGeneratePulsarSignal() and LALSignalToSFTs(), which generate the 00089 time series data and then FFT it. Simple tests performed by the code in 00090 GeneratePulsarSignalTest.c indicate that the maximum modulus of the SFTs output 00091 by the approximate and exact codes differs by less that 10\%. Since the tests 00092 are not exhaustive, the user should use caution and conduct their own test 00093 to compare LALComputeSkyAndZeroPsiAMResponse() and LALFastGeneratePulsarSFTs() with 00094 LALGeneratePulsarSignal() and LALSignalToSFTs(). 00095 00096 The strain of a periodic signal at the detector is given by 00097 \f[ 00098 h(t) = F_+(t) A_+ {\rm cos}\Phi(t) + F_\times(t) A_\times {\rm sin}\Phi(t), 00099 \f] 00100 where \f$F_+\f$ and \f$F_\times\f$ are the usual beam pattern response functions, 00101 \f$A_+\f$ and \f$A_\times\f$ are the amplitudes of the gravitational wave for the 00102 plus and cross polarizations, and \f$\Phi\f$ is the phase. The phase contains modulations 00103 from doppler shifts due to the relative motion between the source and the 00104 detector and the spin evolution of the source. (The functions discussed here 00105 support both isolated sources and those in binary systems. The binary case 00106 has not been tested.) 00107 00108 If we Taylor expand the phase out to first order about the time at the midpoint of 00109 an SFT and approximate \f$F_+\f$ and \f$F_\times\f$ as constants, for one SFT we can write 00110 \f[ 00111 \Phi(t) \approx \Phi_{1/2} + 2\pi f_{1/2}(t - t_{1/2}). 00112 \f] 00113 The strain at discrete time \f$t_j\f$, measured from the start of the SFT, can 00114 thus be approximated as 00115 \f[ 00116 h_j \approx F_{+ 1/2} A_+ {\rm cos} [\Phi_{1/2} + 2\pi f_{1/2}(t_0 + t_j - t_{1/2})] 00117 + F_{\times 1/2} A_\times {\rm sin} [\Phi_{1/2} + 2\pi f_{1/2}(t_0 + t_j - t_{1/2})], 00118 \f] 00119 where \f$t_0\f$ is the time as the start of the SFT, and \f$t_{1/2} - t_0 = T_{\rm sft}/2\f$, 00120 where \f$T_{\rm sft}\f$ is the duration of one SFT. This simplifies to 00121 \f[ 00122 h_j \approx F_{+ 1/2} A_+ {\rm cos} (\Phi_0 + 2\pi f_{1/2}t_j) 00123 + F_{\times 1/2} A_\times {\rm sin} (\Phi_0 + 2\pi f_{1/2}t_j), 00124 \f] 00125 where \f$\Phi_0\f$ is the phase at the start of the SFT 00126 (not the initial phase at the start of the observation), i.e., 00127 \f[ 00128 \Phi_0 = \Phi_{1/2} - 2 \pi f_{1/2} (T_{\rm sft} / 2). 00129 \f] 00130 Note that these are the same approximations used by LALDemod(). 00131 00132 One can show that the Discrete Fourier Transform (DFT) of \f$h_j\f$ above is: 00133 \f[ 00134 \tilde{h}_k = e^{i\Phi_0} { ( F_{+ 1/2} A_+ - i F_{\times 1/2} A_\times) \over 2 } 00135 { 1 - e^{2\pi i (\kappa - k)} \over 1 - e^{2\pi i (\kappa - k)/N} } 00136 \\ 00137 + e^{-i\Phi_0} { ( F_{+ 1/2} A_+ + i F_{\times 1/2} A_\times) \over 2 } 00138 { 1 - e^{-2\pi i (\kappa + k)} \over 1 - e^{-2\pi i (\kappa + k)/N} } 00139 \f] 00140 where \f$N\f$ is the number of time samples used to find the 00141 DFT (i.e., the sample rate times \f$T_{\rm sft}\f$), and 00142 \f[ 00143 \kappa \equiv f_{1/2} T_{\rm sft}, 00144 \f] 00145 is usually not an integer. 00146 00147 Note that the factor \f$e^{\pm 2\pi i k}\f$ in the numerators of the equation for \f$\tilde{h}_k\f$ 00148 equals 1. Furthermore, for \f$0 < \kappa < N/2\f$ and \f$|\kappa - k| << N\f$ the first term 00149 dominates and can be Taylor expanded to give: 00150 \f[ 00151 \tilde{h}_k = N e^{i\Phi_0} { ( F_{+ 1/2} A_+ - i F_{\times 1/2} A_\times) \over 2 } 00152 \left [ \, { {\rm sin} (2\pi\kappa) \over 2 \pi (\kappa - k) } \, 00153 + \, i { 1 - {\rm cos} (2\pi\kappa) \over 2 \pi (\kappa - k) } \, \right ] 00154 \f] 00155 Note that the last factor in square brackets is \f$P_{\alpha k}^*\f$ and 00156 \f$e^{i\Phi_0} = Q_{\alpha}^*\f$ used by LALDemod. 00157 00158 \par Example pseudocode 00159 00160 The structs used by LALComputeSkyAndZeroPsiAMResponse and LALFastGeneratePulsarSFTs 00161 are given in previous sections, and make use of those used by 00162 LALGeneratePulsarSignal and LALSignalToSFTs plus a small number of 00163 additional parameters. Thus it is fairly easy to change between the above 00164 approximate routines the exact routines. See GeneratePulsarSignalTest.c for 00165 an example implementation of the code. 00166 00167 Note that one needs to call LALComputeSkyAndZeroPsiAMResponse once per sky position, 00168 and then call LALFastGeneratePulsarSFTs for each set of signal parameters at that 00169 sky position. Thus, one could perform a Monte Carlo simulation, as shown 00170 by the pseudo code: 00171 00172 \code 00173 loop over sky positions { 00174 ... 00175 LALComputeSkyAndZeroPsiAMResponse(); 00176 ... 00177 loop over spindown { 00178 ... 00179 loop over frequencies { 00180 ... 00181 LALFastGeneratePulsarSFTs(); 00182 ... 00183 } 00184 ... 00185 } 00186 ... 00187 } 00188 00189 \endcode 00190 00191 \par Notes on LALFastGeneratePulsarSFTs 00192 00193 -# If \c *outputSFTs sent to LALFastGeneratePulsarSFTs() is \c NULL then 00194 LALFastGeneratePulsarSFTs() allocates memory for the output SFTs; otherwise it assumes 00195 memory has already been allocated. Thus, the user does not have to deallocate 00196 memory for the SFTs until all calls to LALFastGeneratePulsarSFTs() are completed. 00197 00198 -# \c fHeterodyne and <tt>0.5 * samplingRate</tt> set in the PulsarSignalParams struct 00199 give the start frequency and frequency band of the SFTs output from LALFastGeneratePulsarSFTs(). 00200 00201 -# If \c resTrig is set to zero in the SFTandSignalParams struct, then 00202 the C math libary \c cos() \c sin() functions are called, else lookup tables (LUTs) are used 00203 for calls to trig functions. There may be a slight speedup in using LUTs. 00204 00205 -# To maximize the speed of SFT generations, LALFastGeneratePulsarSFTs() only generates 00206 values for the bins in the band <tt>2*Dterms</tt> centered on the signal frequency in each SFT. Dterms must be 00207 greater than zero and less than or equal to the number of frequency bins in the output SFTs. Note that 00208 Dterms is used the same way here as it is in LALDemod(). Nothing is done to the other bins, unless 00209 \c *outputSFTs is \c NULL; then, since memory is allocates for the output SFTs, the bins 00210 not in the <tt>2*Dterms</tt> band are initialized to zero. 00211 00212 */ 00213 00214 00215 /** 00216 * \author Reinhard Prix, Greg Mendell 00217 * \date 2005 00218 * \file 00219 * \ingroup moduleGeneratePulsarSignal 00220 * \brief API for GeneratePulsarSignal.c 00221 * 00222 * $Id: GeneratePulsarSignal.h,v 1.24 2008/08/14 18:09:08 evang Exp $ 00223 */ 00224 00225 /* NOTES: */ 00226 /* 07/14/04 gam; add functions LALFastGeneratePulsarSFTs and LALComputeSkyAndZeroPsiAMResponse */ 00227 /* 10/08/04 gam; fix indexing into trig lookup tables (LUTs) by having table go from -2*pi to 2*pi */ 00228 /* 09/07/05 gam; Add Dterms parameter to LALFastGeneratePulsarSFTs; use this to fill in SFT bins with fake data as per LALDemod else fill in bin with zero */ 00229 00230 #ifndef _GENERATEPULSARSIGNAL_H /* Double-include protection. */ 00231 #define _GENERATEPULSARSIGNAL_H 00232 00233 #include <lal/LALDatatypes.h> 00234 #include <lal/DetResponse.h> 00235 #include <lal/DetectorSite.h> 00236 #include <lal/GenerateSpinOrbitCW.h> 00237 #include <lal/Date.h> 00238 #include <lal/LALBarycenter.h> 00239 #include <lal/PulsarDataTypes.h> 00240 #include <lal/ComputeSky.h> 00241 #include <lal/ComputeSkyBinary.h> 00242 #include <lal/Window.h> 00243 00244 /* C++ protection. */ 00245 #ifdef __cplusplus 00246 extern "C" { 00247 #endif 00248 00249 NRCSID( GENERATEPULSARSIGNALH, "$Id: GeneratePulsarSignal.h,v 1.24 2008/08/14 18:09:08 evang Exp $"); 00250 00251 /** \name Error codes */ 00252 /*@{*/ 00253 #define GENERATEPULSARSIGNALH_ENULL 1 00254 #define GENERATEPULSARSIGNALH_ENONULL 2 00255 #define GENERATEPULSARSIGNALH_EMEM 3 00256 #define GENERATEPULSARSIGNALH_ESAMPLING 4 00257 #define GENERATEPULSARSIGNALH_ESSBCONVERT 5 00258 #define GENERATEPULSARSIGNALH_ESYS 6 00259 #define GENERATEPULSARSIGNALH_ETIMEBOUND 7 00260 #define GENERATEPULSARSIGNALH_ENUMSFTS 8 00261 #define GENERATEPULSARSIGNALH_EINCONSBAND 9 00262 #define GENERATEPULSARSIGNALH_ENOISEDELTAF 10 00263 #define GENERATEPULSARSIGNALH_ENOISEBAND 11 00264 #define GENERATEPULSARSIGNALH_ENOISEBINS 12 00265 #define GENERATEPULSARSIGNALH_EBADCOORDS 13 00266 #define GENERATEPULSARSIGNALH_ELUTS 14 00267 #define GENERATEPULSARSIGNALH_EDTERMS 15 00268 #define GENERATEPULSARSIGNALH_EINPUT 16 00269 #define GENERATEPULSARSIGNALH_EDETECTOR 17 00270 00271 #define GENERATEPULSARSIGNALH_MSGENULL "Arguments contained an unexpected null pointer" 00272 #define GENERATEPULSARSIGNALH_MSGENONULL "Output pointer is not NULL" 00273 #define GENERATEPULSARSIGNALH_MSGEMEM "Out of memory" 00274 #define GENERATEPULSARSIGNALH_MSGESAMPLING "Waveform sampling interval too large." 00275 #define GENERATEPULSARSIGNALH_MSGESSBCONVERT "SSB->GPS iterative conversion failed" 00276 #define GENERATEPULSARSIGNALH_MSGESYS "System error, probably while File I/O" 00277 #define GENERATEPULSARSIGNALH_MSGETIMEBOUND "Timestamp outside of allowed time-interval" 00278 #define GENERATEPULSARSIGNALH_MSGENUMSFTS "Inconsistent number of SFTs in timestamps and noise-SFTs" 00279 #define GENERATEPULSARSIGNALH_MSGEINCONSBAND "Inconsistent values of sampling-rate and Tsft" 00280 #define GENERATEPULSARSIGNALH_MSGENOISEDELTAF "Frequency resolution of noise-SFTs inconsistent with signal" 00281 #define GENERATEPULSARSIGNALH_MSGENOISEBAND "Frequency band of noise-SFTs inconsistent with signal" 00282 #define GENERATEPULSARSIGNALH_MSGENOISEBINS "Frequency bins of noise-SFTs inconsistent with signal" 00283 #define GENERATEPULSARSIGNALH_MSGEBADCOORDS "Current code requires sky position in equatorial coordinates" 00284 #define GENERATEPULSARSIGNALH_MSGELUTS "Lookup tables (LUTs) for trig functions must be defined on domain -2pi to 2pi inclusive" 00285 #define GENERATEPULSARSIGNALH_MSGEDTERMS "Dterms must be greater than zero and less than or equal to half the number of SFT bins" 00286 #define GENERATEPULSARSIGNALH_MSGEINPUT "Invalid input-arguments to function" 00287 #define GENERATEPULSARSIGNALH_MSGEDETECTOR "Unknown detector-name" 00288 /*@}*/ 00289 00290 00291 /** Input parameters to GeneratePulsarSignal(), defining the source and the time-series 00292 */ 00293 typedef struct { 00294 /* source-parameters */ 00295 PulsarSourceParams pulsar; /**< the actual pulsar-source */ 00296 BinaryOrbitParams *orbit; /**< and its binary orbit (NULL if isolated pulsar) */ 00297 00298 /* characterize the detector */ 00299 COMPLEX8FrequencySeries *transfer; /**< detector transfer function (NULL if not used) */ 00300 LALDetector *site; /**< detector location and orientation */ 00301 EphemerisData *ephemerides; /**< Earth and Sun ephemerides */ 00302 00303 /* characterize the output time-series */ 00304 LIGOTimeGPS startTimeGPS; /**< start time of output time series */ 00305 UINT4 duration; /**< length of time series in seconds */ 00306 REAL8 samplingRate; /**< sampling rate of time-series (= 2 * frequency-Band) */ 00307 REAL8 fHeterodyne; /**< heterodyning frequency for output time-series */ 00308 } PulsarSignalParams; 00309 00310 /** Parameters defining the SFTs to be returned from LALSignalToSFTs(). 00311 */ 00312 typedef struct { 00313 REAL8 Tsft; /**< length of each SFT in seconds */ 00314 LIGOTimeGPSVector *timestamps; /**< timestamps to produce SFTs for (can be NULL) */ 00315 SFTVector *noiseSFTs; /**< noise SFTs to be added (can be NULL) */ 00316 INT4 make_v2SFTs; /**< UPGRADING switch: should be set to 1 to avoid verbose complaints */ 00317 REAL4Window *window; /**< window function for the time series (can be NULL) */ 00318 } SFTParams; 00319 00320 /** Parameters defining the pulsar signal and SFTs used by LALFastGeneratePulsarSFTs(). Lookup tables (LUTs) are 00321 * used for trig functions if \code resTrig > 0 \endcode the user must then initialize \c trigArg, \c sinVal, and 00322 * \c cosVal on the domain \f$[-2\pi, 2\pi]\f$ inclusive. See GeneratePulsarSignalTest.c for an example. 00323 */ 00324 typedef struct { 00325 PulsarSignalParams *pSigParams; 00326 SFTParams *pSFTParams; 00327 INT4 nSamples; /**< nsample from noise SFT header; 2x this equals effective number of time samples */ 00328 INT4 Dterms; /**< use this to fill in SFT bins with fake data as per LALDemod else fill in bin with zero */ 00329 INT4 resTrig; /**< length sinVal, cosVal; domain: -2pi to 2pi; resolution = 4pi/resTrig */ 00330 REAL8 *trigArg; /**< array of arguments to hold lookup table (LUT) values for doing trig calls */ 00331 REAL8 *sinVal; /**< sinVal holds lookup table (LUT) values for doing trig sin calls */ 00332 REAL8 *cosVal; /**< cosVal holds lookup table (LUT) values for doing trig cos calls */ 00333 } SFTandSignalParams; 00334 00335 00336 /** Sky Constants and beam pattern response functions used by LALFastGeneratePulsarSFTs(). 00337 * These are output from LALComputeSkyAndZeroPsiAMResponse(). 00338 */ 00339 typedef struct { 00340 REAL8 *skyConst; /**< vector of A and B sky constants */ 00341 REAL4 *fPlusZeroPsi; /**< vector of Fplus values for psi = 0 at midpoint of each SFT */ 00342 REAL4 *fCrossZeroPsi; /**< vector of Fcross values for psi = 0 at midpoint of each SFT */ 00343 } SkyConstAndZeroPsiAMResponse; 00344 00345 /*---------- Global variables ----------*/ 00346 /* empty init-structs for the types defined in here */ 00347 extern const PulsarSignalParams empty_PulsarSignalParams; 00348 extern const SFTParams empty_SFTParams; 00349 extern const SFTandSignalParams empty_SFTandSignalParams; 00350 00351 00352 /* Function prototypes */ 00353 void LALGeneratePulsarSignal (LALStatus *, REAL4TimeSeries **signal, const PulsarSignalParams *params); 00354 void LALSimulateExactPulsarSignal (LALStatus *, REAL4TimeSeries **timeSeries, const PulsarSignalParams *params); 00355 00356 void LALSignalToSFTs (LALStatus *, SFTVector **outputSFTs, const REAL4TimeSeries *signal, const SFTParams *params); 00357 00358 void LALComputeSkyAndZeroPsiAMResponse (LALStatus *, SkyConstAndZeroPsiAMResponse *output, const SFTandSignalParams *params); 00359 void LALFastGeneratePulsarSFTs (LALStatus *, SFTVector **outputSFTs, const SkyConstAndZeroPsiAMResponse *input, const SFTandSignalParams *params); 00360 00361 void LALConvertGPS2SSB (LALStatus* , LIGOTimeGPS *SSBout, LIGOTimeGPS GPSin, const PulsarSignalParams *params); 00362 void LALConvertSSB2GPS (LALStatus *, LIGOTimeGPS *GPSout, LIGOTimeGPS GPSin, const PulsarSignalParams *params); 00363 00364 #ifdef __cplusplus 00365 } 00366 #endif 00367 /* C++ protection. */ 00368 00369 #endif /* Double-include protection. */
1.5.2