示例#1
0
    def test_antenna_pattern(self):
        vals = zip(self.ra, self.dec, self.pol, self.time)
        for ifo in self.d:
            fp = []
            fc = []
            for ra1, dec1, pol1, time1 in vals:
                gmst = lal.GreenwichMeanSiderealTime(time1)
                fp1, fc1 = tuple(
                    lal.ComputeDetAMResponse(ifo.response, ra1, dec1, pol1,
                                             gmst))
                fp.append(fp1)
                fc.append(fc1)

            fp2, fc2 = ifo.antenna_pattern(self.ra, self.dec, self.pol,
                                           self.time)

            fp = numpy.array(fp)
            fc = numpy.array(fc)

            diff1 = fp - fp2
            diff2 = fc - fc2
            diff = abs(numpy.concatenate([diff1, diff2]))
            tolerance = 1e-4
            print("Max antenna diff:", ifo.name, diff.max())

            self.assertLess(diff.max(), tolerance)
示例#2
0
def makeplot(options):
    fig = figure.Figure()
    FigureCanvasAgg(fig)
    fig.set_size_inches(6.5, 6.5 / ((1 + math.sqrt(5)) / 2))
    axes = fig.gca()
    axes.grid(True)

    xvals = numpy.arange(0.0, 401.0, 1.0, "Float64") * math.pi / 200.0
    for instrument in options.instrument:
        yvals = [
            plus**2.0 + cross**2.0 for (plus, cross) in map(
                lambda t: lal.ComputeDetAMResponse(
                    lal.cached_detector_by_prefix[instrument].response, options
                    .right_ascension, options.declination, 0.0, t), xvals)
        ]
        axes.plot(xvals, yvals)

    axes.set_xlim([0.0, 2.0 * math.pi])

    axes.set_xticks(numpy.arange(9) * math.pi / 4)
    axes.set_xticklabels([
        r"0", r"$\pi/4$", r"$\pi/2$", r"$3\pi/4$", r"$\pi$", r"$5\pi/4$",
        r"$3\pi/2$", r"$7\pi/4$", r"$2\pi$"
    ])

    axes.legend([r"\verb|%s|" % ins for ins in options.instrument])

    axes.set_xlabel("Greenwich Mean Sidereal Time (rad)")
    axes.set_ylabel(r"$F_{+}^{2} + F_{\times}^{2}$")
    axes.set_title(
        r"Detector Response by Sidereal Time for Source at R.A.\ %g rad, Dec.\ %g rad"
        % (options.right_ascension, options.declination))

    return fig
示例#3
0
def get_delta_D_rss(pt,coinc):
  """
  compute the rms difference in the ratio of the difference of the squares of Deff to
  the sum of the squares of Deff between the measured values and a "marginalized" effective
  distance this is just the squared Deff integrated over inclination and polarization which
  is proportional to (F+^2 + Fx^2)^(-1)
  """
  latitude,longitude = pt
  gmst = {}
  D_marg_sq = {}
  F_plus = {}
  F_cross = {}
  for ifo in coinc.ifo_list:
    gmst[ifo] = date.XLALGreenwichMeanSiderealTime(coinc.gps[ifo])
    F_plus[ifo], F_cross[ifo] = lal.ComputeDetAMResponse(detector_responses[ifo],\
                                longitude,latitude,0,gmst[ifo])
    D_marg_sq[ifo] = 1/(F_plus[ifo]*F_plus[ifo]+F_cross[ifo]*F_cross[ifo])

  delta_D = {}
  effD_diff = 0.0
  effD_sum = 0.0
  Dmarg_diff = 0.0
  Dmarg_sum = 0.0
  delta_D_rss = 0.0
  for ifos in coinc.ifo_coincs:
    effD_diff = coinc.eff_distances[ifos[0]] * coinc.eff_distances[ifos[0]]\
                - coinc.eff_distances[ifos[1]] * coinc.eff_distances[ifos[1]]
    effD_sum = coinc.eff_distances[ifos[0]] * coinc.eff_distances[ifos[0]]\
               + coinc.eff_distances[ifos[1]] * coinc.eff_distances[ifos[1]]
    Dmarg_diff = D_marg_sq[ifos[0]] - D_marg_sq[ifos[1]]
    Dmarg_sum = D_marg_sq[ifos[0]] + D_marg_sq[ifos[1]]
    delta_D[ifos[0]+ifos[1]] = (effD_diff/effD_sum) - (Dmarg_diff/Dmarg_sum)
    delta_D_rss += delta_D[ifos[0]+ifos[1]]*delta_D[ifos[0]+ifos[1]]

  return sqrt(delta_D_rss)
