LALBurst  2.0.4.1-b72065a
EPSearch.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (C) 2007 Brady, P. and Kipp Cannon
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 <gsl/gsl_blas.h>
35 #include <gsl/gsl_matrix.h>
36 #include <gsl/gsl_vector.h>
37 
38 
39 #include <lal/Date.h>
40 #include <lal/EPSearch.h>
41 #include <lal/FrequencySeries.h>
42 #include <lal/LALChisq.h>
43 #include <lal/LALDatatypes.h>
44 #include <lal/LALMalloc.h>
45 #include <lal/LALStdlib.h>
46 #include <lal/LIGOLwXMLArray.h>
47 #include <lal/LIGOMetadataTables.h>
48 #include <lal/LIGOMetadataUtils.h>
49 #include <lal/RealFFT.h>
50 #include <lal/SnglBurstUtils.h>
51 #include <lal/TimeFreqFFT.h>
52 #include <lal/TimeSeries.h>
53 #include <lal/Units.h>
54 #include <lal/XLALError.h>
55 #include <lal/Window.h>
56 
57 
58 static double min(double a, double b)
59 {
60  return a < b ? a : b;
61 }
62 
63 
64 static double max(double a, double b)
65 {
66  return a > b ? a : b;
67 }
68 
69 
70 /*
71  * ============================================================================
72  *
73  * Filter Bank
74  *
75  * ============================================================================
76  */
77 
78 
79 typedef struct tagExcessPowerFilter {
81  double unwhitened_rms; /**< root mean square of the unwhitened time series corresponding to this filter */
83 
84 
85 typedef struct tagLALExcessPowerFilterBank {
86  int n_filters;
88  REAL8Sequence *twice_channel_overlap; /**< twice the inner product of filters for neighbouring channels; twice_channel_overlap[0] is twice the inner product of the filters for channels 0 and 1, and so on (for n channels, there are n - 1 channel_overlaps) */
89  REAL8Sequence *unwhitened_cross; /**< the mean square cross terms for wide channels (indices same as for twice_channel_overlap) */
91 
92 
93 /**
94  * From the power spectral density function, generate the comb of channel
95  * filters for the time-frequency plane --- an excess power filter bank.
96  */
98  double filter_deltaF,
99  double flow,
100  double channel_bandwidth,
101  int n_channels,
102  const REAL8FrequencySeries *psd,
103  const REAL8Sequence *two_point_spectral_correlation
104 )
105 {
107  ExcessPowerFilter *basis_filters;
108  REAL8Sequence *twice_channel_overlap;
109  REAL8Sequence *unwhitened_cross;
110  int i;
111 
112  new = malloc(sizeof(*new));
113  basis_filters = calloc(n_channels, sizeof(*basis_filters));
114  twice_channel_overlap = XLALCreateREAL8Sequence(n_channels - 1);
115  unwhitened_cross = XLALCreateREAL8Sequence(n_channels - 1);
116  if(!new || !basis_filters || !twice_channel_overlap || !unwhitened_cross) {
117  free(new);
118  free(basis_filters);
119  XLALDestroyREAL8Sequence(twice_channel_overlap);
120  XLALDestroyREAL8Sequence(unwhitened_cross);
122  }
123 
124  new->n_filters = n_channels;
125  new->basis_filters = basis_filters;
126  new->twice_channel_overlap = twice_channel_overlap;
127  new->unwhitened_cross = unwhitened_cross;
128 
129  for(i = 0; i < n_channels; i++) {
130  basis_filters[i].fseries = XLALCreateExcessPowerFilter(flow + i * channel_bandwidth, channel_bandwidth, psd, two_point_spectral_correlation);
131  if(!basis_filters[i].fseries) {
132  while(i--)
133  XLALDestroyCOMPLEX16FrequencySeries(basis_filters[i].fseries);
134  free(new);
135  XLALDestroyREAL8Sequence(twice_channel_overlap);
136  XLALDestroyREAL8Sequence(unwhitened_cross);
138  }
139 
140  /* compute the unwhitened root mean square for this channel */
141  basis_filters[i].unwhitened_rms = sqrt(XLALExcessPowerFilterInnerProduct(basis_filters[i].fseries, basis_filters[i].fseries, two_point_spectral_correlation, psd) * filter_deltaF / 2);
142  }
143 
144  /* compute the cross terms for the channel normalizations and
145  * unwhitened mean squares */
146  for(i = 0; i < new->n_filters - 1; i++) {
147  twice_channel_overlap->data[i] = 2 * XLALExcessPowerFilterInnerProduct(basis_filters[i].fseries, basis_filters[i + 1].fseries, two_point_spectral_correlation, NULL);
148  unwhitened_cross->data[i] = XLALExcessPowerFilterInnerProduct(basis_filters[i].fseries, basis_filters[i + 1].fseries, two_point_spectral_correlation, psd) * psd->deltaF;
149  }
150 
151  return new;
152 }
153 
154 
155 /**
156  * Destroy and excess power filter bank.
157  */
160 )
161 {
162  if(bank) {
163  if(bank->basis_filters) {
164  int i;
165  for(i = 0; i < bank->n_filters; i++)
167  free(bank->basis_filters);
168  }
171  }
172 
173  free(bank);
174 }
175 
176 
177 /*
178  * ============================================================================
179  *
180  * Timing Arithmetic
181  *
182  * ============================================================================
183  */
184 
185 
186 /**
187  * Round target_length down so that an integer number of intervals of
188  * length segment_length, each shifted by segment_shift with respect to the
189  * interval preceding it, fits into the result.
190  */
192  int target_length,
193  int segment_length,
194  int segment_shift
195 )
196 {
197  unsigned segments;
198 
199  /*
200  * check input
201  */
202 
203  if(segment_length < 1) {
204  XLALPrintError("segment_length < 1");
206  }
207  if(segment_shift < 1) {
208  XLALPrintError("segment_shift < 1");
210  }
211 
212  /*
213  * trivial case
214  */
215 
216  if(target_length < segment_length)
217  return 0;
218 
219  /*
220  * do the arithmetic
221  */
222 
223  segments = (target_length - segment_length) / segment_shift;
224 
225  return segments * segment_shift + segment_length;
226 }
227 
228 
229 /**
230  * Compute and return the timing parameters for an excess power analysis.
231  * Pass NULL for any optional pointer to not compute and return that
232  * parameter. The return is 0 on success, negative on failure.
233  */
235  int window_length, /**< Number of samples in a window used for the time-frequency plane */
236  int max_tile_length, /**< Number of samples in the tile of longest duration */
237  double fractional_tile_shift, /**< Number of samples by which the start of the longest tile is shifted from the start of the tile preceding it, as a fraction of its length */
238  int *psd_length, /**< (optional) User's desired number of samples to use in computing a PSD estimate. Will be replaced with actual number of samples to use in computing a PSD estimate (rounded down to be comensurate with the windowing). */
239  int *psd_shift, /**< (optional) Number of samples by which the start of a PSD is to be shifted from the start of the PSD that preceded it in order that the tiling pattern continue smoothly across the boundary. */
240  int *window_shift, /**< Number of samples by which the start of a time-frequency plane window is shifted from the window preceding it in order that the tiling pattern continue smoothly across the boundary. */
241  int *window_pad, /**< How many samples at the start and end of each window are treated as padding, and will not be covered by the tiling. */
242  int *tiling_length /**< How many samples will be covered by the tiling. */
243 )
244 {
245  int max_tile_shift = fractional_tile_shift * max_tile_length;
246 
247  /*
248  * check input parameters
249  */
250 
251  if(window_length % 4 != 0) {
252  XLALPrintError("window_length is not a multiple of 4");
254  }
255  if(max_tile_length < 1) {
256  XLALPrintError("max_tile_length < 1");
258  }
259  if(fractional_tile_shift <= 0) {
260  XLALPrintError("fractional_tile_shift <= 0");
262  }
263  if(fmod(fractional_tile_shift * max_tile_length, 1) != 0) {
264  XLALPrintError("fractional_tile_shift * max_tile_length not an integer");
266  }
267  if(max_tile_shift < 1) {
268  XLALPrintError("fractional_tile_shift * max_tile_length < 1");
270  }
271 
272  /*
273  * discard first and last 4096 samples
274  *
275  * FIXME. this should be tied to the sample frequency and
276  * time-frequency plane's channel spacing. multiplying the time
277  * series by a window has the effect of convolving the Fourier
278  * transform of the data by the F.T. of the window, and we don't
279  * want this to blur the spectrum by an amount larger than 1
280  * channel --- a delta function in the spectrum should remain
281  * confined to a single bin. a channel width of 2 Hz means the
282  * notch feature created in the time series by the window must be
283  * at least .5 s long to not result in undesired leakage. at a
284  * sample frequency of 8192 samples / s, it must be at least 4096
285  * samples long (2048 samples at each end of the time series). to
286  * be safe, we double that to 4096 samples at each end.
287  */
288 
289  *window_pad = 4096;
290 
291  /*
292  * tiling covers the remainder, rounded down to fit an integer
293  * number of tiles
294  */
295 
296  *tiling_length = window_length - 2 * *window_pad;
297  *tiling_length = XLALOverlappedSegmentsCommensurate(*tiling_length, max_tile_length, max_tile_shift);
298  if(*tiling_length <= 0) {
299  XLALPrintError("window_length too small for tiling, must be >= 2 * %d + %d", *window_pad, max_tile_length);
301  }
302 
303  /*
304  * now re-compute window_pad from rounded-off tiling_length
305  */
306 
307  *window_pad = (window_length - *tiling_length) / 2;
308  if(*tiling_length + 2 * *window_pad != window_length) {
309  XLALPrintError("window_length does not permit equal padding before and after tiling");
311  }
312 
313  /*
314  * adjacent tilings overlap so that their largest tiles overlap the
315  * same as within each tiling
316  */
317 
318  *window_shift = *tiling_length - (max_tile_length - max_tile_shift);
319  if(*window_shift < 1) {
320  XLALPrintError("window_shift < 1");
322  }
323 
324  /*
325  * compute the adjusted PSD length if desired
326  */
327 
328  if(psd_length) {
329  *psd_length = XLALOverlappedSegmentsCommensurate(*psd_length, window_length, *window_shift);
330  if(*psd_length < 0)
332 
333  *psd_shift = *psd_length - (window_length - *window_shift);
334  if(*psd_shift < 1) {
335  XLALPrintError("psd_shift < 1");
337  }
338  } else if(psd_shift) {
339  /* for safety */
340  *psd_shift = -1;
341  /* can't compute psd_shift without psd_length input */
343  }
344 
345  return 0;
346 }
347 
348 
349 /*
350  * ============================================================================
351  *
352  * Time-Frequency Plane Create / Destroy
353  *
354  * ============================================================================
355  */
356 
357 
358 /**
359  * A time-frequency plane
360  */
361 
362 
363 typedef struct tagREAL8TimeFrequencyPlaneTiles {
364  unsigned max_length;
365  unsigned min_channels;
366  unsigned max_channels;
367  unsigned tiling_start;
368  unsigned tiling_end;
372 
373 
374 typedef struct tagREAL8TimeFrequencyPlane {
375  char name[LALNameLength]; /**< name of data from which this was computed */
376  LIGOTimeGPS epoch; /**< epoch of data from which this was computed */
377  double deltaT; /**< time resolution of the plane */
378  double fseries_deltaF; /**< input frequency series' resolution */
379  double deltaF; /**< TF plane's frequency resolution (channel spacing) */
380  double flow; /**< low frequency boundary of TF plane */
381  gsl_matrix *channel_data; /**< channel data. each channel is placed into its own column. channel_data[i * channels + j] corresponds to time epoch + i * deltaT and the frequency band [flow + j * deltaF, flow + (j + 1) * deltaF) */
382  REAL8Sequence *channel_buffer; /**< re-usable holding area for the data for a single channel */
384  REAL8TimeFrequencyPlaneTiles tiles; /**< time-frequency plane's tiling information */
385  REAL8Window *window; /**< time-domain window applied to input time series for tapering edges to 0 */
386  int window_shift; /**< by how many samples a window's start should be shifted from the start of the window preceding it */
387  REAL8Sequence *two_point_spectral_correlation; /**< two-point spectral correlation of the whitened frequency series, computed from the time-domain window function */
389 
390 
391 /**
392  * Create and initialize a time-frequency plane object.
393  */
394 
395 
397  unsigned tseries_length, /**< length of time series from which TF plane will be computed */
398  double tseries_deltaT, /**< sample rate of time series */
399  double flow, /**< minimum frequency to search for */
400  double bandwidth, /**< bandwidth of TF plane */
401  double tiling_fractional_stride, /**< overlap of adjacent tiles */
402  double max_tile_bandwidth, /**< largest tile's bandwidth */
403  double max_tile_duration, /**< largest tile's duration */
404  const REAL8FFTPlan *plan /**< forward plan whose length is tseries_length */
405 )
406 {
408  gsl_matrix *channel_data;
409  REAL8Sequence *channel_buffer;
410  REAL8Sequence *unwhitened_channel_buffer;
411  REAL8Window *tukey;
412  REAL8Sequence *correlation;
413 
414  /*
415  * resolution of FT of input time series
416  */
417 
418  const double fseries_deltaF = 1.0 / (tseries_length * tseries_deltaT);
419 
420  /*
421  * time-frequency plane's channel spacing
422  */
423 
424  const double deltaF = 1 / max_tile_duration * tiling_fractional_stride;
425 
426  /*
427  * total number of channels
428  */
429 
430  const int channels = round(bandwidth / deltaF);
431 
432  /*
433  * stride
434  */
435 
436  const unsigned inv_fractional_stride = round(1.0 / tiling_fractional_stride);
437 
438  /*
439  * tile size limits
440  */
441 
442  const unsigned min_length = round((1 / max_tile_bandwidth) / tseries_deltaT);
443  const unsigned max_length = round(max_tile_duration / tseries_deltaT);
444  const unsigned min_channels = inv_fractional_stride;
445  const unsigned max_channels = round(max_tile_bandwidth / deltaF);
446 
447  /*
448  * sample on which tiling starts
449  */
450 
451  int tiling_start;
452 
453  /*
454  * length of tiling
455  */
456 
457  int tiling_length;
458 
459  /*
460  * window shift
461  */
462 
463  int window_shift;
464 
465  /*
466  * Compute window_shift, tiling_start, and tiling_length.
467  */
468 
469  if(XLALEPGetTimingParameters(tseries_length, max_tile_duration / tseries_deltaT, tiling_fractional_stride, NULL, NULL, &window_shift, &tiling_start, &tiling_length) < 0)
471 
472  /*
473  * Make sure that input parameters are reasonable, and that a
474  * complete tiling is possible.
475  *
476  * Note that because all tile durations are integer power of two
477  * multiples of the smallest duration, if the largest duration fits
478  * an integer number of times in the tiling length, then all tile
479  * sizes do so there's no need to test them all. Likewise for the
480  * bandwidths.
481  *
482  * FIXME: these tests require an integer number of non-overlapping
483  * tiles to fit, which is stricter than required; only need an
484  * integer number of overlapping tiles to fit, but then probably
485  * have to test all sizes separately.
486  */
487 
488  if((flow < 0) ||
489  (bandwidth <= 0) ||
490  (deltaF <= 0) ||
491  (inv_fractional_stride * tiling_fractional_stride != 1) ||
492  (fmod(max_tile_duration, tseries_deltaT) != 0) ||
493  (fmod(deltaF, fseries_deltaF) != 0) ||
494  (tseries_deltaT <= 0) ||
495  (channels * deltaF != bandwidth) ||
496  (min_length * tseries_deltaT != (1 / max_tile_bandwidth)) ||
497  (min_length % inv_fractional_stride != 0) ||
498  (tiling_length % max_length != 0) ||
499  (channels % max_channels != 0)) {
500  XLALPrintError("unable to construct time-frequency tiling from input parameters\n");
502  }
503 
504  /*
505  * Allocate memory.
506  */
507 
508  plane = XLALMalloc(sizeof(*plane));
509  channel_data = gsl_matrix_alloc(tseries_length, channels);
510  channel_buffer = XLALCreateREAL8Sequence(tseries_length);
511  unwhitened_channel_buffer = XLALCreateREAL8Sequence(tseries_length);
512  tukey = XLALCreateTukeyREAL8Window(tseries_length, (tseries_length - tiling_length) / (double) tseries_length);
513  if(tukey)
514  correlation = XLALREAL8WindowTwoPointSpectralCorrelation(tukey, plan);
515  else
516  /* error path */
517  correlation = NULL;
518  if(!plane || !channel_data || !channel_buffer || !unwhitened_channel_buffer || !tukey || !correlation) {
519  XLALFree(plane);
520  if(channel_data)
521  gsl_matrix_free(channel_data);
522  XLALDestroyREAL8Sequence(channel_buffer);
523  XLALDestroyREAL8Sequence(unwhitened_channel_buffer);
524  XLALDestroyREAL8Window(tukey);
525  XLALDestroyREAL8Sequence(correlation);
527  }
528 
529  /*
530  * Initialize the structure
531  */
532 
533  plane->name[0] = '\0';
534  XLALGPSSetREAL8(&plane->epoch, 0.0);
535  plane->deltaT = tseries_deltaT;
536  plane->fseries_deltaF = fseries_deltaF;
537  plane->deltaF = deltaF;
538  plane->flow = flow;
539  plane->channel_data = channel_data;
540  plane->channel_buffer = channel_buffer;
541  plane->unwhitened_channel_buffer = unwhitened_channel_buffer;
542  plane->tiles.max_length = max_length;
543  plane->tiles.min_channels = min_channels;
544  plane->tiles.max_channels = max_channels;
545  plane->tiles.tiling_start = tiling_start;
546  plane->tiles.tiling_end = tiling_start + tiling_length;
547  plane->tiles.inv_fractional_stride = inv_fractional_stride;
548  plane->tiles.dof_per_pixel = 2 * tseries_deltaT * deltaF;
549  plane->window = tukey;
550  plane->window_shift = window_shift;
551  plane->two_point_spectral_correlation = correlation;
552 
553  /*
554  * Success
555  */
556 
557  return plane;
558 }
559 
560 
561 /**
562  * Free a time-frequency plane object.
563  */
564 
565 
566 static void XLALDestroyTFPlane(
568 )
569 {
570  if(plane) {
571  if(plane->channel_data)
572  gsl_matrix_free(plane->channel_data);
577  }
578  XLALFree(plane);
579 }
580 
581 
582 /*
583  * ============================================================================
584  *
585  * Time-Frequency Plane Projection
586  *
587  * ============================================================================
588  */
589 
590 
591 /*
592  * Multiply the data by the filter. The check that the frequency
593  * resolutions and units are compatible is omitted because it is implied by
594  * the calling code.
595  */
596 
597 
599  COMPLEX16Sequence *outputseq,
600  const COMPLEX16FrequencySeries *inputseries,
601  const COMPLEX16FrequencySeries *filterseries
602 )
603 {
604  /* find bounds of common frequencies */
605  const double flo = max(filterseries->f0, inputseries->f0);
606  const double fhi = min(filterseries->f0 + filterseries->data->length * filterseries->deltaF, inputseries->f0 + inputseries->data->length * inputseries->deltaF);
607  double complex *output = outputseq->data + (int) round((flo - inputseries->f0) / inputseries->deltaF);
608  double complex *last = outputseq->data + (int) round((fhi - inputseries->f0) / inputseries->deltaF);
609  const double complex *input = inputseries->data->data + (int) round((flo - inputseries->f0) / inputseries->deltaF);
610  const double complex *filter = filterseries->data->data + (int) round((flo - filterseries->f0) / filterseries->deltaF);
611 
612  if(outputseq->length != inputseries->data->length)
614 
615  if(((unsigned) (output - outputseq->data) > outputseq->length) || (last - outputseq->data < 0))
616  /* inputseries and filterseries don't intersect */
617  memset(outputseq->data, 0, outputseq->length * sizeof(*outputseq->data));
618  else {
619  /* output = inputseries * conj(filter) */
620  memset(outputseq->data, 0, (output - outputseq->data) * sizeof(*outputseq->data));
621  for(; output < last; output++, input++, filter++)
622  *output = *input * conj(*filter);
623  memset(last, 0, (outputseq->length - (last - outputseq->data)) * sizeof(*outputseq->data));
624  }
625 
626  return outputseq;
627 }
628 
629 
630 /*
631  * Project a frequency series onto the comb of channel filters
632  */
633 
634 
637  const LALExcessPowerFilterBank *filter_bank,
638  const COMPLEX16FrequencySeries *fseries,
639  const REAL8FFTPlan *reverseplan
640 )
641 {
642  COMPLEX16Sequence *fcorr;
643  unsigned i;
644 
645  /* check input parameters */
646  if((fmod(plane->deltaF, fseries->deltaF) != 0.0) ||
647  (fmod(plane->flow - fseries->f0, fseries->deltaF) != 0.0))
649 
650  /* make sure the frequency series spans an appropriate band */
651  if((plane->flow < fseries->f0) ||
652  (plane->flow + plane->channel_data->size2 * plane->deltaF > fseries->f0 + fseries->data->length * fseries->deltaF))
654 
655  /* create temporary vectors */
656  fcorr = XLALCreateCOMPLEX16Sequence(fseries->data->length);
657  if(!fcorr)
659 
660 #if 0
661  /* diagnostic code to dump data for the \hat{s}_{k} histogram */
662  {
663  unsigned k;
664  FILE *f = fopen("sk.dat", "a");
665  for(k = plane->flow / fseries->deltaF; k < (plane->flow + plane->channel_data->size2 * plane->deltaF) / fseries->deltaF; k++)
666  fprintf(f, "%g\n%g\n", fseries->data->data[k].re, fseries->data->data[k].im);
667  fclose(f);
668  }
669 #endif
670 #if 0
671  /* diagnostic code to dump data for the \hat{s}_{k}
672  * \hat{s}^{*}_{k'} histogram */
673  {
674  unsigned k, dk;
675  FILE *f = fopen("sksk.dat", "a");
676  for(dk = 0; dk < 100; dk++) {
677  double avg_r = 0;
678  double avg_i = 0;
679  for(k = plane->flow / fseries->deltaF; k + dk < (plane->flow + plane->channel_data->size2 * plane->deltaF) / fseries->deltaF; k++) {
680  double dr = fseries->data->data[k].re;
681  double di = fseries->data->data[k].im;
682  double dkr = fseries->data->data[k + dk].re;
683  double dki = fseries->data->data[k + dk].im;
684  avg_r += dr * dkr + di * dki;
685  avg_i += di * dkr - dr * dki;
686  }
687  avg_r /= k - plane->flow / fseries->deltaF;
688  avg_i /= k - plane->flow / fseries->deltaF;
689  fprintf(f, "%d %g %g\n", dk, avg_r, avg_i);
690  }
691  fclose(f);
692  }
693 #endif
694 
695  /* loop over the time-frequency plane's channels */
696  for(i = 0; i < plane->channel_data->size2; i++) {
697  unsigned j;
698  /* cross correlate the input data against the channel
699  * filter by taking their product in the frequency domain
700  * and then inverse transforming to the time domain to
701  * obtain an SNR time series. Note that
702  * XLALREAL8ReverseFFT() omits the factor of 1 / (N Delta
703  * t) in the inverse transform. */
704  apply_filter(fcorr, fseries, filter_bank->basis_filters[i].fseries);
705  if(XLALREAL8ReverseFFT(plane->channel_buffer, fcorr, reverseplan)) {
708  }
709  /* interleave the result into the channel_data array */
710  for(j = 0; j < plane->channel_buffer->length; j++)
711  gsl_matrix_set(plane->channel_data, j, i, plane->channel_buffer->data[j]);
712  }
713 
714  /* clean up */
716 
717  /* set the name and epoch of the TF plane */
718  strncpy(plane->name, fseries->name, LALNameLength);
719  plane->epoch = fseries->epoch;
720 
721  /* success */
722  return 0;
723 }
724 
725 
726 /*
727  * ============================================================================
728  *
729  * Tile Analysis
730  *
731  * ============================================================================
732  */
733 
734 
736  const LALExcessPowerFilterBank *filter_bank,
737  unsigned channel,
738  unsigned channels
739 )
740 {
741  unsigned i;
742  double mean_square = 0;
743 
744  for(i = channel; i < channel + channels; i++)
745  mean_square += pow(filter_bank->basis_filters[i].unwhitened_rms, 2);
746 
747  return mean_square;
748 }
749 
750 
751 /*
752  * Convert time-frequency tile info to a SnglBurst row.
753  */
754 
755 
757  const REAL8TimeFrequencyPlane *plane,
758  double tile_start, /* in samples, allowed to be non-integer */
759  double tile_length, /* in samples, allowed to be non-integer */
760  double f_centre,
761  double bandwidth,
762  double h_rss,
763  double E,
764  double d,
765  double confidence
766 )
767 {
768  SnglBurst *event = XLALCreateSnglBurst();
769 
770  if(!event)
772 
773  event->next = NULL;
774  strncpy(event->ifo, plane->name, 2);
775  event->ifo[2] = '\0';
776  strncpy(event->search, "excesspower", LIGOMETA_SEARCH_MAX);
777  event->search[LIGOMETA_SEARCH_MAX - 1] = '\0';
778  strncpy(event->channel, plane->name, LIGOMETA_CHANNEL_MAX);
779  event->channel[LIGOMETA_CHANNEL_MAX - 1] = '\0';
780  event->start_time = plane->epoch;
781  XLALGPSAdd(&event->start_time, tile_start * plane->deltaT);
782  event->duration = tile_length * plane->deltaT;
783  event->peak_time = event->start_time;
784  XLALGPSAdd(&event->peak_time, event->duration / 2);
785  event->bandwidth = bandwidth;
786  event->central_freq = f_centre;
787  /* FIXME: put h_rss into the "hrss" column */
788  event->amplitude = h_rss;
789  event->snr = E / d - 1;
790  /* -ln P(event | stationary Gaussian white noise) */
791  event->confidence = confidence;
792 
793  return event;
794 }
795 
796 
798  const REAL8TimeFrequencyPlane *plane,
799  const LALExcessPowerFilterBank *filter_bank,
800  SnglBurst *head,
801  double confidence_threshold
802 )
803 {
804  gsl_vector filter_output = {
805  .size = plane->tiles.tiling_end - plane->tiles.tiling_start,
806  .stride = plane->channel_data->size2,
807  .data = NULL,
808  .block = NULL,
809  .owner = 0
810  };
811  gsl_vector_view filter_output_view;
812  gsl_vector *channel_buffer;
813  gsl_vector *unwhitened_channel_buffer;
814  unsigned channel;
815  unsigned channels;
816  unsigned channel_end;
817  double h_rss;
818  double confidence;
819  /* number of degrees of freedom in tile = number of
820  * "virtual pixels" in tile. */
821  double tile_dof;
822  unsigned i;
823 
824  /*
825  * create work spaces
826  */
827 
828  channel_buffer = gsl_vector_alloc(filter_output.size);
829  unwhitened_channel_buffer = gsl_vector_alloc(filter_output.size);
830  if(!channel_buffer || !unwhitened_channel_buffer) {
831  if(channel_buffer)
832  gsl_vector_free(channel_buffer);
833  if(unwhitened_channel_buffer)
834  gsl_vector_free(unwhitened_channel_buffer);
836  }
837 
838  /*
839  * enter loops. note: this is a quadruply-nested loop that is not
840  * indented to help fit the code on a terminal display.
841  */
842 
843  for(channels = plane->tiles.min_channels; channels <= plane->tiles.max_channels; channels *= 2) {
844  /* compute distance between "virtual pixels" for this
845  * (wide) channel */
846  const unsigned stride = round(1.0 / (channels * plane->tiles.dof_per_pixel));
847 
848  for(channel_end = (channel = 0) + channels; channel_end <= plane->channel_data->size2; channel_end = (channel += channels / plane->tiles.inv_fractional_stride) + channels) {
849  /* the root mean square of the "virtual channel",
850  * \sqrt{\mu^{2}} in the algorithm description */
851  const double sample_rms = sqrt(channels * plane->deltaF / plane->fseries_deltaF + XLALREAL8SequenceSum(filter_bank->twice_channel_overlap, channel, channels - 1));
852  /* the root mean square of the "uwapprox" quantity computed
853  * below, which is proportional to an approximation of the
854  * unwhitened time series. */
855  double uwsample_rms;
856  /* true unwhitened root mean square for this channel. the
857  * ratio of this squared to uwsample_rms^2 is the
858  * correction factor to be applied to uwapprox^2 to convert
859  * it to an approximation of the square of the unwhitened
860  * channel */
861  const double strain_rms = sqrt(compute_unwhitened_mean_square(filter_bank, channel, channels) + XLALREAL8SequenceSum(filter_bank->unwhitened_cross, channel, channels - 1));
862 
863  /* compute uwsample_rms */
864  uwsample_rms = compute_unwhitened_mean_square(filter_bank, channel, channels);
865  for(i = channel; i < channel_end - 1; i++)
866  uwsample_rms += filter_bank->twice_channel_overlap->data[i] * filter_bank->basis_filters[i].unwhitened_rms * filter_bank->basis_filters[i + 1].unwhitened_rms * plane->fseries_deltaF / plane->deltaF;
867  uwsample_rms = sqrt(uwsample_rms);
868 
869  /* reconstruct the time series and unwhitened time series
870  * for this (possibly multi-filter) channel. both time
871  * series are normalized so that each sample has a mean
872  * square of 1 */
873  filter_output.data = plane->channel_data->data + filter_output.stride * plane->tiles.tiling_start + channel;
874  filter_output_view = gsl_vector_subvector_with_stride(&filter_output, 0, stride, filter_output.size / stride);
875  gsl_vector_set_zero(channel_buffer);
876  gsl_vector_set_zero(unwhitened_channel_buffer);
877  channel_buffer->size = unwhitened_channel_buffer->size = filter_output_view.vector.size;
878  for(i = channel; i < channel_end; filter_output_view.vector.data++, i++) {
879  gsl_blas_daxpy(1.0 / sample_rms, &filter_output_view.vector, channel_buffer);
880  gsl_blas_daxpy(filter_bank->basis_filters[i].unwhitened_rms * sqrt(plane->fseries_deltaF / plane->deltaF) / uwsample_rms, &filter_output_view.vector, unwhitened_channel_buffer);
881  }
882 
883 #if 0
884  /* diagnostic code to dump data for the s_{j} histogram */
885  {
886  FILE *f = fopen("sj.dat", "a");
887  for(i = 0; i < channel_buffer->size; i++)
888  fprintf(f, "%g\n", gsl_vector_get(unwhitened_channel_buffer, i));
889  fclose(f);
890  }
891 #endif
892 
893  /* square the samples in the channel time series because
894  * from now on that's all we'll need */
895  for(i = 0; i < channel_buffer->size; i++) {
896  gsl_vector_set(channel_buffer, i, pow(gsl_vector_get(channel_buffer, i), 2));
897  gsl_vector_set(unwhitened_channel_buffer, i, pow(gsl_vector_get(unwhitened_channel_buffer, i), 2));
898  }
899 
900  /* start with at least 2 degrees of freedom */
901  for(tile_dof = 2; tile_dof <= plane->tiles.max_length / stride; tile_dof *= 2) {
902  unsigned start;
903  for(start = 0; start + tile_dof <= channel_buffer->size; start += tile_dof / plane->tiles.inv_fractional_stride) {
904  /* compute sum of squares, and unwhitened sum of squares
905  * (samples have already been squared) */
906  double sumsquares = 0;
907  double uwsumsquares = 0;
908  for(i = start; i < start + tile_dof; i++) {
909  sumsquares += gsl_vector_get(channel_buffer, i);
910  uwsumsquares += gsl_vector_get(unwhitened_channel_buffer, i);
911  }
912 
913  /* compute statistical confidence */
914  /* FIXME: the 0.62 is an empirically determined
915  * degree-of-freedom fudge factor. figure out what its
916  * origin is, and account for it correctly. it's most
917  * likely due to the time-frequency plane pixels not being
918  * independent of one another as a consequence of a
919  * non-zero inner product of the time-domain impulse
920  * response of the channel filter for adjacent pixels */
921  confidence = -XLALLogChisqCCDF(sumsquares * .62, tile_dof * .62);
922  if(XLALIsREAL8FailNaN(confidence)) {
923  gsl_vector_free(channel_buffer);
924  gsl_vector_free(unwhitened_channel_buffer);
926  }
927 
928  /* record tiles whose statistical confidence is above
929  * threshold and that have real-valued h_rss */
930  if((confidence >= confidence_threshold) && (uwsumsquares >= tile_dof)) {
931  SnglBurst *oldhead = head;
932 
933  /* compute h_rss */
934  h_rss = sqrt((uwsumsquares - tile_dof) * (stride * plane->deltaT)) * strain_rms;
935 
936  /* add new event to head of linked list */
937  head = XLALTFTileToBurstEvent(plane, plane->tiles.tiling_start + (start - 0.5) * stride, tile_dof * stride, plane->flow + (channel + .5 * channels) * plane->deltaF, channels * plane->deltaF, h_rss, sumsquares, tile_dof, confidence);
938  if(!head) {
939  gsl_vector_free(channel_buffer);
940  gsl_vector_free(unwhitened_channel_buffer);
942  }
943  head->next = oldhead;
944  }
945  }
946  }
947  }
948  }
949 
950  /* success */
951  gsl_vector_free(channel_buffer);
952  gsl_vector_free(unwhitened_channel_buffer);
953  return head;
954 }
955 
956 
957 /*
958  * ============================================================================
959  *
960  * Entry Point
961  *
962  * ============================================================================
963  */
964 
965 
966 /**
967  * Generate a linked list of burst events from a time series.
968  */
970  LIGOLwXMLStream *diagnostics,
971  const REAL8TimeSeries *tseries,
972  REAL8Window *window,
973  double flow,
974  double bandwidth,
975  double confidence_threshold,
976  double fractional_stride,
977  double maxTileBandwidth,
978  double maxTileDuration
979 )
980 {
981  SnglBurst *head = NULL;
982  int errorcode = 0;
983  int start_sample;
984  COMPLEX16FrequencySeries *fseries;
985  REAL8FFTPlan *fplan;
986  REAL8FFTPlan *rplan;
988  REAL8TimeSeries *cuttseries = NULL;
989  LALExcessPowerFilterBank *filter_bank = NULL;
990  REAL8TimeFrequencyPlane *plane = NULL;
991 
992  /*
993  * Construct forward and reverse FFT plans, storage for the PSD,
994  * the time-frequency plane, and a tiling. Note that the flat part
995  * of the Tukey window needs to match the locations of the tiles as
996  * specified by the tiling_start parameter of XLALCreateTFPlane.
997  * The metadata for the two frequency series will be filled in
998  * later, so it doesn't all have to be correct here.
999  */
1000 
1001  fplan = XLALCreateForwardREAL8FFTPlan(window->data->length, 1);
1002  rplan = XLALCreateReverseREAL8FFTPlan(window->data->length, 1);
1003  psd = XLALCreateREAL8FrequencySeries("PSD", &tseries->epoch, 0, 0, &lalDimensionlessUnit, window->data->length / 2 + 1);
1004  fseries = XLALCreateCOMPLEX16FrequencySeries(tseries->name, &tseries->epoch, 0, 0, &lalDimensionlessUnit, window->data->length / 2 + 1);
1005  if(fplan)
1006  plane = XLALCreateTFPlane(window->data->length, tseries->deltaT, flow, bandwidth, fractional_stride, maxTileBandwidth, maxTileDuration, fplan);
1007  if(!fplan || !rplan || !psd || !fseries || !plane) {
1008  errorcode = XLAL_EFUNC;
1009  goto error;
1010  }
1011 
1012 #if 0
1013  /* diagnostic code to replace the input time series with stationary
1014  * Gaussian white noise. the normalization is such that it yields
1015  * unit variance frequency components without a call to the
1016  * whitening function. */
1017  {
1018  unsigned i;
1019  static RandomParams *rparams = NULL;
1020  if(!rparams)
1022  XLALNormalDeviates(tseries->data, rparams);
1023  for(i = 0; i < tseries->data->length; i++)
1024  tseries->data->data[i] *= sqrt(0.5 / tseries->deltaT);
1025  }
1026 #endif
1027 #if 0
1028  /* diagnostic code to disable the tapering window */
1029  {
1030  unsigned i = plane->window->data->length;
1033  }
1034 #endif
1035 
1036  /*
1037  * Compute the average spectrum.
1038  *
1039  * FIXME: is using windowShift here correct? we have to, otherwise
1040  * the time series' lengths are inconsistent
1041  */
1042 
1043  if(XLALREAL8AverageSpectrumMedian(psd, tseries, plane->window->data->length, plane->window_shift, plane->window, fplan) < 0) {
1044  errorcode = XLAL_EFUNC;
1045  goto error;
1046  }
1047 
1048  if(diagnostics)
1049  XLALWriteLIGOLwXMLArrayREAL8FrequencySeries(diagnostics, NULL, psd);
1050 
1051  /*
1052  * Construct the time-frequency plane's channel filters.
1053  */
1054 
1055  XLALPrintInfo("%s(): constructing channel filters\n", __func__);
1056  filter_bank = XLALCreateExcessPowerFilterBank(psd->deltaF, plane->flow, plane->deltaF, plane->channel_data->size2, psd, plane->two_point_spectral_correlation);
1057  if(!filter_bank) {
1058  errorcode = XLAL_EFUNC;
1059  goto error;
1060  }
1061 
1062  /*
1063  * Loop over data applying excess power method.
1064  */
1065 
1066  for(start_sample = 0; start_sample + plane->window->data->length <= tseries->data->length; start_sample += plane->window_shift) {
1067  /*
1068  * Verbosity.
1069  */
1070 
1071  XLALPrintInfo("%s(): ", __func__);
1072  XLALPrintProgressBar(start_sample / (double) (tseries->data->length - plane->window->data->length));
1073  XLALPrintInfo(" complete\n");
1074 
1075  /*
1076  * Extract a window-length of data from the time series.
1077  */
1078 
1079  cuttseries = XLALCutREAL8TimeSeries(tseries, start_sample, plane->window->data->length);
1080  if(!cuttseries) {
1081  errorcode = XLAL_EFUNC;
1082  goto error;
1083  }
1084  XLALPrintInfo("%s(): analyzing %u samples (%.9lf s) at offset %u (%.9lf s) from epoch %d.%09u s\n", __func__, cuttseries->data->length, cuttseries->data->length * cuttseries->deltaT, start_sample, start_sample * cuttseries->deltaT, tseries->epoch.gpsSeconds, tseries->epoch.gpsNanoSeconds);
1085  if(diagnostics)
1086  XLALWriteLIGOLwXMLArrayREAL8TimeSeries(diagnostics, NULL, cuttseries);
1087 
1088  /*
1089  * Window and DFT the time series.
1090  */
1091 
1092  XLALPrintInfo("%s(): computing the Fourier transform\n", __func__);
1093  if(!XLALUnitaryWindowREAL8Sequence(cuttseries->data, plane->window)) {
1094  errorcode = XLAL_EFUNC;
1095  goto error;
1096  }
1097  if(XLALREAL8TimeFreqFFT(fseries, cuttseries, fplan)) {
1098  errorcode = XLAL_EFUNC;
1099  goto error;
1100  }
1101  XLALDestroyREAL8TimeSeries(cuttseries);
1102  cuttseries = NULL;
1103 
1104  /*
1105  * Normalize the frequency series to the average PSD.
1106  */
1107 
1108 #if 1
1109  XLALPrintInfo("%s(): normalizing to the average spectrum\n", __func__);
1110  if(!XLALWhitenCOMPLEX16FrequencySeries(fseries, psd)) {
1111  errorcode = XLAL_EFUNC;
1112  goto error;
1113  }
1114  if(diagnostics)
1115  XLALWriteLIGOLwXMLArrayCOMPLEX16FrequencySeries(diagnostics, "whitened", fseries);
1116 #endif
1117 
1118  /*
1119  * Compute the time-frequency plane from the frequency
1120  * series and channel filters.
1121  */
1122 
1123  XLALPrintInfo("%s(): projecting data onto time-frequency plane\n", __func__);
1124  if(XLALFreqSeriesToTFPlane(plane, filter_bank, fseries, rplan)) {
1125  errorcode = XLAL_EFUNC;
1126  goto error;
1127  }
1128 
1129  /*
1130  * Compute the excess power for each time-frequency tile
1131  * using the data in the time-frequency plane, and add
1132  * those tiles whose confidence is above threshold to the
1133  * trigger list. Note that because it is possible for
1134  * there to be 0 triggers found, we can't check for errors
1135  * by testing for head == NULL.
1136  */
1137 
1138  XLALPrintInfo("%s(): computing the excess power for each tile\n", __func__);
1139  XLALClearErrno();
1140  head = XLALComputeExcessPower(plane, filter_bank, head, confidence_threshold);
1141  if(xlalErrno) {
1142  errorcode = XLAL_EFUNC;
1143  goto error;
1144  }
1145  }
1146 
1147  /*
1148  * Memory clean-up.
1149  */
1150 
1151  XLALPrintInfo("%s(): done\n", __func__);
1152 
1153  error:
1154  XLALDestroyREAL8FFTPlan(fplan);
1155  XLALDestroyREAL8FFTPlan(rplan);
1157  XLALDestroyREAL8TimeSeries(cuttseries);
1159  XLALDestroyExcessPowerFilterBank(filter_bank);
1160  XLALDestroyTFPlane(plane);
1161  if(errorcode) {
1163  XLAL_ERROR_NULL(errorcode);
1164  }
1165  return(head);
1166 }
static SnglBurst * XLALComputeExcessPower(const REAL8TimeFrequencyPlane *plane, const LALExcessPowerFilterBank *filter_bank, SnglBurst *head, double confidence_threshold)
Definition: EPSearch.c:797
static SnglBurst * XLALTFTileToBurstEvent(const REAL8TimeFrequencyPlane *plane, double tile_start, double tile_length, double f_centre, double bandwidth, double h_rss, double E, double d, double confidence)
Definition: EPSearch.c:756
static double max(double a, double b)
Definition: EPSearch.c:64
static COMPLEX16Sequence * apply_filter(COMPLEX16Sequence *outputseq, const COMPLEX16FrequencySeries *inputseries, const COMPLEX16FrequencySeries *filterseries)
Definition: EPSearch.c:598
static void XLALDestroyExcessPowerFilterBank(LALExcessPowerFilterBank *bank)
Destroy and excess power filter bank.
Definition: EPSearch.c:158
static double compute_unwhitened_mean_square(const LALExcessPowerFilterBank *filter_bank, unsigned channel, unsigned channels)
Definition: EPSearch.c:735
static REAL8TimeFrequencyPlane * XLALCreateTFPlane(unsigned tseries_length, double tseries_deltaT, double flow, double bandwidth, double tiling_fractional_stride, double max_tile_bandwidth, double max_tile_duration, const REAL8FFTPlan *plan)
Create and initialize a time-frequency plane object.
Definition: EPSearch.c:396
static void XLALDestroyTFPlane(REAL8TimeFrequencyPlane *plane)
Free a time-frequency plane object.
Definition: EPSearch.c:566
static int XLALFreqSeriesToTFPlane(REAL8TimeFrequencyPlane *plane, const LALExcessPowerFilterBank *filter_bank, const COMPLEX16FrequencySeries *fseries, const REAL8FFTPlan *reverseplan)
Definition: EPSearch.c:635
static LALExcessPowerFilterBank * XLALCreateExcessPowerFilterBank(double filter_deltaF, double flow, double channel_bandwidth, int n_channels, const REAL8FrequencySeries *psd, const REAL8Sequence *two_point_spectral_correlation)
From the power spectral density function, generate the comb of channel filters for the time-frequency...
Definition: EPSearch.c:97
static double min(double a, double b)
Definition: EPSearch.c:58
int XLALWriteLIGOLwXMLArrayREAL8TimeSeries(LIGOLwXMLStream *xml, const char *comment, const REAL8TimeSeries *series)
int XLALWriteLIGOLwXMLArrayCOMPLEX16FrequencySeries(LIGOLwXMLStream *xml, const char *comment, const COMPLEX16FrequencySeries *series)
int XLALWriteLIGOLwXMLArrayREAL8FrequencySeries(LIGOLwXMLStream *xml, const char *comment, const REAL8FrequencySeries *series)
#define LIGOMETA_SEARCH_MAX
#define LIGOMETA_CHANNEL_MAX
SnglBurst * XLALCreateSnglBurst(void)
void XLALDestroySnglBurstTable(SnglBurst *head)
#define fprintf
const char *const name
double i
double flow
int XLALOverlappedSegmentsCommensurate(int target_length, int segment_length, int segment_shift)
Round target_length down so that an integer number of intervals of length segment_length,...
Definition: EPSearch.c:191
SnglBurst * XLALEPSearch(LIGOLwXMLStream *diagnostics, const REAL8TimeSeries *tseries, REAL8Window *window, double flow, double bandwidth, double confidence_threshold, double fractional_stride, double maxTileBandwidth, double maxTileDuration)
Generate a linked list of burst events from a time series.
Definition: EPSearch.c:969
int XLALEPGetTimingParameters(int window_length, int max_tile_length, double fractional_tile_shift, int *psd_length, int *psd_shift, int *window_shift, int *window_pad, int *tiling_length)
Compute and return the timing parameters for an excess power analysis.
Definition: EPSearch.c:234
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
REAL8FrequencySeries * XLALCreateREAL8FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
COMPLEX16FrequencySeries * XLALCreateCOMPLEX16FrequencySeries(const CHAR *name, const LIGOTimeGPS *epoch, REAL8 f0, REAL8 deltaF, const LALUnit *sampleUnits, size_t length)
void XLALDestroyREAL8FrequencySeries(REAL8FrequencySeries *series)
void XLALDestroyCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *series)
double XLALLogChisqCCDF(double chi2, double dof)
LALNameLength
void * XLALMalloc(size_t n)
void XLALFree(void *p)
RandomParams * XLALCreateRandomParams(INT4 seed)
int XLALNormalDeviates(REAL4Vector *deviates, RandomParams *params)
static const INT4 a
int XLALREAL8ReverseFFT(REAL8Vector *output, const COMPLEX16Vector *input, const REAL8FFTPlan *plan)
void XLALDestroyREAL8FFTPlan(REAL8FFTPlan *plan)
REAL8FFTPlan * XLALCreateReverseREAL8FFTPlan(UINT4 size, int measurelvl)
REAL8FFTPlan * XLALCreateForwardREAL8FFTPlan(UINT4 size, int measurelvl)
REAL8 XLALREAL8SequenceSum(const REAL8Sequence *sequence, size_t first, size_t count)
void XLALDestroyREAL8Sequence(REAL8Sequence *sequence)
void XLALDestroyCOMPLEX16Sequence(COMPLEX16Sequence *sequence)
REAL8Sequence * XLALCreateREAL8Sequence(size_t length)
COMPLEX16Sequence * XLALCreateCOMPLEX16Sequence(size_t length)
REAL8Sequence * XLALREAL8WindowTwoPointSpectralCorrelation(const REAL8Window *window, const REAL8FFTPlan *plan)
int XLALREAL8AverageSpectrumMedian(REAL8FrequencySeries *spectrum, const REAL8TimeSeries *tseries, UINT4 seglen, UINT4 stride, const REAL8Window *window, const REAL8FFTPlan *plan)
int XLALREAL8TimeFreqFFT(COMPLEX16FrequencySeries *freq, const REAL8TimeSeries *tser, const REAL8FFTPlan *plan)
COMPLEX16FrequencySeries * XLALWhitenCOMPLEX16FrequencySeries(COMPLEX16FrequencySeries *fseries, const REAL8FrequencySeries *psd)
REAL8TimeSeries * XLALCutREAL8TimeSeries(const REAL8TimeSeries *series, size_t first, size_t length)
void XLALDestroyREAL8TimeSeries(REAL8TimeSeries *series)
const LALUnit lalDimensionlessUnit
REAL8Window * XLALCreateRectangularREAL8Window(UINT4 length)
void XLALDestroyREAL8Window(REAL8Window *window)
REAL8Sequence * XLALUnitaryWindowREAL8Sequence(REAL8Sequence *sequence, const REAL8Window *window)
REAL8Window * XLALCreateTukeyREAL8Window(UINT4 length, REAL8 beta)
#define XLAL_ERROR_NULL(...)
#define xlalErrno
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int XLALClearErrno(void)
int XLALPrintProgressBar(double)
static _LAL_INLINE_ int XLALIsREAL8FailNaN(REAL8 val)
XLAL_EBADLEN
XLAL_ENOMEM
XLAL_EDATA
XLAL_EFAULT
XLAL_EFUNC
XLAL_EINVAL
LIGOTimeGPS * XLALGPSAdd(LIGOTimeGPS *epoch, REAL8 dt)
LIGOTimeGPS * XLALGPSSetREAL8(LIGOTimeGPS *epoch, REAL8 t)
CHAR name[LALNameLength]
COMPLEX16Sequence * data
COMPLEX16 * data
double unwhitened_rms
root mean square of the unwhitened time series corresponding to this filter
Definition: EPSearch.c:81
COMPLEX16FrequencySeries * fseries
Definition: EPSearch.c:80
REAL8Sequence * unwhitened_cross
the mean square cross terms for wide channels (indices same as for twice_channel_overlap)
Definition: EPSearch.c:89
REAL8Sequence * twice_channel_overlap
twice the inner product of filters for neighbouring channels; twice_channel_overlap[0] is twice the i...
Definition: EPSearch.c:88
ExcessPowerFilter * basis_filters
Definition: EPSearch.c:87
INT4 gpsNanoSeconds
double flow
low frequency boundary of TF plane
Definition: EPSearch.c:380
double deltaT
time resolution of the plane
Definition: EPSearch.c:377
REAL8Sequence * unwhitened_channel_buffer
UNDOCUMENTED.
Definition: EPSearch.c:383
int window_shift
by how many samples a window's start should be shifted from the start of the window preceding it
Definition: EPSearch.c:386
LIGOTimeGPS epoch
epoch of data from which this was computed
Definition: EPSearch.c:376
REAL8Window * window
time-domain window applied to input time series for tapering edges to 0
Definition: EPSearch.c:385
char name[LALNameLength]
name of data from which this was computed
Definition: EPSearch.c:375
REAL8Sequence * two_point_spectral_correlation
two-point spectral correlation of the whitened frequency series, computed from the time-domain window...
Definition: EPSearch.c:387
REAL8TimeFrequencyPlaneTiles tiles
time-frequency plane's tiling information
Definition: EPSearch.c:384
double deltaF
TF plane's frequency resolution (channel spacing)
Definition: EPSearch.c:379
REAL8Sequence * channel_buffer
re-usable holding area for the data for a single channel
Definition: EPSearch.c:382
gsl_matrix * channel_data
channel data.
Definition: EPSearch.c:381
double fseries_deltaF
input frequency series' resolution
Definition: EPSearch.c:378
A time-frequency plane.
Definition: EPSearch.c:363
REAL8Sequence * data
LIGOTimeGPS epoch
CHAR name[LALNameLength]
REAL8 * data
REAL8Sequence * data
struct tagSnglBurst * next