Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALBurst 2.0.7.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros Modules Pages
EPFilters.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007,2011,2012 Kipp Cannon
3 * Copyright (C) 2012,2013 Reinhard Prix, Karl Wette
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 * Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20
21/*
22 * ============================================================================
23 *
24 * Preamble
25 *
26 * ============================================================================
27 */
28
29
30#include <complex.h>
31#include <math.h>
32
33
34#include <lal/EPSearch.h>
35#include <lal/FrequencySeries.h>
36#include <lal/Sequence.h>
37#include <lal/TimeFreqFFT.h>
38#include <lal/Units.h>
39#include <lal/Window.h>
40#include <lal/XLALError.h>
41
42static double min(double a, double b) { return a < b ? a : b; }
43static double max(double a, double b) { return a > b ? a : b; }
44
45
46/*
47 * ============================================================================
48 *
49 * Channel Filter Management
50 *
51 * ============================================================================
52 */
53
54
55/**
56 * Compute the magnitude of the inner product of two arbitrary channel
57 * filters. Note that the sums are done over only the positive frequency
58 * components, so this function multiplies by the required factor of 2.
59 * The result is the *full* inner product, not the half inner product. It
60 * is safe to pass the same filter as both arguments. If the PSD is set to
61 * NULL then no PSD weighting is applied. PSD weighting is only used in
62 * reconstructing h_rss.
63 *
64 * The return value is NaN if the input frequency series have incompatible
65 * parameters. Note that the two-point spectral correlation function does
66 * not carry enough metadata to determine if it is compatible with the
67 * filters or PSD, for example it does not carry a deltaF parameter. It is
68 * left as an excercise for the calling code to ensure the two-point
69 * spectral correlation is appropriate.
70 */
71
72
74 const COMPLEX16FrequencySeries *filter1, /**< frequency-domain filter */
75 const COMPLEX16FrequencySeries *filter2, /**< frequency-domain filter */
76 const REAL8Sequence *correlation, /**< two-point spectral correlation function. see XLALREAL8WindowTwoPointSpectralCorrelation(). */
77 const REAL8FrequencySeries *psd /**< power spectral density function. see XLALREAL8AverageSpectrumWelch() and friends. */
78)
79{
80 const int k10 = round(filter1->f0 / filter1->deltaF);
81 const int k20 = round(filter2->f0 / filter2->deltaF);
82 const double complex *f1data = filter1->data->data;
83 const double complex *f2data = filter2->data->data;
84 const double *pdata = psd ? psd->data->data - (int) round(psd->f0 / psd->deltaF) : NULL;
85 int k1, k2;
86 double complex sum = 0;
87
88 /*
89 * check that filters have same frequency resolution, and if a PSD
90 * is provided that it also has the same frequency resolution and
91 * spans the frequencies spanned by the fitlers
92 */
93
94 if(filter1->deltaF != filter2->deltaF || (psd &&
95 (psd->deltaF != filter1->deltaF || psd->f0 > min(filter1->f0, filter2->f0) || max(filter1->f0 + filter1->data->length * filter1->deltaF, filter2->f0 + filter2->data->length * filter2->deltaF) > psd->f0 + psd->data->length * psd->deltaF)
96 )) {
97 XLALPrintError("%s(): filters are incompatible or PSD does not span filters' frequencies", __func__);
99 }
100
101 /*
102 * compute and return inner product
103 */
104
105 for(k1 = 0; k1 < (int) filter1->data->length; k1++) {
106 for(k2 = 0; k2 < (int) filter2->data->length; k2++) {
107 const unsigned delta_k = abs(k10 + k1 - k20 - k2);
108 double sksk = (delta_k & 1 ? -1 : +1) * (delta_k < correlation->length ? correlation->data[delta_k] : 0);
109
110 if(pdata)
111 sksk *= sqrt(pdata[k10 + k1] * pdata[k20 + k2]);
112
113 sum += sksk * f1data[k1] * conj(f2data[k2]);
114 }
115 }
116
117 return 2 * cabs(sum);
118}
119
120
121/**
122 * Generate the frequency domain channel filter function. The filter
123 * corresponds to a frequency band [channel_flow, channel_flow +
124 * channel_width]. The filter is nominally a Hann window twice the
125 * channel's width, centred on the channel's centre frequency. This makes
126 * a sum across channels equivalent to constructing a Tukey window spanning
127 * the same frequency band. This trick is one of the ingredients that
128 * allows us to accomplish a multi-resolution tiling using a single
129 * frequency channel projection (*).
130 *
131 * The filter is normalized so that its "magnitude" as defined by the inner
132 * product function XLALExcessPowerFilterInnerProduct() is N. Then the
133 * filter is divided by the square root of the PSD frequency series prior
134 * to normalilization. This has the effect of de-emphasizing frequency
135 * bins with high noise content, and is called "over whitening".
136 *
137 * Note: the number of samples in the window is odd, being one more than
138 * the number of frequency bins in twice the channel width. This gets the
139 * Hann windows to super-impose to form a Tukey window. (you'll have to
140 * draw yourself a picture).
141 *
142 * (*) Really, there's no need for the "effective window" resulting from
143 * summing across channels to be something that has a name, any channel
144 * filter at all would do, but this way the code's behaviour is more easily
145 * understood --- it's easy to say "the channel filter is a Tukey window of
146 * variable central width".
147 */
148
149
151 double channel_flow, /**< Hz */
152 double channel_width, /**< Hz */
153 const REAL8FrequencySeries *psd, /**< power spectral density function. see XLALREAL8AverageSpectrumWelch() and friends. */
154 const REAL8Sequence *correlation /**< two-point spectral correlation function. see XLALREAL8WindowTwoPointSpectralCorrelation(). */
155)
156{
157 char filter_name[100];
158 REAL8Window *hann;
160 unsigned i;
161 double norm;
162
163 /*
164 * create frequency series for filter
165 */
166
167 sprintf(filter_name, "channel %g +/- %g Hz", channel_flow + channel_width / 2, channel_width / 2);
168 filter = XLALCreateCOMPLEX16FrequencySeries(filter_name, &psd->epoch, channel_flow - channel_width / 2, psd->deltaF, &lalDimensionlessUnit, 2 * channel_width / psd->deltaF + 1);
169 if(!filter)
171 if(filter->f0 < 0.0) {
172 XLALPrintError("%s(): channel_flow - channel_width / 2 >= 0.0 failed", __func__);
175 }
176
177 /*
178 * build real-valued Hann window and copy into filter
179 */
180
181 hann = XLALCreateHannREAL8Window(filter->data->length);
182 if(!hann) {
186 }
187 for(i = 0; i < filter->data->length; i++)
188 filter->data->data[i] = hann->data->data[i];
190
191 /*
192 * divide by square root of PSD to whiten
193 */
194
195 if(!XLALWhitenCOMPLEX16FrequencySeries(filter, psd)) {
198 }
199
200 /*
201 * normalize the filter. the filter needs to be normalized so that
202 * it's inner product with itself is (width / delta F), the width
203 * of the filter in bins.
204 */
205
206 norm = XLALExcessPowerFilterInnerProduct(filter, filter, correlation, NULL);
207 if(XLAL_IS_REAL8_FAIL_NAN(norm)) {
210 }
211 norm = sqrt(channel_width / filter->deltaF / norm);
212 for(i = 0; i < filter->data->length; i++)
213 filter->data->data[i] *= norm;
214
215 /*
216 * success
217 */
218
219 return filter;
220}
static double max(double a, double b)
Definition: EPFilters.c:43
static double min(double a, double b)
Definition: EPFilters.c:42
double i
coeffs k2
coeffs k1
COMPLEX16FrequencySeries * XLALCreateExcessPowerFilter(double channel_flow, double channel_width, const REAL8FrequencySeries *psd, const REAL8Sequence *correlation)
Generate the frequency domain channel filter function.
Definition: EPFilters.c:150
double XLALExcessPowerFilterInnerProduct(const COMPLEX16FrequencySeries *filter1, const COMPLEX16FrequencySeries *filter2, const REAL8Sequence *correlation, const REAL8FrequencySeries *psd)
Compute the magnitude of the inner product of two arbitrary channel filters.
Definition: EPFilters.c:73
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
static const INT4 a
COMPLEX16FrequencySeries * XLALWhitenCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *fseries, const REAL8FrequencySeries *psd)
const LALUnit lalDimensionlessUnit
void XLALDestroyREAL8Window(REAL8Window *window)
REAL8Window * XLALCreateHannREAL8Window(UINT4 length)
#define XLAL_ERROR_REAL8(...)
#define XLAL_ERROR_NULL(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_IS_REAL8_FAIL_NAN(val)
XLAL_EFUNC
XLAL_EINVAL
COMPLEX16Sequence * data
COMPLEX16 * data
REAL8Sequence * data
REAL8 * data
REAL8Sequence * data