GeneratePulsarSignal.h

Go to the documentation of this file.
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. */

Generated on Sun Oct 12 02:31:54 2008 for LAL by  doxygen 1.5.2