Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALSimUtils.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 J. Creighton, K. Cannon
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19
20#include <math.h>
21#include <lal/LALStdlib.h>
22#include <lal/LALConstants.h>
23#include <lal/TimeSeries.h>
24#include <lal/FrequencySeries.h>
25#include <lal/TimeFreqFFT.h>
26#include <lal/Units.h>
27#include <lal/LALSimUtils.h>
28
29#include "check_series_macros.h"
30
31/**
32 * Creates a new interpolated psd from an existing psd (if necessary).
33 *
34 * The returned frequency series will have the specified values of @p f0, @p
35 * deltaF, and @p length. If the original frequency series @p old had the same
36 * values, this routine simply returns a pointer to the @p old. Otherwise,
37 * this routine allocates a new frequency series.
38 *
39 * The interpolation in performed is linear-in-log (since a psd is
40 * positive-definite). Any component of the psd that is 0 is taken to be
41 * invalid, and any component of the returned psd that would depend on a 0
42 * component of the original psd is also set to 0. Likewise, any components of
43 * the new psd that would require extrapolation of the original psd are set to
44 * zero. The routines defined here adhere to the convention that frequency
45 * components in which the psd is 0 are ignored.
46 *
47 * @warning If this routines returns a pointer to the original frequency
48 * series, it discards the const qualifier.
49 *
50 * @note The calling routine must test if the pointer to the psd returned by
51 * this routine is the same as the pointer to the psd passed to this routine to
52 * determine if the returned psd needs to be freed separately.
53 */
54static REAL8FrequencySeries * create_interpolated_psd(double f0, double deltaF, size_t length, const REAL8FrequencySeries *old)
55{
57 size_t k, kmin, kmax;
58
59 /* see if we can get away without interpolating */
60 if (fabs(deltaF - old->deltaF) < LAL_REAL8_EPS) {
61 int first;
62
63 /* do we need to do anything? */
64 if (fabs(f0 - old->f0) < LAL_REAL8_EPS && length == old->data->length)
65 return (REAL8FrequencySeries*)(uintptr_t)(old); /* bad: discards const qual */
66
67 /* is this just an integer shift / resize? */
68 first = round(f0 - old->f0) / deltaF;
69 if (fabs(first * deltaF - f0 + old->f0) < LAL_REAL8_EPS) {
70 /* is new a subset of old? */
71 if (first >=0 && old->data->length >= length + first)
72 new = XLALCutREAL8FrequencySeries(old, first, length);
73 else {
74 /* copy and resize */
75 new = XLALCutREAL8FrequencySeries(old, 0, old->data->length);
76 new = XLALResizeREAL8FrequencySeries(new, first, length);
77 }
78 return new;
79 }
80 }
81
82 /* we have to actually interpolate... */
83 new = XLALCreateREAL8FrequencySeries(old->name, &old->epoch, f0, deltaF, &old->sampleUnits, length);
84
85 /* determine the limits of where interpolation can occur */
86 if (f0 < old->f0)
87 kmin = ceil((old->f0 - f0) / deltaF);
88 else
89 kmin = 0;
90
91 if (f0 + length * deltaF > old->f0 + old->data->length * old->deltaF)
92 kmax = floor((old->f0 + old->data->length * old->deltaF - f0) / deltaF);
93 else
94 kmax = length;
95
96 /* zero out any invalid regions */
97 for (k = 0; k < kmin; ++k)
98 new->data->data[k] = 0.0;
99 for (k = kmax; k < length; ++k)
100 new->data->data[k] = 0.0;
101
102 for (k = kmin; k < kmax; ++k) {
103 double x, ix;
104 double y0, y1;
105 size_t i;
106
107 x = modf((f0 + k * deltaF - old->f0) / old->deltaF, &ix);
108 i = (size_t)(ix);
109
110 /* safety checks are probably not necessary */
111 y0 = ix < 0.0 ? 0.0 : old->data->data[i];
112 y1 = i >= old->data->length - 1 ? 0.0 : old->data->data[i+1];
113
114 if (y0 == 0.0 || y1 == 0.0)
115 new->data->data[k] = 0.0; /* invalid data */
116 else /* linear-in-log interpolation */
117 new->data->data[k] = exp((1.0 - x) * log(y0) + x * log(y1));
118 }
119
120 return new;
121}
122
123/**
124 * @brief Computes the sense-monitor range for a binary neutron star standard
125 * siren signal for a given one-sided detector noise power spectral density.
126 *
127 * The "Standard Siren" is a restricted (0 pN in amplitude) gravitational
128 * waveform produced by a binary neutron star system comprised of two neutron
129 * stars, each having a mass of 1.4 Msun. A circular inspiral of point
130 * particles is also assumed. The "Sense-Monitor Range" is corresponds to
131 * the range measure reported by the LIGO control room monitor @c SenseMonitor.
132 * This range is the radius of a sphere that has contains as many sources as
133 * the number that would produce a characteristic signal-to-noise ratio 8 in a
134 * detector under the assumption of a homogeneous distribution of sources
135 * having random orientations. No cosmological effects are included in this
136 * sense-monitor range measure. The sense-monitor range \f$\cal R\f$ is
137 * related to the horizon distance \f$D_{\rm hor}\f$ by
138 * \f$D_{\rm hor} \approx 2.26478\cal R\f$.
139 *
140 * @note
141 * The siren has a maximum gravitational wave frequency equal to twice the
142 * innermost stable cirucluar orbit (ISCO) frequency for a Schwarzschild black
143 * hole of the same total mass as the system. This upper frequency is
144 * \f[ f_{\rm isco} = \frac{c^3}{\pi 6^{3/2} G M} = 1570 {\rm Hz} \f]
145 * where \f$M=2.8M_\odot\f$. If @p f_max is above this ISCO frequency, or
146 * negative, then the ISCO frequency is used; otherwise @p f_max is used.
147 *
148 * @note
149 * Other implementations have used a different value for the ISCO frequency.
150 * The SenseMonitor adopts a dimensionless orbital frequency value of
151 * \f$Mf_{\rm orb}=0.0098325\f$ in geometric units for the equal mass case,
152 * while Table I of Kidder, Will, and Wiseman, Physical Review D @b 47 3281
153 * (1993) http://dx.doi.org/10.1103/PhysRevD.47.3281 gives a value of 0.00933.
154 * For comparison, the Schwarzschild ISCO is 16% larger:
155 * \f$Mf_{\rm orb}=1/(2\pi 6^{3/2})=0.0108\f$.
156 *
157 * See XLALMeasureStandardSirenHorizonDistance() for a description of the
158 * horizon distance.
159 *
160 * See XLALMeasureSNRFD() for further discussion about characteristic
161 * signal-to-noise ratios.
162 *
163 * @sa Appendix D of
164 * Bruce Allen, Warren G. Anderson, Patrick R. Brady, Duncan A. Brown, and
165 * Jolien D. E. Creighton, "FINDCHIRP: An algorithm for detection of
166 * gravitational waves from inspiraling compact binaries", Phys. Rev. D @b 85,
167 * 122006 (2012) http://dx.doi.org/10.1103/PhysRevD.85.122006
168 *
169 * @param[in] psd The one-sided detector strain noise power spectral density.
170 * @param[in] f_min The lower bound of the frequency band over which the
171 * signal-to-noise ratio will be computed; set to 0 or a negative value for no
172 * lower bound.
173 * @param[in] f_max The upper bound of the frequency band over which the
174 * signal-to-noise ratio will be computed; set to a negative value for
175 * no upper bound.
176 * @returns The sense-monitor range in meters.
177 * @retval LAL_REAL8_FAIL_NAN Failure.
178 */
180{
181 double horizon_distance = XLALMeasureStandardSirenHorizonDistance(psd, f_min, f_max);
182 if (XLAL_IS_REAL8_FAIL_NAN(horizon_distance))
184 return horizon_distance / LAL_HORIZON_DISTANCE_OVER_SENSEMON_RANGE;
185}
186
187/**
188 * @brief Computes the horizon distance for a binary neutron star standard
189 * siren signal for a given one-sided detector noise power spectral density.
190 *
191 * The "Standard Siren" is a restricted (0 pN in amplitude) gravitational
192 * waveform produced by a binary neutron star system comprised of two neutron
193 * stars, each having a mass of 1.4 Msun. A circular inspiral of point
194 * particles is also assumed. The horizon distance is the distance at which
195 * such a system that is optimally oriented (face on) and located (at an
196 * interferometer's zenith) would induce a characteristic signal-to-noise
197 * ratio of 8. No cosmological effects are included in this horizon distance
198 * measure.
199 *
200 * @note
201 * The siren has a maximum gravitational wave frequency equal to twice the
202 * innermost stable cirucluar orbit (ISCO) frequency for a Schwarzschild black
203 * hole of the same total mass as the system. This upper frequency is
204 * \f[ f_{\rm isco} = \frac{c^3}{\pi 6^{3/2} G M} = 1570 {\rm Hz} \f]
205 * where \f$M=2.8M_\odot\f$. If @p f_max is above this ISCO frequency, or
206 * negative, then the ISCO frequency is used; otherwise @p f_max is used.
207 *
208 * @note
209 * Other implementations have used a different value for the ISCO frequency.
210 * The SenseMonitor adopts a dimensionless orbital frequency value of
211 * \f$Mf_{\rm orb}=0.0098325\f$ in geometric units for the equal mass case,
212 * while Table I of Kidder, Will, and Wiseman, Physical Review D @b 47 3281
213 * (1993) http://dx.doi.org/10.1103/PhysRevD.47.3281 gives a value of 0.00933.
214 * For comparison, the Schwarzschild ISCO is 16% larger:
215 * \f$Mf_{\rm orb}=1/(2\pi 6^{3/2})=0.0108\f$.
216 *
217 * See XLALMeasureSNRFD() for further discussion about characteristic
218 * signal-to-noise ratios.
219 *
220 * @sa Appendix D of
221 * Bruce Allen, Warren G. Anderson, Patrick R. Brady, Duncan A. Brown, and
222 * Jolien D. E. Creighton, "FINDCHIRP: An algorithm for detection of
223 * gravitational waves from inspiraling compact binaries", Phys. Rev. D @b 85,
224 * 122006 (2012) http://dx.doi.org/10.1103/PhysRevD.85.122006
225 *
226 * @param[in] psd The one-sided detector strain noise power spectral density.
227 * @param[in] f_min The lower bound of the frequency band over which the
228 * signal-to-noise ratio will be computed; set to 0 or a negative value for no
229 * lower bound.
230 * @param[in] f_max The upper bound of the frequency band over which the
231 * signal-to-noise ratio will be computed; set to a negative value for
232 * no upper bound.
233 * @returns The horizon distance in meters.
234 * @retval LAL_REAL8_FAIL_NAN Failure.
235 */
237{
238 double Mpc = 1e6 * LAL_PC_SI;
239 double snr_8 = 8.0;
240 double snr;
242 if (XLAL_IS_REAL8_FAIL_NAN(snr))
244 return Mpc * snr / snr_8;
245}
246
247/**
248 * @brief Computes the characteristic signal-to-noise for a binary neutron star
249 * standard siren signal located at an effective distance of 1 Mpc for a given
250 * one-sided detector noise power spectral density.
251 *
252 * The "Standard Siren" is a restricted (0 pN in amplitude) gravitational
253 * waveform produced by a binary neutron star system comprised of two neutron
254 * stars, each having a mass of 1.4 Msun, that is optimally oriented (face on)
255 * and located (at an interferometer's zenith) at a distance of 1 Mpc. A
256 * circular inspiral of point particles is also assumed. No cosmological
257 * effects are included in this standard siren.
258 *
259 * @note
260 * The siren has a maximum gravitational wave frequency equal to twice the
261 * innermost stable cirucluar orbit (ISCO) frequency for a Schwarzschild black
262 * hole of the same total mass as the system. This upper frequency is
263 * \f[ f_{\rm isco} = \frac{c^3}{\pi 6^{3/2} G M} = 1570 {\rm Hz} \f]
264 * where \f$M=2.8M_\odot\f$. If @p f_max is above this ISCO frequency, or
265 * negative, then the ISCO frequency is used; otherwise @p f_max is used.
266 *
267 * @note
268 * Other implementations have used a different value for the ISCO frequency.
269 * The SenseMonitor adopts a dimensionless orbital frequency value of
270 * \f$Mf_{\rm orb}=0.0098325\f$ in geometric units for the equal mass case,
271 * while Table I of Kidder, Will, and Wiseman, Physical Review D @b 47 3281
272 * (1993) http://dx.doi.org/10.1103/PhysRevD.47.3281 gives a value of 0.00933.
273 * For comparison, the Schwarzschild ISCO is 16% larger:
274 * \f$Mf_{\rm orb}=1/(2\pi 6^{3/2})=0.0108\f$.
275 *
276 * Implements Eq. (D1) of FINDCHIRP for a 1.4 Msun + 1.4 Msun binary neutron
277 * star standard siren at an effective distance 1 Mpc, but with the specified
278 * limits on the integral.
279 *
280 * @sa Appendix D of
281 * Bruce Allen, Warren G. Anderson, Patrick R. Brady, Duncan A. Brown, and
282 * Jolien D. E. Creighton, "FINDCHIRP: An algorithm for detection of
283 * gravitational waves from inspiraling compact binaries", Phys. Rev. D @b 85,
284 * 122006 (2012) http://dx.doi.org/10.1103/PhysRevD.85.122006
285 *
286 * @param[in] psd The one-sided detector strain noise power spectral density.
287 * @param[in] f_min The lower bound of the frequency band over which the
288 * signal-to-noise ratio will be computed; set to 0 or a negative value for no
289 * lower bound.
290 * @param[in] f_max The upper bound of the frequency band over which the
291 * signal-to-noise ratio will be computed; set to a negative value for
292 * the Schwarzschild ISCO upper bound.
293 * @returns The characteristic signal-to-noise ratio of a binary neutron star
294 * standard siren at an effective distance of 1 Mpc.
295 * @retval LAL_REAL8_FAIL_NAN Failure.
296 */
298{
299 LALUnit strainSquaredPerHertzUnit = { 0, { 0, 0, 1, 0, 0, 2, 0}, { 0, 0, 0, 0, 0, 0, 0} };
300 LALUnit snrUnits;
301 size_t k, k_min, k_max;
302 double e = 0.0;
303 double sum = 0.0;
304 double prefac = 1.0;
305
306 /* standard siren constants */
307 double Mpc = 1e6 * LAL_PC_SI;
308 double m1 = 1.4; /* in solar masses */
309 double m2 = 1.4; /* in solar masses */
310 double M = m1 + m2;
311 double mu = m1 * m2 / M;
312 double f_isco = pow(6.0, -1.5) / (LAL_PI * M * LAL_MTSUN_SI);
313 double A_1_Mpc;
314
315 /* make sure that the psd has correct units
316 * and also extract any unit prefactor */
318 if (!XLALUnitIsDimensionless(&snrUnits))
319 XLAL_ERROR_REAL8(XLAL_EINVAL, "Incorrect PSD units.");
320 else
321 prefac = XLALUnitPrefactor(&snrUnits);
322
323 /* make sure that f_isco is used by default */
324 if (f_max < 0 || f_max > f_isco)
325 f_max = f_isco;
326
327 /* use smallest possible f_min if f_min is below that value */
328 if (f_min < 0 || f_min <= psd->f0)
329 f_min = psd->f0;
330
331 /* find the (inclusive) limits of the summation */
332 k_min = round((f_min - psd->f0)/psd->deltaF);
333 if (k_min == 0)
334 k_min = 1;
335
336 k_max = round((f_max - psd->f0)/psd->deltaF);
337 if (k_max > psd->data->length - 2) {
338 k_max = psd->data->length - 2;
339 }
340
341 /* domain error if integral is empty */
342 if (k_max < k_min)
343 XLAL_ERROR_REAL8(XLAL_EDOM, "Maximum frequency is below minimum frequency");
344
345 /* Kahan's compensated summation algorithm. The summation is done
346 * from lowest to highest frequency under the assumption that high
347 * frequency components tend to add more to the magnitude of the
348 * derivative. Note that because only half the components of the
349 * Fourier transform are stored a factor of 2 is added after the
350 * sum. The DC component should only count once, but it does not
351 * contribute anything to the sum so no special case is required to
352 * handle it. */
353
354 for (k = k_min; k <= k_max; ++k) {
355 double tmp = sum;
356 double f = psd->f0 + k * psd->deltaF;
357 double x;
358
359 /* make sure that psd is valid at this point */
360 /* if it is 0 then it must be infinity! */
361 if (isinf(psd->data->data[k]) || psd->data->data[k] <= 0.0)
362 continue; /* no contribution from this component */
363
364 /* what we want to add = f^{-7/3}/S(f) + "error
365 * from last iteration" */
366 x = pow(f, -7.0/3.0) / psd->data->data[k] + e;
367 /* add */
368 sum += x;
369 /* negative of what was actually added */
370 e = tmp - sum;
371 /* what didn't get added, add next time */
372 e += x;
373 }
374
375 /* because we've only summed the positive frequency components */
376 sum *= 2;
377
378 sum *= 2.0 * psd->deltaF * prefac;
379
380 /* from Eq. (3.4b) of FINDCHIRP */
381 A_1_Mpc = -sqrt(5.0 / 24.0 / LAL_PI);
382 A_1_Mpc *= (LAL_G_SI * LAL_MSUN_SI / LAL_C_SI / LAL_C_SI / Mpc);
383 A_1_Mpc *= pow(LAL_PI * LAL_G_SI * LAL_MSUN_SI / LAL_C_SI / LAL_C_SI / LAL_C_SI, -1.0/6.0);
384 A_1_Mpc *= sqrt(mu);
385 A_1_Mpc *= pow(M, 1.0/3.0);
386
387 return fabs(A_1_Mpc) * sqrt(sum);
388}
389
390/**
391 * @brief Measures the characteristic signal-to-noise ratio of a gravitational
392 * waveform represented in the frequency domain.
393 *
394 * This routine measures the characteristic signal-to-noise ratio of a signal
395 * @p htilde for a detector with a given strain noise power spectral density
396 * @p psd. Only frequency components of the signal between @p f_mim and
397 * @p f_max are included in this measurement. If @p f_min is zero or negative,
398 * no lower bound is imposed. If @p f_max is negative, no upper bound is
399 * imposed.
400 *
401 * The term @e characteristic is used to indicate that this signal-to-noise
402 * ratio is the expected value of the signal-to-noise ratio that would be
403 * measured for that signal my a perfectly-matched filter in a detector having
404 * stationary Gaussian noise with the specified power spectral density. The
405 * signal-to-noise ratio actually recorded by a matched filter is a random
406 * variable that depends on the particular instance of the noise. Thus the
407 * @e characteristic signal-to-noise ratio returned by this routine is a
408 * property of the signal and the statistical properties of the detector noise.
409 *
410 * The @e square of the signal-to-noise ratio is given by
411 * \f[
412 * (\mbox{signal-to-noise ratio})^2 =
413 * 4 \int_{f_{\rm min}}^{f_{\rm max}} \frac{|\tilde{h}(f)|^2}{S_h(f)}\,df
414 * \f]
415 * where \f$S_h(f)\f$ is the one-sided detector strain noise power spectral
416 * density and \f$\tilde{h}(f)\f$ is the Fourier transform of the signal
417 * strain time series \f$h(t)\f$
418 * \f[
419 * \tilde{h}(f) = \int_{-\infty}^\infty h(t) e^{-2\pi ift}\,dt.
420 * \f]
421 * The one-sided strain noise power spectral density is defined by
422 * \f$\langle\tilde{n}(f)\tilde{n}^\ast(f')\rangle=\frac{1}{2}S_h(|f|)\delta(f-f')\f$
423 * where \f$\tilde{n}(f)\f$ is the Fourier transform of the detector noise
424 * process \f$n(t)\f$.
425 *
426 * The discrete versions of these equations are
427 * \f[
428 * (\mbox{signal-to-noise ratio})^2 = 4 \Delta f
429 * \sum_{k=k_{\rm min}}^{k_{\rm max}} |\tilde{h}[k]|^2 / S_h[k]
430 * \f]
431 * where \f$\tilde{h}[k]\f$ for \f$0\le k<N\f$ is the discrete Fourier
432 * transform of the discrete time series \f$h[j]=h(j\Delta t)\f$ for
433 * \f$0\le j<N\f$:
434 * \f[
435 * \tilde{h}[k] = \Delta t \sum_{j=0}^{N-1} h[j] e^{-2\pi ijk/N}
436 * \f]
437 * (note the factor of \f$\Delta t\f$). Here \f$\Delta t\f$ is the sampling
438 * interval in time, \f$\Delta f=1/(N\Delta t)\f$ is the sampling interval in
439 * frequency, and \f$N\f$ is the number of points in the time series. The
440 * discrete one-sided detector strain noise power spectral density is
441 * \f$S_h[k]=2\Delta f\langle|\tilde{n}[k]|^2\rangle\f$ where
442 * \f$\tilde{n}[k]\f$ is the discrete Fourier transform of the detector noise
443 * process \f$n[j]\f$.
444 *
445 * The limits of the summation are \f$k_{\rm min}=f_{\rm min}/\Delta f\f$ and
446 * \f$k_{\rm max}=f_{\rm max}/\Delta f\f$, both rounded to the nearest integer.
447 * If \f$k_{\rm min}\f$ is less than 0, it is set to 0. If \f$k_{\rm max}\f$
448 * is negative or greater than \f$N/2\f$ rounded down, it is set to \f$N/2\f$
449 * rounded down. This ends up double-counting the DC and a possible Nyquist
450 * component, but it is assumed these terms have negligible contribution to the
451 * sum and there is no special case to handle them separately (most likely,
452 * the detector will have no sensitivity to those components anyway).
453 *
454 * This routine will accept frequency series \f$\tilde{h}\f$ and \f$S_h\f$ that
455 * have different frequency resolutions (i.e., different \f$\Delta f\f$). In
456 * this case, a new frequency series \f$S_h\f$ is computed with the same
457 * resolution as \f$\tilde{h}\f$ by interpolation. A simple linear
458 * interpolation in the logarithm of the power spectral density is used. Any
459 * points where the power spectral density is zero are considered to be invalid
460 * and are omitted from the sum.
461 *
462 * @param[in] htilde The Fourier transform of the signal strain.
463 * @param[in] psd The one-sided detector strain noise power spectral density.
464 * @param[in] f_min The lower bound of the frequency band over which the
465 * signal-to-noise ratio will be computed; set to 0 or a negative value for no
466 * lower bound.
467 * @param[in] f_max The upper bound of the frequency band over which the
468 * signal-to-noise ratio will be computed; set to a negative value for
469 * no upper bound.
470 * @returns The characteristic signal to noise ratio.
471 * @retval LAL_REAL8_FAIL_NAN Failure.
472 */
473double XLALMeasureSNRFD(const COMPLEX16FrequencySeries *htilde, const REAL8FrequencySeries *psd, double f_min, double f_max)
474{
475 LALUnit snrUnits;
477 size_t k, k_min, k_max;
478 double e = 0.0;
479 double sum = 0.0;
480 double prefac = 1.0;
481
482 XLAL_CHECK_REAL8(htilde && psd, XLAL_EFAULT);
483 XLAL_CHECK_REAL8(htilde->f0 >= 0.0 && psd->f0 >= 0.0, XLAL_EINVAL, "Can only handle non-negative frequencies");
484
485 /* make sure that snr units will be dimensionless,
486 *
487 * snr ~ deltaF * |htilde|^2 / psd
488 *
489 * and also compute snr unit prefactor */
490 XLALUnitSquare(&snrUnits, &htilde->sampleUnits);
491 XLALUnitDivide(&snrUnits, &snrUnits, &psd->sampleUnits);
492 XLALUnitMultiply(&snrUnits, &snrUnits, &lalHertzUnit);
493 if (!XLALUnitIsDimensionless(&snrUnits))
494 XLAL_ERROR_REAL8(XLAL_EINVAL, "Incompatible frequency series: incorrect sample units");
495 else
496 prefac = XLALUnitPrefactor(&snrUnits);
497
498 /* find the (inclusive) limits of the summation */
499 if (f_min < 0 || f_min <= htilde->f0)
500 k_min = 0;
501 else
502 k_min = round((f_min - htilde->f0)/htilde->deltaF);
503
504 if (f_max < 0 || f_max >= htilde->f0 + htilde->data->length * htilde->deltaF)
505 k_max = htilde->data->length - 1;
506 else {
507 k_max = round((f_max - htilde->f0)/htilde->deltaF);
508 if (k_max >= htilde->data->length - 1) {
509 k_max = htilde->data->length - 1;
510 }
511 }
512
513 /* interpolate psd if necessary */
514 S = create_interpolated_psd(htilde->f0, htilde->deltaF, htilde->data->length, psd);
515 if (!S)
517
518 /* Kahan's compensated summation algorithm. The summation is done
519 * from lowest to highest frequency under the assumption that high
520 * frequency components tend to add more to the magnitude of the
521 * derivative. Note that because only half the components of the
522 * Fourier transform are stored a factor of 2 is added after the
523 * sum. The DC component should only count once, but it does not
524 * contribute anything to the sum so no special case is required to
525 * handle it. */
526
527 for (k = k_min; k <= k_max; ++k) {
528 double tmp = sum;
529 double x;
530
531 /* make sure that psd is valid at this point */
532 /* if it is 0 then it must be infinity! */
533 if (isinf(S->data->data[k]) || S->data->data[k] <= 0.0)
534 continue; /* no contribution from this component */
535
536 /* what we want to add = |\tilde{h}(f)|^{2}/S(f) + "error
537 * from last iteration" */
538 x = pow(cabs(htilde->data->data[k]), 2) / S->data->data[k] + e;
539 /* add */
540 sum += x;
541 /* negative of what was actually added */
542 e = tmp - sum;
543 /* what didn't get added, add next time */
544 e += x;
545 }
546
547 /* because we've only summed the positive frequency components,
548 * multiply sum by two; note that we assume that the DC and Nyquist
549 * components do not contribute significantly to the sum, so there is
550 * no special case to handle these separately */
551 sum *= 2;
552
553 sum *= 2.0 * htilde->deltaF * prefac;
554
555 if (S != psd)
557
558 return sqrt(sum);
559}
560
561/**
562 * @brief Measures the characteristic signal-to-noise ratio of a gravitational
563 * waveform.
564 *
565 * This routine measures the characteristic signal-to-noise ratio of a signal
566 * @p h for a detector with a given strain noise power spectral density @p psd.
567 * Only frequency components of the signal between @p f_mim and @p f_max are
568 * included in this measurement. If @p f_min is zero or negative, no lower
569 * bound is imposed. If @p f_max is negative, no upper bound is imposed.
570 *
571 * A copy of the strain time series @p h is zero padded up to the next power of
572 * two in length and then Fourier transformed; the routine XLALMeasureSNRFD()
573 * is then used to compute the characteristic signal-to-noise ratio. See
574 * XLALMeasureSNRFD() for further details.
575 *
576 * @param[in] h The strain time series of the signal.
577 * @param[in] psd The one-sided detector strain noise power spectral density.
578 * @param[in] f_min The lower bound of the frequency band over which the
579 * signal-to-noise ratio will be computed; set to 0 or a negative value for no
580 * lower bound.
581 * @param[in] f_max The upper bound of the frequency band over which the
582 * signal-to-noise ratio will be computed; set to a negative value for
583 * no upper bound.
584 * @returns The characteristic signal to noise ratio.
585 * @retval LAL_REAL8_FAIL_NAN Failure.
586 */
587double XLALMeasureSNR(const REAL8TimeSeries *h, const REAL8FrequencySeries *psd, double f_min, double f_max)
588{
589 REAL8FFTPlan *plan;
590 REAL8TimeSeries *hpadded;
592 size_t new_length;
593 int length_exp;
594 double snr;
595
596 XLAL_CHECK_REAL8(h && psd, XLAL_EFAULT);
597
598 /* zero-pad to the next power of two in length */
599 frexp(h->data->length, &length_exp);
600 new_length = (size_t)ldexp(1.0, length_exp);
601
602 /* create a new time series padded at the end.
603 * first, copy the series, then resize it. */
604 hpadded = XLALCutREAL8TimeSeries(h, 0, h->data->length);
605 hpadded = XLALResizeREAL8TimeSeries(hpadded, 0, new_length);
606 htilde = XLALCreateCOMPLEX16FrequencySeries(NULL, &hpadded->epoch, 0.0, 0.0, &lalDimensionlessUnit, hpadded->data->length / 2 + 1);
607 plan = XLALCreateForwardREAL8FFTPlan(hpadded->data->length, 0);
608 if (!hpadded || !plan || !htilde) {
613 }
614
615 if (XLALREAL8TimeFreqFFT(htilde, hpadded, plan) < 0) {
620 }
623
624 snr = XLALMeasureSNRFD(htilde, psd, f_min, f_max);
625
627
628 if (XLAL_IS_REAL8_FAIL_NAN(snr))
630
631 return snr;
632}
static REAL8FrequencySeries * create_interpolated_psd(double f0, double deltaF, size_t length, const REAL8FrequencySeries *old)
Creates a new interpolated psd from an existing psd (if necessary).
Definition: LALSimUtils.c:54
static REAL8 sum(REAL8 *arr1, REAL8 *arr2, int k)
REAL8 M
Definition: bh_qnmode.c:133
double i
Definition: bh_ringdown.c:118
double e
Definition: bh_ringdown.c:117
static LALUnit strainSquaredPerHertzUnit
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
REAL8FrequencySeries * XLALResizeREAL8FrequencySeries(REAL8FrequencySeries *series, int first, size_t length)
REAL8FrequencySeries * XLALCreateREAL8FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
REAL8FrequencySeries * XLALCutREAL8FrequencySeries(const REAL8FrequencySeries *series, size_t first, size_t length)
void XLALDestroyREAL8FrequencySeries(REAL8FrequencySeries *series)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
#define LAL_C_SI
#define LAL_MSUN_SI
#define LAL_REAL8_EPS
#define LAL_PI
#define LAL_MTSUN_SI
#define LAL_PC_SI
#define LAL_G_SI
double XLALMeasureStandardSirenHorizonDistance(const REAL8FrequencySeries *psd, double f_min, double f_max)
Computes the horizon distance for a binary neutron star standard siren signal for a given one-sided d...
Definition: LALSimUtils.c:236
double XLALMeasureStandardSirenSenseMonitorRange(const REAL8FrequencySeries *psd, double f_min, double f_max)
Computes the sense-monitor range for a binary neutron star standard siren signal for a given one-side...
Definition: LALSimUtils.c:179
#define LAL_HORIZON_DISTANCE_OVER_SENSEMON_RANGE
Ratio of horizon distance to sense-monitor range.
Definition: LALSimUtils.h:56
double XLALMeasureSNR(const REAL8TimeSeries *h, const REAL8FrequencySeries *psd, double f_min, double f_max)
Measures the characteristic signal-to-noise ratio of a gravitational waveform.
Definition: LALSimUtils.c:587
double XLALMeasureSNRFD(const COMPLEX16FrequencySeries *htilde, const REAL8FrequencySeries *psd, double f_min, double f_max)
Measures the characteristic signal-to-noise ratio of a gravitational waveform represented in the freq...
Definition: LALSimUtils.c:473
double XLALMeasureStandardSirenSNR(const REAL8FrequencySeries *psd, double f_min, double f_max)
Computes the characteristic signal-to-noise for a binary neutron star standard siren signal located a...
Definition: LALSimUtils.c:297
void XLALDestroyREAL8FFTPlan(REAL8FFTPlan *plan)
REAL8FFTPlan * XLALCreateForwardREAL8FFTPlan(UINT4 size, int measurelvl)
int XLALREAL8TimeFreqFFT(COMPLEX16FrequencySeries *freq, const REAL8TimeSeries *tser, const REAL8FFTPlan *plan)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
REAL8TimeSeries * XLALResizeREAL8TimeSeries(REAL8TimeSeries *series, int first, size_t length)
REAL8TimeSeries * XLALCutREAL8TimeSeries(const REAL8TimeSeries *series, size_t first, size_t length)
int XLALUnitIsDimensionless(const LALUnit *unit)
REAL8 XLALUnitPrefactor(const LALUnit *unit)
const LALUnit lalHertzUnit
const LALUnit lalDimensionlessUnit
LALUnit * XLALUnitDivide(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
LALUnit * XLALUnitMultiply(LALUnit *output, const LALUnit *unit1, const LALUnit *unit2)
LALUnit * XLALUnitSquare(LALUnit *output, const LALUnit *input)
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR(...)
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_IS_REAL8_FAIL_NAN(val)
XLAL_EFAULT
XLAL_EFUNC
XLAL_EDOM
XLAL_EINVAL
list mu
x
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8Sequence * data
CHAR name[LALNameLength]
REAL8Sequence * data
LIGOTimeGPS epoch
REAL8 * data
double f_min
Definition: unicorn.c:22
double f_max
Definition: unicorn.c:23