示例#4
0
def magnitude_b(burst):
    gmst = lal.GreenwichMeanSiderealTime(burst.peak)
    fplus, fcross = lal.ComputeDetAMResponse(
        lal.cached_detector_by_prefix[burst.ifo].response,
        SimBurstUtils.MW_CENTER_J2000_RA_RAD,
        SimBurstUtils.MW_CENTER_J2000_DEC_RAD, 0.0, gmst)
    return (burst.ms_hrss**2.0 / (fplus**2.0 + fcross**2.0))**0.5
示例#5
0
def delay_and_amplitude_correct(event, ra, dec):
    # retrieve station metadata

    detector = lal.cached_detector_by_prefix[event.ifo]

    # delay-correct the event to the geocentre

    delay = lal.TimeDelayFromEarthCenter(detector.location, ra, dec,
                                         event.peak)
    event.peak -= delay
    event.period = event.period.shift(-delay)
    try:
        event.ms_peak -= delay
    except AttributeError:
        pass
    try:
        event.ms_period = event.ms_period.shift(-delay)
    except AttributeError:
        pass

    # amplitude-correct the event using the polarization-averaged
    # antenna response

    fp, fc = lal.ComputeDetAMResponse(
        detector.response, ra, dec, 0,
        lal.GreenwichMeanSiderealTime(event.peak))
    mean_response = math.sqrt(fp**2 + fc**2)
    event.amplitude /= mean_response
    event.ms_hrss /= mean_response

    # done

    return event
示例#6
0
def getDetResp(detector, ra, dec, time=0., psi=0.):
    # Set time
    gmst = lal.GreenwichMeanSiderealTime(lal.LIGOTimeGPS(time))
    #Get Detector Responses
    det_response = lal.CachedDetectors[det_index[detector]].response
    # Get Fplus, Fcross
    fplus, fcross = lal.ComputeDetAMResponse(det_response, ra, dec, psi, gmst)
    return fplus, fcross
示例#7
0
 def calculate_sensitivity(self, event):
     """
     Calculate the sensitivity of the detector to an event
     :param event: object, containing ra, dec, psi, gmst
     """
     self.f_plus, self.f_cross = lal.ComputeDetAMResponse(self.response,
                                                          event.ra, event.dec,
                                                          event.psi, event.gmst)
示例#8
0
 def antenna_pattern(self, right_ascension, declination, polarization,
                     t_gps):
     """Return the detector response.
     """
     gmst = lal.GreenwichMeanSiderealTime(t_gps)
     return tuple(
         lal.ComputeDetAMResponse(self.response, right_ascension,
                                  declination, polarization, gmst))
示例#9
0
 def calculate_mirror_sensitivity(self, event):
     """
     Calculate the sensitivity of the detector to an event, in its mirror sky location
     :param event: object, containing mirror_ra, mirror_dec, psi, gmst
     """
     self.mirror_f_plus, self.mirror_f_cross = \
         lal.ComputeDetAMResponse(self.response,
                                  event.mirror_ra, event.mirror_dec,
                                  event.psi, event.gmst)
