/**
 * \deprecated Use XLALGetDetectorStates() instead
 */
void
LALGetDetectorStates (LALStatus *status,			/**< pointer to LALStatus structure */
		      DetectorStateSeries **DetectorStates,	/**< [out] series of DetectorStates */
		      const LIGOTimeGPSVector *timestamps,	/**< array of GPS timestamps t_i */
		      const LALDetector *detector,		/**< detector info */
		      const EphemerisData *edat,		/**< ephemeris file data */
		      REAL8 tOffset				/**< compute detector states at timestamps SHIFTED by tOffset */
		      )
{
  INITSTATUS(status);

  ASSERT ( DetectorStates != NULL, status,  DETECTORSTATES_ENULL, DETECTORSTATES_MSGENULL);
  ASSERT ( *DetectorStates == NULL, status,  DETECTORSTATES_ENONULL, DETECTORSTATES_MSGENONULL);

  ASSERT ( timestamps, status, DETECTORSTATES_ENULL, DETECTORSTATES_MSGENULL);
  ASSERT ( detector, status, DETECTORSTATES_ENULL, DETECTORSTATES_MSGENULL);
  ASSERT ( edat, status, DETECTORSTATES_ENULL, DETECTORSTATES_MSGENULL);

  /* call XLAL function */
  DetectorStateSeries *ret = NULL;
  if ( ( ret = XLALGetDetectorStates ( timestamps, detector, edat, tOffset )) == NULL ) {
    XLALPrintError ("%s: XLALGetDetectorStates() failed with code=%d\n", __func__, xlalErrno );
    ABORT ( status, DETECTORSTATES_EXLAL, DETECTORSTATES_MSGEXLAL );
  }

  /* return result */
  (*DetectorStates) = ret;

  RETURN (status);

} /* LALGetDetectorStates() */
Esempio n. 2
0
/**
 * Get the detector-time series for the given MultiLIGOTimeGPSVector.
 * NOTE: contrary to the deprecated XLALGetMultiDetectorStatesFromMultiSFTs() interface, this
 * function computes detector-states at the given timestamps shifted by tOffset
 *
 */