示例#10
0
    def antenna_pattern(self, skypoints, time=None, psi=0):
        """ Compute antenna response of a detector for a list of skypoints

            skypoints: Skypoint object or list of Skypoint objects
            time: time date when to compute the antenna pattern (default: None) 
            psi: optional polarization angle (default: 0)

            This function uses XLALComputeDetAMResponse() that takes equatorial 
            coordinates (RA and dec) and the Greenwich Mean Sidereal Time (GMST) 
            to define the sky location.

            If the skypoints are given in the equatorial coordinate system, 
            the antenna pattern is computed at the provided time if not None, otherwise
            it is computed at the reference time of the coordinate system of 
            the skypoints.

            If the skypoints are given in the geographic coordinate system,
            they are mapped to fiducial equatorial coordinate system with 
            GMST = 0 hr (REFDATE_GMST_ZERO).
        """

        if not isinstance(skypoints, list):
            skypoints = [skypoints]

        f = []
        for p in skypoints:

            assert isinstance(p, Skypoint), "Requires Skypoint objects"
            assert p.coordsystem.is_valid(), "Unsupported coordinate system"

            # XLALComputeDetAMResponse() requires equatorial coordinates.
            # We transform the points with Earth-fixed coordsystem ('geographic')
            # to the fiducial equatorial coordinates system with GMST = 0 hr.

            if p.coordsystem.name == 'geographic':
                assert time is None, \
                    'time cannot be forced for skypoints in the geographic coordinate system'
                p = p.transformed_to(FIDUCIAL_EQUATORIAL_COORDSYS_GMST_ZERO)
                gmst_rad = lal.GreenwichMeanSiderealTime(
                    p.coordsystem.ref_time)
            else:
                gmst_rad = lal.GreenwichMeanSiderealTime(time if time is not None else \
                                                     p.coordsystem.ref_time)

            # XLALComputeDetAMResponse() takes equatorial coordinates (RA and dec)
            # and gmst to define a sky location
            f.append(lal.ComputeDetAMResponse(self.descriptor.response, \
                                      *p.coords(fmt='lonlat',unit='radians'), \
                                      psi, gmst_rad))

        f = numpy.squeeze(numpy.array(f))

        if f.ndim == 1:
            return tuple(f)  # fplus, fcross
        else:
            return f[:, 0], f[:, 1]  # fplus, fcross
def complex_antenna_factor(det, RA, DEC, psi, tref):
    """
    Function to compute the complex-valued antenna pattern function:
    F+ + i Fx

    'det' is a detector prefix string (e.g. 'H1')
    'RA' and 'DEC' are right ascension and declination (in radians)
    'psi' is the polarization angle
    'tref' is the reference GPS time
    """
    detector = lalsim.DetectorPrefixToLALDetector(det)
    Fp, Fc = lal.ComputeDetAMResponse(detector.response, RA, DEC, psi, lal.GreenwichMeanSiderealTime(tref))

    return Fp + 1j * Fc
示例#12
0
def find_eff_d(dlum, alpha, delta, pol, iota, T_inj):
    d_eff_dict = {}
    # calculate and set detector-specific columns
    for det_site, det in detectors.iteritems():
        d_eff_dict[det_site] = []
        for i in range(len(dlum)):
            fp, fc = lal.ComputeDetAMResponse(det.response, alpha[i], delta[i],
                                              pol[i], T_inj[i])
            cosi = np.cos(iota[i])
            deff = dlum[i] * ((0.5 * (1.0 + cosi**2) * fp)**2 +
                              (cosi * fc)**2)**-0.5
            d_eff_dict[det_site].append(deff)
        d_eff_dict[det_site] = np.array(d_eff_dict[det_site])
    return d_eff_dict
示例#13
0
def hrss_in_instrument(sim, instrument, offsetvector):
    """
	Given an injection and an instrument, compute and return the h_rss
	of the injection as should be observed in the instrument.  That is,
	project the waveform onto the instrument, and return the root
	integrated strain squared.
	"""
    # FIXME:  this function is really only correct for sine-Gaussian
    # injections.  that's OK because I only quote sensitivities in
    # units of hrss when discussing sine-Gaussians.
    #
    # the problem is the following.  first,
    #
    #	h = F+ h+ + Fx hx
    #
    # so
    #
    #	h^{2} = F+^2 h+^2 + Fx^2 hx^2 + 2 F+ Fx h+ hx
    #
    # which means to calculate the hrss in the instrument you need to
    # know:  mean-square h in the + polarization, mean-square h in the
    # x polarization, and the correlation between the polarizations <h+
    # hx>.  these could be recorded in the sim_burst table, but they
    # aren't at present.

    # semimajor and semiminor axes of polarization ellipse

    a = 1.0 / math.sqrt(2.0 - sim.pol_ellipse_e**2)
    b = a * math.sqrt(1.0 - sim.pol_ellipse_e**2)

    # hrss in plus and cross polarizations

    hplusrss = sim.hrss * (a * math.cos(sim.pol_ellipse_angle) -
                           b * math.sin(sim.pol_ellipse_angle))
    hcrossrss = sim.hrss * (b * math.cos(sim.pol_ellipse_angle) +
                            a * math.sin(sim.pol_ellipse_angle))

    # antenna response factors

    fplus, fcross = lal.ComputeDetAMResponse(
        lal.cached_detector_by_prefix[instrument].response, sim.ra, sim.dec,
        sim.psi,
        lal.GreenwichMeanSiderealTime(
            sim.time_at_instrument(instrument, offsetvector)))

    # hrss in detector

    return math.sqrt((fplus * hplusrss)**2 + (fcross * hcrossrss)**2)
示例#14
0
def string_amplitude_in_instrument(sim, instrument, offsetvector):
    """
	Given a string cusp injection and an instrument, compute and return
	the amplitude of the injection as should be observed in the
	instrument.
	"""
    assert sim.waveform == "StringCusp"

    # antenna response factors

    fplus, fcross = lal.ComputeDetAMResponse(
        lal.cached_detector_by_prefix[instrument].response, sim.ra, sim.dec,
        sim.psi,
        lal.GreenwichMeanSiderealTime(
            sim.time_at_instrument(instrument, offsetvector)))

    # amplitude in detector

    return fplus * sim.amplitude
示例#15
0
def get_detector_response(ra, dec, psi, detector_tag, gmst=0):
    detMap = {
        'H1': lal.LALDetectorIndexLHODIFF,
        'H2': lal.LALDetectorIndexLHODIFF,
        'L1': lal.LALDetectorIndexLLODIFF,
        'G1': lal.LALDetectorIndexGEO600DIFF,
        'V1': lal.LALDetectorIndexVIRGODIFF,
        'T1': lal.LALDetectorIndexTAMA300DIFF,
        'AL1': lal.LALDetectorIndexLLODIFF,
        'AH1': lal.LALDetectorIndexLHODIFF,
        'AV1': lal.LALDetectorIndexVIRGODIFF
    }
    detector = detMap[detector_tag]
    # get detector
    detval = lal.CachedDetectors[detector]
    # get its response Tensor
    response = detval.response
    # get plus and cross polarization response
    return lal.ComputeDetAMResponse(response, ra, dec, psi, gmst)
    def __Fcross(self, detector, RA, Dec, psi, gmst):
        """
        Computes the 'plus' antenna pattern

        Parameters
        ----------
        detector : str
            name of detector in network (eg 'H1', 'L1')
        RA,Dec : float
            sky location of the event in radians
        psi : float
            source polarisation in radians
        gmst : float
            Greenwich Mean Sidereal Time in seconds

        Returns
        -------
        float
            F_x antenna response
        """
        detector = lalsim.DetectorPrefixToLALDetector(detector)
        return lal.ComputeDetAMResponse(detector.response, RA,
                                        Dec, psi, gmst)[1]