MultiDetectorStateSeries *
XLALGetMultiDetectorStates( const MultiLIGOTimeGPSVector *multiTS, /**< [in] multi-IFO timestamps */
                            const MultiLALDetector *multiIFO, 	   /**< [in] multi-IFO array holding detector info */
                            const EphemerisData *edat,		   /**< [in] ephemeris data */
                            REAL8 tOffset			   /**< [in] shift all timestamps by this amount */
                            )
{
  /* check input consistency */
  if ( !multiIFO || !multiTS || !edat ) {
    XLALPrintError ("%s: invalid NULL input (multiIFO=%p, multiTS=%p or edat=%p)\n", __func__, multiIFO, multiTS, edat );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  UINT4 numDetectors;
  numDetectors = multiIFO->length;
  if ( numDetectors != multiTS->length ) {
    XLALPrintError ("%s: inconsistent number of IFOs in 'multiIFO' (%d) and 'multiTS' (%d)\n", __func__, multiIFO->length, multiTS->length );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  /* prepare return-structure */
  MultiDetectorStateSeries *ret = NULL;
  if ( ( ret = LALCalloc ( 1, sizeof( *ret ) )) == NULL ) {
    XLALPrintError ("%s: LALCalloc ( 1, %zu ) failed\n", __func__, sizeof(*ret) );
    XLAL_ERROR_NULL ( XLAL_ENOMEM );
  }
  if ( ( ret->data = LALCalloc ( numDetectors, sizeof( *(ret->data) ) )) == NULL ) {
    XLALFree ( ret );
    XLALPrintError ("%s: LALCalloc ( %d, %zu ) failed\n", __func__, numDetectors, sizeof(*(ret->data)) );
    XLAL_ERROR_NULL ( XLAL_ENOMEM );
  }
  ret->length = numDetectors;

  REAL8 t0=LAL_REAL4_MAX;
  REAL8 t1=0;
  REAL8 deltaT = multiTS->data[0]->deltaT;
  LIGOTimeGPS startTime = {0, 0};
  /* loop over detectors */
  UINT4 X;
  for ( X=0; X < numDetectors; X ++ )
    {
      LIGOTimeGPSVector *tsX = multiTS->data[X];
      const LALDetector *detX = &(multiIFO->sites[X]);

      if ( !tsX || !detX ) {
        XLALPrintError ("%s: invalid NULL data-vector tsX[%d] = %p, detX[%d] = %p\n", __func__, X, tsX, X, detX );
        XLAL_ERROR_NULL ( XLAL_EINVAL );
      }
      if ( multiTS->data[X]->deltaT != deltaT ) {
        XLALPrintError ("%s: inconsistent time-base multi-timeseries deltaT[%d]=%f  !=  deltaT[0] = %f\n", __func__, X, multiTS->data[X]->deltaT, deltaT );
        XLAL_ERROR_NULL ( XLAL_EINVAL );
      }

      /* fill in the detector-state series for this detector */
      if ( ( ret->data[X] = XLALGetDetectorStates ( tsX, detX, edat, tOffset )) == NULL ) {
        XLALPrintError ("%s: XLALGetDetectorStates() failed.\n", __func__ );
        XLAL_ERROR_NULL ( XLAL_EFUNC );
      }

      /* keep track of earliest/latest timestamp in order to determine total Tspan */
      UINT4 numTS = tsX->length;
      REAL8 t0_X = XLALGPSGetREAL8( &tsX->data[0] );
      REAL8 t1_X = XLALGPSGetREAL8( &tsX->data[numTS-1] );

      if ( t0_X < t0 ) {
        t0 = t0_X;
        startTime = tsX->data[0];
      }
      if ( t1_X > t1 ) t1 = t1_X;

    } /* for X < numDetectors */

  ret->Tspan = t1 - t0 + deltaT;	/* total time spanned by all SFTs */
  ret->startTime = startTime;		/* earliest start-time of observation */

  return ret;

} /* XLALGetMultiDetectorStates() */
int
main(int argc, char *argv[])
{
  LALStatus status = blank_status;

  ConfigVariables XLAL_INIT_DECL(config);
  UserVariables_t XLAL_INIT_DECL(uvar);

  /* register user-variables */

  XLAL_CHECK ( XLALInitUserVars ( &uvar ) == XLAL_SUCCESS, XLAL_EFUNC );

  /* read cmdline & cfgfile  */
  BOOLEAN should_exit = 0;
  XLAL_CHECK( XLALUserVarReadAllInput( &should_exit, argc, argv ) == XLAL_SUCCESS, XLAL_EFUNC );
  if ( should_exit ) {
    exit(1);
  }

  if ( uvar.version )
    {
      XLALOutputVersionString ( stdout, lalDebugLevel );
      exit(0);
    }

  /* basic setup and initializations */
  XLAL_CHECK ( XLALInitCode( &config, &uvar, argv[0] ) == XLAL_SUCCESS, XLAL_EFUNC );

  /* ----- allocate memory for AM-coeffs ----- */
  AMCoeffs AMold, AMnew1, AMnew2;	/**< containers holding AM-coefs computed by 3 different AM functions */
  AMold.a = XLALCreateREAL4Vector ( 1 );
  AMold.b = XLALCreateREAL4Vector ( 1 );
  AMnew1.a = XLALCreateREAL4Vector ( 1 );
  AMnew1.b = XLALCreateREAL4Vector ( 1 );
  AMnew2.a = XLALCreateREAL4Vector ( 1 );
  AMnew2.b = XLALCreateREAL4Vector ( 1 );

  XLAL_CHECK ( AMold.a && AMold.b && AMnew1.a && AMnew1.b && AMnew2.a && AMnew2.a, XLAL_ENOMEM, "Failed to XLALCreateREAL4Vector ( 1 )\n" );

  /* ----- get detector-state series ----- */
  DetectorStateSeries *detStates = NULL;
  XLAL_CHECK ( (detStates = XLALGetDetectorStates ( config.timestamps, config.det, config.edat, 0 )) != NULL, XLAL_EFUNC );

  /* ----- compute associated SSB timing info ----- */
  SSBtimes *tSSB = XLALGetSSBtimes ( detStates, config.skypos, config.timeGPS, SSBPREC_RELATIVISTIC );
  XLAL_CHECK ( tSSB != NULL, XLAL_EFUNC, "XLALGetSSBtimes() failed with xlalErrno = %d\n", xlalErrno );

  /* ===== 1) compute AM-coeffs the 'old way': [used in CFSv1] ===== */
  BarycenterInput XLAL_INIT_DECL(baryinput);
  AMCoeffsParams XLAL_INIT_DECL(amParams);
  EarthState earth;

  baryinput.site.location[0] = config.det->location[0]/LAL_C_SI;
  baryinput.site.location[1] = config.det->location[1]/LAL_C_SI;
  baryinput.site.location[2] = config.det->location[2]/LAL_C_SI;
  baryinput.alpha = config.skypos.longitude;
  baryinput.delta = config.skypos.latitude;
  baryinput.dInv = 0.e0;

  /* amParams structure to compute a(t) and b(t) */
  amParams.das = XLALMalloc(sizeof(*amParams.das));
  amParams.das->pSource = XLALMalloc(sizeof(*amParams.das->pSource));
  amParams.baryinput = &baryinput;
  amParams.earth = &earth;
  amParams.edat = config.edat;
  amParams.das->pDetector = config.det;
  amParams.das->pSource->equatorialCoords.longitude = config.skypos.longitude;
  amParams.das->pSource->equatorialCoords.latitude = config.skypos.latitude;
  amParams.das->pSource->orientation = 0.0;
  amParams.das->pSource->equatorialCoords.system = COORDINATESYSTEM_EQUATORIAL;
  amParams.polAngle = 0;

  LAL_CALL ( LALComputeAM ( &status, &AMold, config.timestamps->data, &amParams), &status);

  XLALFree ( amParams.das->pSource );
  XLALFree ( amParams.das );


  /* ===== 2) compute AM-coeffs the 'new way' using LALNewGetAMCoeffs() */
  LALGetAMCoeffs ( &status, &AMnew1, detStates, config.skypos );
  if ( status.statusCode ) {
    XLALPrintError ("%s: call to LALGetAMCoeffs() failed, status = %d\n\n", __func__, status.statusCode );
    XLAL_ERROR (  status.statusCode & XLAL_EFUNC );
  }

  /* ===== 3) compute AM-coeffs the 'newer way' using LALNewGetAMCoeffs() [used in CFSv2] */
  LALNewGetAMCoeffs ( &status, &AMnew2, detStates, config.skypos );
  if ( status.statusCode ) {
    XLALPrintError ("%s: call to LALNewGetAMCoeffs() failed, status = %d\n\n", __func__, status.statusCode );
    XLAL_ERROR (  status.statusCode & XLAL_EFUNC );
  }

  /* ===== 4) use standalone version of the above [used in FstatMetric_v2] */
  REAL8 a0,b0;
  if ( XLALComputeAntennaPatternCoeffs ( &a0, &b0, &config.skypos, &config.timeGPS, config.det, config.edat ) != XLAL_SUCCESS ) {
    XLALPrintError ("%s: XLALComputeAntennaPatternCoeffs() failed.\n", __func__ );
    XLAL_ERROR ( XLAL_EFUNC );
  }


  /* ==================== output the results ==================== */
  printf ("\n");
  printf ("----- Input parameters:\n");
  printf ("tGPS = { %d, %d }\n", config.timeGPS.gpsSeconds, config.timeGPS.gpsNanoSeconds );
  printf ("Detector = %s\n", config.det->frDetector.name );
  printf ("Sky position: longitude = %g rad, latitude = %g rad [equatorial coordinates]\n", config.skypos.longitude, config.skypos.latitude );
  printf ("\n");

  printf ("----- Antenna pattern functions (a,b):\n");
  printf ("LALComputeAM:                    ( %-12.8g, %-12.8g)  [REAL4]\n", AMold.a->data[0], AMold.b->data[0] );
  printf ("LALGetAMCoeffs:                  ( %-12.8g, %-12.8g)  [REAL4]\n", AMnew1.a->data[0], AMnew1.b->data[0] );
  printf ("LALNewGetAMCoeffs:               ( %-12.8g, %-12.8g)  [REAL4]\n", AMnew2.a->data[0]/config.sinzeta, AMnew2.b->data[0]/config.sinzeta );
  printf ("XLALComputeAntennaPatternCoeffs: ( %-12.8g, %-12.8g)  [REAL8]\n", a0/config.sinzeta, b0/config.sinzeta );
  printf ("\n");

  printf ("----- Detector & Earth state:\n");
  REAL8 *pos = detStates->data[0].rDetector;
  printf ("Detector position [ICRS J2000. Units=sec]: rDet = {%g, %g, %g}\n", pos[0], pos[1], pos[2] );
  REAL8 *vel = detStates->data[0].vDetector;
  printf ("Detector velocity [ICRS J2000. Units=c]:   vDet = {%g, %g, %g}\n", vel[0], vel[1], vel[2] );
  printf ("Local mean sideral time: LMST = %g rad\n", detStates->data[0].LMST);
  printf ("\n");
  printf ("----- SSB timing data:\n");
  printf ("TOA difference tSSB - tDet = %g s\n", tSSB->DeltaT->data[0] );
  printf ("TOA rate of change dtSSB/dtDet - 1 = %g\n", tSSB->Tdot->data[0] - 1.0 );
  printf ("\n\n");


  /* ----- done: free all memory */
  XLAL_CHECK ( XLALDestroyConfig( &config ) == XLAL_SUCCESS, XLAL_EFUNC );

  XLALDestroyDetectorStateSeries ( detStates );

  XLALDestroyREAL4Vector ( AMold.a );
  XLALDestroyREAL4Vector ( AMold.b );
  XLALDestroyREAL4Vector ( AMnew1.a );
  XLALDestroyREAL4Vector ( AMnew1.b );
  XLALDestroyREAL4Vector ( AMnew2.a );
  XLALDestroyREAL4Vector ( AMnew2.b );

  XLALDestroyREAL8Vector ( tSSB->DeltaT );
  XLALDestroyREAL8Vector ( tSSB->Tdot );
  XLALFree (tSSB);

  LALCheckMemoryLeaks();

  return 0;
} /* main */
/**
 * Simulate a pulsar signal to best accuracy possible.
 * \author Reinhard Prix
 * \date 2005
 *
 * The motivation for this function is to provide functions to
 * simulate pulsar signals <em>with the best possible accuracy</em>,
 * i.e. using no approximations, contrary to LALGeneratePulsarSignal().
 *
 * Obviously this is not meant as a fast code to be used in a Monte-Carlo
 * simulation, but rather as a <em>reference</em> to compare other (faster)
 * functions agains, in order to be able to gauge the quality of a given
 * signal-generation routine.
 *
 * We want to calculate \f$h(t)\f$, given by
 * \f[
 * h(t) = F_+(t)\, h_+(t) + F_\times(t) \,h_\times(t)\,,
 * \f]
 * where \f$F_+\f$ and \f$F_x\f$ are called the <em>beam-pattern</em> functions,
 * which depend of the wave polarization \f$\psi\f$,
 * the source position \f$\alpha\f$, \f$\delta\f$ and the detector position and
 * orientation (\f$\gamma\f$, \f$\lambda\f$, \f$L\f$ and \f$\xi\f$). The expressions for
 * the beam-pattern functions are given in \cite JKS98 , which we write as
 * \f{eqnarray}{
 * F_+(t) = \sin \zeta \cos 2\psi \, a(t)  + \sin \zeta \sin 2\psi \, b(t)\,,\\
 * F_\times(t) = \sin\zeta  \cos 2\psi \,b(t) - \sin\zeta \sin 2\psi \, a(t) \,,
 * \f}
 * where \f$\zeta\f$ is the angle between the interferometer arms, and
 * \f{eqnarray}{
 * a(t) &=& a_1 \cos[ 2 (\alpha - T)) ] + a_2 \sin[ 2(\alpha - T)]
 * + a_3 \cos[ \alpha - T ] + a_4 \sin [ \alpha - T ] + a_5\,,\\
 * b(t) &=& b_1 \cos[ 2(\alpha - T)] + b_2 \sin[ 2(\alpha - T) ]
 * + b_3 \cos[ \alpha - T ] + b_4 \sin[ \alpha - T]\,,
 * \f}
 * where \f$T\f$ is the local (mean) sidereal time of the detector, and the
 * time-independent coefficients \f$a_i\f$ and \f$b_i\f$ are given by
 * \f{eqnarray}{
 * a_1 &=& \frac{1}{16} \sin 2\gamma \,(3- \cos 2\lambda)\,(3 - \cos 2\delta)\,,\\
 * a_2 &=& -\frac{1}{4}\cos 2\gamma \,\sin \lambda \,(3 - \cos 2\delta) \,,\\
 * a_3 &=& \frac{1}{4} \sin 2\gamma \,\sin 2\lambda \,\sin 2\delta  \,\\
 * a_4 &=& -\frac{1}{2} \cos 2\gamma \,\cos \lambda \,\sin 2 \delta\,,\\
 * a_5 &=& \frac{3}{4} \sin 2\gamma \, \cos^2 \lambda \,\cos^2 \delta\,,
 * \f}
 * and
 * \f{eqnarray}{
 * b_1 &=& \cos 2\gamma \,\sin \lambda \,\sin \delta\,,\\
 * b_2 &=& \frac{1}{4} \sin 2\gamma \,(3-\cos 2\lambda)\, \sin \delta\,,\\
 * b_3 &=& \cos 2\gamma \,\cos \lambda \,\cos\delta \,, \\
 * b_4 &=& \frac{1}{2} \sin2\gamma \,\sin 2\lambda \,\cos\delta\,,
 * \f}
 *
 * The source model considered is a plane-wave
 * \f{eqnarray}{
 * h_+(t) &=& A_+\, \cos \Psi(t)\,,\\
 * h_\times(t) &=& A_\times \, \sin \Psi(t)\,,
 * \f}
 * where the wave-phase is \f$\Psi(t) = \Phi_0 + \Phi(t)\f$, and for an
 * isolated pulsar we have
 * \f{equation}{
 * \Phi(t) = 2\pi \left[\sum_{s=0} \frac{f^{(s)}(\tau_\mathrm{ref})}{
 * (s+1)!} \left( \tau(t) - \tau_\mathrm{ref} \right)^{s+1} \right]\,,
 * \f}
 * where \f$\tau_\mathrm{ref}\f$ is the "reference time" for the definition
 * of the pulsar-parameters \f$f^{(s)}\f$ in the solar-system barycenter
 * (SSB), and \f$\tau(t)\f$ is the SSB-time of the phase arriving at the
 * detector at UTC-time \f$t\f$, which depends on the source-position
 * (\f$\alpha\f$, \f$\delta\f$) and the detector-position, namely
 * \f{equation}{
 * \tau (t) = t + \frac{ \vec{r}(t)\cdot\vec{n}}{c}\,,
 * \f}
 * where \f$\vec{r}(t)\f$ is the vector from SSB to the detector, and \f$\vec{n}\f$
 * is the unit-vector pointing <em>to</em> the source.
 *
 * This is a standalone "clean-room" implementation using no other
 * outside-functions <em>except</em> for LALGPStoLMST1() to calculate
 * the local (mean) sidereal time at the detector for given GPS-time,
 * (which I double-checked with an independent Mathematica script),
 * and and XLALBarycenter() to calculate \f$\tau(t)\f$.
 *
 * NOTE: currently only isolated pulsars are supported
 *
 * NOTE2: we don't really use the highest possible accuracy right now,
 * as we blatently neglect all relativistic timing effects (i.e. using dT=v.n/c)
 *
 * NOTE3: no heterodyning is performed here, the time-series is generated and sampled
 * at the given rate, that's all! ==\> the caller needs to make sure about the
 * right sampling rate to use (-\>aliasing) and do the proper post-treatment...
 *
 */
REAL4TimeSeries *
XLALSimulateExactPulsarSignal ( const PulsarSignalParams *params )
{
  XLAL_CHECK_NULL ( params != NULL, XLAL_EINVAL, "Invalid NULL input 'params'\n");
  XLAL_CHECK_NULL ( params->samplingRate > 0, XLAL_EDOM, "Sampling rate must be positive, got samplingRate = %g\n", params->samplingRate );

  /* don't accept heterodyning frequency */
  XLAL_CHECK_NULL ( params->fHeterodyne == 0, XLAL_EINVAL, "Heterodyning frequency must be set to 0, got params->fHeterodyne = %g\n", params->fHeterodyne );

  UINT4 numSpins = 3;

  /* get timestamps of timeseries plus detector-states */
  REAL8 dt = 1.0 / params->samplingRate;
  LIGOTimeGPSVector *timestamps;
  XLAL_CHECK_NULL ( (timestamps = XLALMakeTimestamps ( params->startTimeGPS, params->duration, dt, 0 )) != NULL, XLAL_EFUNC );

  UINT4 numSteps = timestamps->length;

  DetectorStateSeries *detStates = XLALGetDetectorStates ( timestamps, params->site, params->ephemerides, 0 );
  XLAL_CHECK_NULL ( detStates != NULL, XLAL_EFUNC, "XLALGetDetectorStates() failed.\n");

  XLALDestroyTimestampVector ( timestamps );
  timestamps = NULL;

  AMCoeffs *amcoe = XLALComputeAMCoeffs ( detStates, params->pulsar.position );
  XLAL_CHECK_NULL ( amcoe != NULL, XLAL_EFUNC, "XLALComputeAMCoeffs() failed.\n");

  /* create output timeseries (FIXME: should really know *detector* here, not just site!!) */
  const LALFrDetector *site = &(params->site->frDetector);
  CHAR *channel = XLALGetChannelPrefix ( site->name );
  XLAL_CHECK_NULL ( channel != NULL, XLAL_EFUNC, "XLALGetChannelPrefix( %s ) failed.\n", site->name );

  REAL4TimeSeries *ts = XLALCreateREAL4TimeSeries ( channel, &(detStates->data[0].tGPS), 0, dt, &emptyUnit, numSteps );
  XLAL_CHECK_NULL ( ts != NULL, XLAL_EFUNC, "XLALCreateREAL4TimeSeries() failed.\n");
  XLALFree ( channel );
  channel = NULL;

  /* orientation of detector arms */
  REAL8 xAzi = site->xArmAzimuthRadians;
  REAL8 yAzi = site->yArmAzimuthRadians;
  REAL8 Zeta =  xAzi - yAzi;
  if (Zeta < 0) {
    Zeta = -Zeta;
  }
  if ( params->site->type == LALDETECTORTYPE_CYLBAR ) {
    Zeta = LAL_PI_2;
  }
  REAL8 sinZeta = sin(Zeta);

  /* get source skyposition */
  REAL8 Alpha = params->pulsar.position.longitude;
  REAL8 Delta = params->pulsar.position.latitude;
  REAL8 vn[3];
  vn[0] = cos(Delta) * cos(Alpha);
  vn[1] = cos(Delta) * sin(Alpha);
  vn[2] = sin(Delta);

  /* get spin-parameters (restricted to maximally 3 spindowns right now) */
  REAL8 phi0 = params->pulsar.phi0;
  REAL8 f0   = params->pulsar.f0;

  REAL8 f1dot = 0, f2dot = 0, f3dot = 0;
  if ( params->pulsar.spindown && (params->pulsar.spindown->length > numSpins) ) {
    XLAL_ERROR_NULL ( XLAL_EDOM, "Currently only supports up to %d spindowns!\n", numSpins );
  }
  if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 3 ) ) {
    f3dot = params->pulsar.spindown->data[2];
  }
  if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 2 ) ) {
    f2dot = params->pulsar.spindown->data[1];
  }
  if ( params->pulsar.spindown && (params->pulsar.spindown->length >= 1 ) ) {
    f1dot = params->pulsar.spindown->data[0];
  }

  /* internally we always work with refTime = startTime->SSB, therefore
   * we need to translate the pulsar spin-params and initial phase to the
   * startTime
   */
  REAL8 startTimeSSB = XLALGPSGetREAL8 ( &(detStates->data[0].tGPS) ) + SCALAR ( vn, detStates->data[0].rDetector );
  REAL8 refTime;
  if ( params->pulsar.refTime.gpsSeconds != 0 )
    {
      REAL8 refTime0 = XLALGPSGetREAL8 ( &(params->pulsar.refTime) );
      REAL8 deltaRef = startTimeSSB - refTime0;
      LIGOTimeGPS newEpoch;
      PulsarSpins fkdotNew;

      XLALGPSSetREAL8( &newEpoch, startTimeSSB );

      PulsarSpins XLAL_INIT_DECL(fkdotOld);
      fkdotOld[0] = f0;
      fkdotOld[1] = f1dot;
      fkdotOld[2] = f2dot;
      fkdotOld[3] = f3dot;
      REAL8 DeltaTau = XLALGPSDiff ( &newEpoch, &(params->pulsar.refTime) );

      int ret = XLALExtrapolatePulsarSpins ( fkdotNew, fkdotOld, DeltaTau );
      XLAL_CHECK_NULL ( ret == XLAL_SUCCESS, XLAL_EFUNC, "XLALExtrapolatePulsarSpins() failed.\n");

      /* Finally, need to propagate phase */
      phi0 += LAL_TWOPI * (               f0    * deltaRef
			    + (1.0/2.0) * f1dot * deltaRef * deltaRef
			    + (1.0/6.0) * f2dot * deltaRef * deltaRef * deltaRef
			    + (1.0/24.0)* f3dot * deltaRef * deltaRef * deltaRef * deltaRef
			    );

      f0    = fkdotNew[0];
      f1dot = fkdotNew[1];
      f2dot = fkdotNew[2];
      f3dot = fkdotNew[3];

      refTime = startTimeSSB;

    } /* if refTime given */
  else  { /* if not given: use startTime -> SSB */
    refTime = startTimeSSB;
  }

  /* get 4 amplitudes A_\mu */
  REAL8 aPlus  = sinZeta * params->pulsar.aPlus;
  REAL8 aCross = sinZeta * params->pulsar.aCross;
  REAL8 twopsi = 2.0 * params->pulsar.psi;

  REAL8 A1 =  aPlus * cos(phi0) * cos(twopsi) - aCross * sin(phi0) * sin(twopsi);
  REAL8 A2 =  aPlus * cos(phi0) * sin(twopsi) + aCross * sin(phi0) * cos(twopsi);
  REAL8 A3 = -aPlus * sin(phi0) * cos(twopsi) - aCross * cos(phi0) * sin(twopsi);
  REAL8 A4 = -aPlus * sin(phi0) * sin(twopsi) + aCross * cos(phi0) * cos(twopsi);

  /* main loop: generate time-series */
  for ( UINT4 i = 0; i < numSteps; i++)
    {
      LIGOTimeGPS *tiGPS = &(detStates->data[i].tGPS);

      REAL8 ti = XLALGPSGetREAL8 ( tiGPS );
      REAL8 deltati = ti - refTime;
      REAL8 dT = SCALAR(vn, detStates->data[i].rDetector );
      REAL8 taui = deltati + dT;

      REAL8 phi_i = LAL_TWOPI * ( f0 * taui
			    + (1.0/2.0) * f1dot * taui*taui
			    + (1.0/6.0) * f2dot * taui*taui*taui
			    + (1.0/24.0)* f3dot * taui*taui*taui*taui
			    );

      REAL8 cosphi_i = cos(phi_i);
      REAL8 sinphi_i = sin(phi_i);

      REAL8 ai = amcoe->a->data[i];
      REAL8 bi = amcoe->b->data[i];

      REAL8 hi = A1 * ai * cosphi_i
	+  A2 * bi * cosphi_i
	+  A3 * ai * sinphi_i
	+  A4 * bi * sinphi_i;

      ts->data->data[i] = (REAL4)hi;

    } /* for i < numSteps */

  XLALDestroyDetectorStateSeries( detStates );
  XLALDestroyAMCoeffs ( amcoe );

  return ts;

} /* XLALSimulateExactPulsarSignal() */