示例#17
0
def response(gpsTime, rightAscension, declination, inclination, polarization,
             unit, det):
    """
  response( gpsTime, rightAscension, declination, inclination,
              polarization, unit, detector )
  
  Calculates the antenna factors for a detector 'detector' (e.g. 'H1')
  at a given gps time (as integer) for a given sky location
  (rightAscension, declination) in some unit (degree/radians).
  This computation also takes into account a specific inclination
  and polarization.
  
  The returned values are: (f-plus, f-cross, f-average, q-value).
  
  Example: antenna.response( 854378604.780, 11.089, 42.308, 0, 0, 'radians', 'H1' )
  """

    # check the input arguments
    if unit == 'radians':
        ra_rad = rightAscension
        de_rad = declination
        psi_rad = polarization
        iota_rad = inclination
    elif unit == 'degree':
        ra_rad = rightAscension / 180.0 * pi
        de_rad = declination / 180.0 * pi
        psi_rad = polarization / 180.0 * pi
        iota_rad = inclination / 180.0 * pi
    else:
        raise ValueError, "Unknown unit %s" % unit

    # calculate GMST if the GPS time
    gps = lal.LIGOTimeGPS(gpsTime)
    gmst_rad = lal.GreenwichMeanSiderealTime(gps)

    # create detector-name map
    detMap = {
        'H1': 'LHO_4k',
        'H2': 'LHO_2k',
        'L1': 'LLO_4k',
        'G1': 'GEO_600',
        'V1': 'VIRGO',
        'T1': 'TAMA_300'
    }
    try:
        detector = detMap[det]
    except KeyError:
        raise ValueError, "ERROR. Key %s is not a valid detector name."\
              % (det)

    # get detector
    if detector not in inject.cached_detector.keys():
        raise ValueError, "%s is not a cached detector.  "\
              "Cached detectors are: %s" \
              % (det, inject.cached_detector.keys())

    # get the correct response data
    response = inject.cached_detector[detector].response

    # actual computation of antenna factors
    f_plus, f_cross = lal.ComputeDetAMResponse(response, ra_rad, de_rad,
                                               psi_rad, gmst_rad)

    f_ave = sqrt((f_plus * f_plus + f_cross * f_cross) / 2.0)
    ci = cos(iota_rad)
    cc = ci * ci

    # calculate q-value, e.g. ratio of effective to real distance
    # ref: Duncans PhD, eq. (4.3) on page 57
    f_q = sqrt(f_plus * f_plus * (1 + cc) * (1 + cc) / 4.0 +
               f_cross * f_cross * cc)

    # output
    return f_plus, f_cross, f_ave, f_q
                                 spin1z=sim_inspiral.spin1z,
                                 spin2x=sim_inspiral.spin2x,
                                 spin2y=sim_inspiral.spin2y,
                                 spin2z=sim_inspiral.spin2z,
                                 f_min=f_low)
    W = [filter.signal_psd_series(H, psds[ifo]) for ifo in opts.detector]
    signal_models = [timing.SignalModel(_) for _ in W]

    # Get SNR=1 horizon distances for each detector.
    horizons = np.asarray([
        signal_model.get_horizon_distance() for signal_model in signal_models
    ])

    # Get antenna factors for each detector.
    Fplus, Fcross = np.asarray([
        lal.ComputeDetAMResponse(response, ra, dec, psi, gmst)
        for response in responses
    ]).T

    # Compute TOAs at each detector.
    toas = np.asarray([
        lal.TimeDelayFromEarthCenter(location, ra, dec, epoch)
        for location in locations
    ])

    # Compute SNR in each detector.
    snrs = (0.5 * (1 + u2) * Fplus + 1j * u * Fcross) * horizons / DL

    abs_snrs = np.abs(snrs)
    arg_snrs = np.angle(snrs)
示例#19
0
import lal

#Python code to convert gpstime to GMST and to find beam pattern functions.
# Install lalsuite by typing "pip install lalsuite" in command line
#To run the script just do 'python lal-gmst-beam-pattern.py'

timeToUse = 1126259462.41302  #GPStime
IFO_l = lal.CachedDetectors[lal.LALDetectorIndexLLODIFF]  #Livingston
IFO_h = lal.CachedDetectors[lal.LALDetectorIndexLHODIFF]  #Handoford
fancy_time = lal.lal.LIGOTimeGPS(timeToUse)  #Nothing important
#print fancy_time
gmst = lal.GreenwichMeanSiderealTime(fancy_time)  #converts gpstime to gmst
print gmst
RA = 1.123  #right-ascension
dec = -0.012  #declination
#change the RA and dec to the numbers from the posteior files (the ones I use here are just random...)
psi = 1.57  #polarization
F_plus_l, F_cross_l = lal.ComputeDetAMResponse(
    IFO_l.response, RA, dec, psi, gmst)  #beam pattern for Livingston
F_plus_h, F_cross_h = lal.ComputeDetAMResponse(IFO_h.response, RA, dec, psi,
                                               gmst)  #beam pattern for Hanford
print F_plus_h, F_cross_h
print F_plus_l, F_cross_l
def simulate_snr(ra,
                 dec,
                 psi,
                 inc,
                 distance,
                 epoch,
                 gmst,
                 H,
                 S,
                 response,
                 location,
                 measurement_error='zero-noise'):
    from scipy.interpolate import interp1d

    from ..bayestar import filter
    from ..bayestar.interpolation import interpolate_max

    duration = 0.1

    # Calculate whitened template autocorrelation sequence.
    HS = filter.signal_psd_series(H, S)
    n = len(HS.data.data)
    acor, sample_rate = filter.autocorrelation(HS, duration)

    # Calculate time, amplitude, and phase.
    u = np.cos(inc)
    u2 = np.square(u)
    signal_model = filter.SignalModel(HS)
    horizon = signal_model.get_horizon_distance()
    Fplus, Fcross = lal.ComputeDetAMResponse(response, ra, dec, psi, gmst)
    toa = lal.TimeDelayFromEarthCenter(location, ra, dec, epoch)
    z = (0.5 * (1 + u2) * Fplus + 1j * u * Fcross) * horizon / distance

    # Calculate complex autocorrelation sequence.
    snr_series = z * np.concatenate((acor[:0:-1].conj(), acor))

    # If requested, add noise.
    if measurement_error == 'gaussian-noise':
        sigmasq = 4 * np.sum(HS.deltaF * np.abs(HS.data.data))
        amp = 4 * n * HS.deltaF**0.5 * np.sqrt(HS.data.data / sigmasq)
        N = lal.CreateCOMPLEX16FrequencySeries('', HS.epoch, HS.f0, HS.deltaF,
                                               HS.sampleUnits, n)
        N.data.data = amp * (np.random.randn(n) + 1j * np.random.randn(n))
        noise_term, sample_rate_2 = filter.autocorrelation(N,
                                                           2 * duration -
                                                           1 / sample_rate,
                                                           normalize=False)
        assert sample_rate == sample_rate_2
        snr_series += noise_term

    # Shift SNR series to the nearest sample.
    int_samples, frac_samples = divmod(
        (1e-9 * epoch.gpsNanoSeconds + toa) * sample_rate, 1)
    if frac_samples > 0.5:
        int_samples += 1
        frac_samples -= 1
    epoch = lal.LIGOTimeGPS(epoch.gpsSeconds, 0)
    n = len(acor) - 1
    mprime = np.arange(-n, n + 1)
    m = mprime + frac_samples
    re, im = (interp1d(m, x, kind='cubic', bounds_error=False,
                       fill_value=0)(mprime)
              for x in (snr_series.real, snr_series.imag))
    snr_series = re + 1j * im

    # Find the trigger values.
    i_nearest = np.argmax(np.abs(
        snr_series[n - n // 2:n + n // 2 + 1])) + n - n // 2
    i_interp, z_interp = interpolate_max(i_nearest,
                                         snr_series,
                                         n // 2,
                                         method='lanczos')
    toa = epoch + (int_samples + i_interp - n) / sample_rate
    snr = np.abs(z_interp)
    phase = np.angle(z_interp)

    # Shift and truncate the SNR time series.
    epoch += (int_samples + i_nearest - n - n // 2) / sample_rate
    snr_series = snr_series[(i_nearest - n // 2):(i_nearest + n // 2 + 1)]
    tseries = lal.CreateCOMPLEX8TimeSeries('snr', epoch, 0, 1 / sample_rate,
                                           lal.DimensionlessUnit,
                                           len(snr_series))
    tseries.data.data = snr_series
    return horizon, snr, phase, toa, tseries
def test_bayestar_signal_amplitude_model(ra, dec, inclination, polarization,
                                         epoch, instrument):
    """Test BAYESTAR signal amplitude model against LAL injection code."""
    detector = lalsimulation.DetectorPrefixToLALDetector(instrument)
    epoch = lal.LIGOTimeGPS(epoch)
    gmst = lal.GreenwichMeanSiderealTime(epoch)

    exp_i_twopsi = np.exp(2j * polarization)
    u = np.cos(inclination)
    u2 = np.square(u)
    F = get_complex_antenna(detector.response, ra, dec, gmst)
    result = signal_amplitude_model(F, exp_i_twopsi, u, u2)

    abs_expected = 1 / get_eff_dist(detector, ra, dec, inclination,
                                    polarization, epoch, gmst)

    # This is the *really* slow way of working out the signal amplitude:
    # generate a frequency-domain waveform and inject it.

    params = lal.CreateDict()
    lalsimulation.SimInspiralWaveformParamsInsertPNPhaseOrder(
        params, lalsimulation.PNORDER_NEWTONIAN)
    lalsimulation.SimInspiralWaveformParamsInsertPNAmplitudeOrder(
        params, lalsimulation.PNORDER_NEWTONIAN)

    # Calculate antenna factors
    Fplus, Fcross = lal.ComputeDetAMResponse(detector.response, ra, dec,
                                             polarization, gmst)

    # Check that the way I compute the antenna factors matches
    F = get_complex_antenna(detector.response, ra, dec, gmst)
    F *= np.exp(-2j * polarization)

    assert F.real == approx(Fplus, abs=4 * np.finfo(np.float64).eps)
    assert F.imag == approx(Fcross, abs=4 * np.finfo(np.float64).eps)

    # "Template" waveform with inclination angle of zero
    Htemplate, Hcross = lalsimulation.SimInspiralFD(1.4 * lal.MSUN_SI,
                                                    1.4 * lal.MSUN_SI, 0, 0, 0,
                                                    0, 0, 0, 1, 0, 0, 0, 0, 0,
                                                    1, 100, 101, 100, params,
                                                    lalsimulation.TaylorF2)

    # Discard any non-quadrature phase component of "template"
    Htemplate.data.data += 1j * Hcross.data.data

    # Normalize "template"
    h = np.sum(
        np.square(Htemplate.data.data.real) +
        np.square(Htemplate.data.data.imag))
    h = 2 / h
    Htemplate.data.data *= h

    # "Signal" waveform with requested inclination angle
    Hsignal, Hcross = lalsimulation.SimInspiralFD(
        1.4 * lal.MSUN_SI, 1.4 * lal.MSUN_SI, 0, 0, 0, 0, 0, 0, 1, inclination,
        0, 0, 0, 0, 1, 100, 101, 100, params, lalsimulation.TaylorF2)

    # Project "signal" using antenna factors
    Hsignal.data.data = Fplus * Hsignal.data.data + Fcross * Hcross.data.data

    # Work out complex amplitude by comparing with "template" waveform
    expected = np.sum(Htemplate.data.data.conj() * Hsignal.data.data)

    assert abs(expected) == approx(abs_expected,
                                   abs=1.5 * np.finfo(np.float32).eps)
    assert abs(result) == approx(abs_expected,
                                 abs=1.5 * np.finfo(np.float32).eps)
    assert result.real == approx(expected.real,
                                 abs=4 * np.finfo(np.float32).eps)
    assert result.imag == approx(expected.imag,
                                 abs=4 * np.finfo(np.float32).eps)
def get_complex_antenna(response, ra, dec, gmst):
    Fplus, Fcross = lal.ComputeDetAMResponse(response, ra, dec, 0, gmst)
    return Fplus + 1j * Fcross