From 9745ee1e07e4f5a743e30f915a111a9f2c5be422 Mon Sep 17 00:00:00 2001 From: Aaron Viets <aaron.viets@ligo.org> Date: Sat, 31 Mar 2018 18:35:43 -0700 Subject: [PATCH] lal_transferfunction: Made fir filter length independent of fft length. Added ability to resample and low-pass filter transfer functions to produce fir filters. Reduces noise in transfer functions wieh multiple witness channels are equally well correlated with the signal to be cleaned. --- gstlal-calibration/gst/lal/gstlal_resample.c | 6 +- .../gst/lal/gstlal_transferfunction.c | 138 ++++++++++-------- .../python/calibration_parts.py | 4 +- .../tests/lal_transferfunction_test.py | 4 +- 4 files changed, 89 insertions(+), 63 deletions(-) diff --git a/gstlal-calibration/gst/lal/gstlal_resample.c b/gstlal-calibration/gst/lal/gstlal_resample.c index 3bf1bce6b9..2478328feb 100644 --- a/gstlal-calibration/gst/lal/gstlal_resample.c +++ b/gstlal-calibration/gst/lal/gstlal_resample.c @@ -1511,8 +1511,10 @@ static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuf normalization += element->sinc_table[j]; for(j = i; j <= element->sinc_length / 2; j += cadence) element->sinc_table[j] /= normalization; - for(j = cadence - i; j <= element->sinc_length / 2; j += cadence) - element->sinc_table[j] /= normalization; + if(i) { + for(j = cadence - i; j <= element->sinc_length / 2; j += cadence) + element->sinc_table[j] /= normalization; + } } /* If cadence is even, we need to account for one more normalization without "over-normalizing." */ if(!((cadence) % 2)) { diff --git a/gstlal-calibration/gst/lal/gstlal_transferfunction.c b/gstlal-calibration/gst/lal/gstlal_transferfunction.c index a6807cb429..7dedf2dd5f 100644 --- a/gstlal-calibration/gst/lal/gstlal_transferfunction.c +++ b/gstlal-calibration/gst/lal/gstlal_transferfunction.c @@ -83,7 +83,7 @@ #include <gstlal_transferfunction.h> -#define SINC_LENGTH 17 +#define SINC_LENGTH 25 /* @@ -178,7 +178,7 @@ DEFINE_MAXIMUM(32); DEFINE_MAXIMUM(64); -static void write_transfer_functions(complex double *tfs, char *element_name, gint64 rows, int columns, gboolean write_to_screen, char *filename) { +static void write_transfer_functions(complex double *tfs, char *element_name, gint64 rows, int columns, gboolean write_to_screen, char *filename, gboolean free_name) { gint64 i; int j, j_stop; if(write_to_screen) { @@ -213,11 +213,12 @@ static void write_transfer_functions(complex double *tfs, char *element_name, gi g_fprintf(fp, "\n\n"); fclose(fp); } - g_free(element_name); + if(free_name) + g_free(element_name); } -static void write_fir_filters(double *filters, char *element_name, gint64 rows, int columns, gboolean write_to_screen, char *filename) { +static void write_fir_filters(double *filters, char *element_name, gint64 rows, int columns, gboolean write_to_screen, char *filename, gboolean free_name) { gint64 i; int j, j_stop; if(write_to_screen) { @@ -252,7 +253,8 @@ static void write_fir_filters(double *filters, char *element_name, gint64 rows, g_fprintf(fp, "\n\n"); fclose(fp); } - g_free(element_name); + if(free_name) + g_free(element_name); } @@ -287,11 +289,11 @@ static gboolean update_transfer_functions_ ## DTYPE(complex DTYPE *autocorrelati /* Now copy the result into transfer_functions */ \ for(j = 0; j < num_tfs; j++) { \ gslz = gsl_vector_complex_get(transfer_functions_solved_at_f, j); \ - if(isnormal(GSL_REAL(gslz))) \ + if(isnormal(GSL_REAL(gslz)) || GSL_REAL(gslz) == 0.0) \ transfer_functions[j * fd_fft_length + i] = GSL_REAL(gslz) + I * GSL_IMAG(gslz); \ else { \ success = FALSE; \ - transfer_functions[j * fd_fft_length + i] = 0; \ + transfer_functions[j * fd_fft_length + i] = 0.0; \ } \ } \ } \ @@ -308,8 +310,8 @@ DEFINE_UPDATE_TRANSFER_FUNCTIONS(double); static gboolean update_fir_filters_ ## DTYPE(complex double *transfer_functions, int num_tfs, gint64 fft_length, gint64 fir_length, int sample_rate, DTYPE *sinc_table, gint64 sinc_length, gint64 sinc_taps_per_df, complex DTYPE *fir_filter, fftw ## F_OR_BLANK ## _plan fir_plan, DTYPE *fd_window, double *tukey, double *fir_filters) { \ \ gboolean success = TRUE; \ - gint16 i, input0, sinc0, sinc_taps_per_input, sinc_taps_per_output; \ - gint64 j, k, k_stop, fd_fft_length, fd_fir_length; \ + gint16 i; \ + gint64 j, k, k_stop, fd_fft_length, fd_fir_length, input0, sinc0, sinc_taps_per_input, sinc_taps_per_output; \ DTYPE df, delay; \ complex DTYPE exp_arg, smooth_tf; \ \ @@ -320,8 +322,8 @@ static gboolean update_fir_filters_ ## DTYPE(complex double *transfer_functions, * with the right length and frequency resolution. First, calculate the number of taps of the * sinc filter that corresponds to one increment in the input and output. */ \ - sinc_taps_per_input = fd_fir_length > fd_fft_length ? sinc_taps_per_df * fd_fir_length / fd_fft_length : sinc_taps_per_df; \ - sinc_taps_per_output = fd_fir_length > fd_fft_length ? sinc_taps_per_df : sinc_taps_per_df * fd_fir_length / fd_fft_length; \ + sinc_taps_per_input = fd_fir_length > fd_fft_length ? sinc_taps_per_df * (fd_fir_length - 1) / (fd_fft_length - 1) : sinc_taps_per_df; \ + sinc_taps_per_output = fd_fir_length > fd_fft_length ? sinc_taps_per_df : sinc_taps_per_df * (fd_fft_length - 1) / (fd_fir_length - 1); \ \ df = sample_rate / 2.0 / (fd_fir_length - 1); /* frequency spacing is Nyquist frequency / number of frequency increments */ \ delay = (fd_fir_length - 1.0) / sample_rate; /* number of samples of delay is length of transfer functions - 1 */ \ @@ -333,45 +335,49 @@ static gboolean update_fir_filters_ ## DTYPE(complex double *transfer_functions, * First, apply the sinc filter to higher frequencies. We could hit the edge * of the sinc table or the Nyquist frequency of the transfer function */ \ - sinc0 = (fd_fir_length - j - 1) * sinc_taps_per_output % sinc_taps_per_input; \ - input0 = i * fd_fft_length + (j * fd_fft_length + fd_fir_length - 1) / fd_fir_length; \ - k_stop = minimum64((sinc_length / 2 - sinc0) / sinc_taps_per_input, (i + 1) * fd_fft_length - input0); \ + sinc0 = (sinc_taps_per_input - j * sinc_taps_per_output % sinc_taps_per_input) % sinc_taps_per_input; \ + input0 = i * fd_fft_length + (j * (fd_fft_length - 1) + fd_fir_length - 2) / (fd_fir_length - 1); \ + k_stop = minimum64((sinc_taps_per_input + sinc_length / 2 - sinc0) / sinc_taps_per_input, (i + 1) * fd_fft_length - input0); \ + gint64 stupid = k_stop; \ for(k = 0; k < k_stop; k++) \ - smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (transfer_functions[input0 + k]); \ + smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (fd_window[(input0 + k) % fd_fft_length] * transfer_functions[input0 + k]); \ /* * If we hit the Nyquist frequency of the transfer function but not the edge of * the sinc table, turn around and keep going until we hit the edge of the sinc table. */ \ sinc0 += k_stop * sinc_taps_per_input; \ - input0 = (i + 1) * fd_fft_length - 1; \ - k_stop = (sinc_length / 2 - sinc0) / sinc_taps_per_input; \ + input0 = (i + 1) * fd_fft_length - 2; \ + k_stop = (sinc_taps_per_input + sinc_length / 2 - sinc0) / sinc_taps_per_input; \ + stupid += k_stop; \ for(k = 0; k < k_stop; k++) \ - smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (transfer_functions[input0 - k]); \ + smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (fd_window[(input0 - k) % fd_fft_length] * transfer_functions[input0 - k]); \ /* * Now, go back and apply the sinc filter to the lower frequencies. We could hit the edge * of the sinc table or the DC component of the transfer function. */ \ - sinc0 = 1 + (j * sinc_taps_per_output - 1) % sinc_taps_per_input; \ - input0 = i * fd_fft_length + (j * fd_fft_length - 1) / fd_fir_length; \ - k_stop = minimum64((sinc_length / 2 - sinc0) / sinc_taps_per_input, input0 - i * fd_fft_length); \ + sinc0 = 1 + (sinc_taps_per_input + j * sinc_taps_per_output - 1) % sinc_taps_per_input; \ + input0 = i * fd_fft_length + (j * (fd_fft_length - 1) - 1) / (fd_fir_length - 1); \ + k_stop = minimum64((sinc_taps_per_input + sinc_length / 2 - sinc0) / sinc_taps_per_input, input0 - i * fd_fft_length); \ + stupid = k_stop; \ for(k = 0; k < k_stop; k++) \ - smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (transfer_functions[input0 - k]); \ + smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (fd_window[(input0 - k) % fd_fft_length] * transfer_functions[input0 - k]); \ /* * If we hit the DC component of the transfer function but not the edge of the * sinc table, turn around and keep going until we hit the edge of the sinc table. */ \ sinc0 += k_stop * sinc_taps_per_input; \ input0 = i * fd_fft_length + 1; \ - k_stop = (sinc_length / 2 - sinc0) / sinc_taps_per_input; \ + k_stop = (sinc_taps_per_input + sinc_length / 2 - sinc0) / sinc_taps_per_input; \ + stupid += k_stop; \ for(k = 0; k < k_stop; k++) \ - smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (transfer_functions[input0 + k]); \ + smooth_tf += sinc_table[sinc0 + k * sinc_taps_per_input] * (complex DTYPE) (fd_window[(input0 + k) % fd_fft_length] * transfer_functions[input0 + k]); \ \ /* * Now use smoothed samples from transfer_functions in fir_filter for fftw(f) to take an inverse fft. * The frequency domain window is applied here to roll off low and high freqneucies. * A delay is also added in order to center the filter in time. */ \ - fir_filter[j] = fd_window[j] * cexp ## F_OR_BLANK(exp_arg * j) * smooth_tf; \ + fir_filter[j] = cexp ## F_OR_BLANK(exp_arg * j) * smooth_tf; \ } \ \ /* Take the inverse Fourier transform */ \ @@ -381,8 +387,7 @@ static gboolean update_fir_filters_ ## DTYPE(complex double *transfer_functions, DTYPE *real_filter = (DTYPE *) fir_filter; \ for(j = 0; j < fir_length; j++) { \ fir_filters[i * fir_length + j] = tukey[j] * real_filter[j]; \ - if(isnan(fir_filters[i * fir_length + j]) || isinf(fir_filters[i * fir_length + j])) \ - success = FALSE; \ + success &= isnormal(fir_filters[i * fir_length + j]) || fir_filters[i * fir_length + j] == 0.0; \ } \ } \ \ @@ -462,6 +467,9 @@ static gboolean find_transfer_functions_ ## DTYPE(GSTLALTransferFunction *elemen } \ } \ } \ + /* Check a few values in the autocorrelation matrix to see if it was computed successfully */ \ + for(j = 0; j < 2 * num_tfs * element->channels; j++) \ + success &= isnormal(creal ## F_OR_BLANK(element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix[j])) || creal ## F_OR_BLANK(element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix[j]) == 0.0; \ } \ \ element->workspace.w ## S_OR_D ## pf.num_ffts_in_avg += num_ffts; \ @@ -520,6 +528,9 @@ static gboolean find_transfer_functions_ ## DTYPE(GSTLALTransferFunction *elemen } \ } \ } \ + /* Check a few values in the autocorrelation matrix to see if it was computed successfully */ \ + for(j = 0; j < 2 * num_tfs * element->channels; j++) \ + success &= isnormal(creal ## F_OR_BLANK(element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix[j])) || creal ## F_OR_BLANK(element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix[j]) == 0.0; \ } \ \ element->workspace.w ## S_OR_D ## pf.num_ffts_in_avg += num_ffts; \ @@ -550,7 +561,7 @@ static gboolean find_transfer_functions_ ## DTYPE(GSTLALTransferFunction *elemen element->workspace.w ## S_OR_D ## pf.num_leftover = maximum64(0, element->sample_count + 1 - sample_count_next_fft); \ \ /* Finally, update transfer functions if ready */ \ - if(element->workspace.w ## S_OR_D ## pf.num_ffts_in_avg == element->num_ffts) { \ + if(success && element->workspace.w ## S_OR_D ## pf.num_ffts_in_avg == element->num_ffts) { \ success &= update_transfer_functions_ ## DTYPE(element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix, num_tfs, fd_fft_length, element->num_ffts, element->workspace.w ## S_OR_D ## pf.transfer_functions_at_f, element->workspace.w ## S_OR_D ## pf.transfer_functions_solved_at_f, element->workspace.w ## S_OR_D ## pf.autocorrelation_matrix_at_f, element->workspace.w ## S_OR_D ## pf.permutation, element->transfer_functions); \ GST_INFO_OBJECT(element, "Just computed new transfer functions"); \ if(success) { \ @@ -558,7 +569,7 @@ static gboolean find_transfer_functions_ ## DTYPE(GSTLALTransferFunction *elemen g_object_notify_by_pspec(G_OBJECT(element), properties[ARG_TRANSFER_FUNCTIONS]); \ /* Write transfer functions to the screen or a file if we want */ \ if(element->write_to_screen || element->filename) \ - write_transfer_functions(element->transfer_functions, gst_element_get_name(element), fd_fft_length, num_tfs, element->write_to_screen, element->filename); \ + write_transfer_functions(element->transfer_functions, gst_element_get_name(element), fd_fft_length, num_tfs, element->write_to_screen, element->filename, TRUE); \ } \ element->sample_count -= element->update_samples + element->num_ffts * stride + element->fft_overlap; \ element->workspace.w ## S_OR_D ## pf.num_ffts_in_avg = 0; \ @@ -572,7 +583,7 @@ static gboolean find_transfer_functions_ ## DTYPE(GSTLALTransferFunction *elemen g_object_notify_by_pspec(G_OBJECT(element), properties[ARG_FIR_FILTERS]); \ /* Write FIR filters to the screen or a file if we want */ \ if(element->write_to_screen || element->filename) \ - write_fir_filters(element->fir_filters, gst_element_get_name(element), element->fir_length, num_tfs, element->write_to_screen, element->filename); \ + write_fir_filters(element->fir_filters, gst_element_get_name(element), element->fir_length, num_tfs, element->write_to_screen, element->filename, TRUE); \ } \ } \ } \ @@ -836,8 +847,10 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { normalization += element->workspace.wspf.sinc_table[j]; for(j = i; j <= element->workspace.wspf.sinc_length / 2; j += taps_per_input) element->workspace.wspf.sinc_table[j] /= normalization; - for(j = taps_per_input - i; j <= element->workspace.wspf.sinc_length / 2; j += taps_per_input) - element->workspace.wspf.sinc_table[j] /= normalization; + if(i) { + for(j = taps_per_input - i; j <= element->workspace.wspf.sinc_length / 2; j += taps_per_input) + element->workspace.wspf.sinc_table[j] /= normalization; + } } /* If taps_per_input is even, we need to account for one more normalization without "over-normalizing." */ if(!((taps_per_input) % 2)) { @@ -853,14 +866,14 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { * Make a frequency-domain window to roll off low and high frequencies */ - element->workspace.wspf.fir_window = g_malloc(fd_fir_length * sizeof(*element->workspace.wspf.fir_window)); + element->workspace.wspf.fir_window = g_malloc(fd_fft_length * sizeof(*element->workspace.wspf.fir_window)); /* Initialize to ones */ - for(i = 0; i < fd_fir_length; i++) + for(i = 0; i < fd_fft_length; i++) element->workspace.wspf.fir_window[i] = 1.0; int f_nyquist = element->rate / 2; - float df_per_hz = (fd_fir_length - 1.0) / f_nyquist; + float df_per_hz = (fd_fft_length - 1.0) / f_nyquist; /* high-pass filter */ /* Remove low frequencies */ @@ -878,13 +891,13 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { if(element->low_pass > 0) { /* Apply half of a Hann window */ i_start = (gint64) (element->low_pass * df_per_hz + 0.5); - i_stop = minimum64(fd_fir_length, 1.4 * i_start); + i_stop = minimum64(fd_fft_length, 1.4 * i_start); for(i = i_start; i < i_stop; i++) element->workspace.wspf.fir_window[i] *= (float) pow(cos((M_PI / 2.0) * (i - i_start) / (i_stop - i_start)), 2.0); /* Remove high frequencies */ i_start = i_stop; - i_stop = fd_fir_length; + i_stop = fd_fft_length; for(i = i_start; i < i_stop; i++) element->workspace.wspf.fir_window[i] = 0.0; } @@ -899,17 +912,17 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { /* first curve of window */ for(i = 0; i < edge_to_corner; i++) - element->workspace.wspf.tukey[i] = element->make_fir_filters * pow(sin((M_PI / 2.0) * i / edge_to_corner), 2.0) / element->fir_length; + element->workspace.wspf.tukey[i] = (float) (element->make_fir_filters * pow(sin((M_PI / 2.0) * i / edge_to_corner), 2.0) / element->fir_length); /* flat top of window */ i_stop = element->fir_length - edge_to_corner; for(i = edge_to_corner; i < i_stop; i++) - element->workspace.wspf.tukey[i] = (double) element->make_fir_filters / element->fir_length; + element->workspace.wspf.tukey[i] = (float) (element->make_fir_filters / element->fir_length); /* last curve of window */ i_start = i_stop; for(i = i_start; i < element->fir_length; i++) - element->workspace.wspf.tukey[i] = element->make_fir_filters * pow(cos((M_PI / 2.0) * (i + 1 - i_start) / (element->fir_length - i_start)), 2.0) / element->fir_length; + element->workspace.wspf.tukey[i] = (float) (element->make_fir_filters * pow(cos((M_PI / 2.0) * (i + 1 - i_start) / (element->fir_length - i_start)), 2.0) / element->fir_length); } /* intermediate data storage */ @@ -1006,8 +1019,10 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { normalization += element->workspace.wdpf.sinc_table[j]; for(j = i; j <= element->workspace.wdpf.sinc_length / 2; j += taps_per_input) element->workspace.wdpf.sinc_table[j] /= normalization; - for(j = taps_per_input - i; j <= element->workspace.wdpf.sinc_length / 2; j += taps_per_input) - element->workspace.wdpf.sinc_table[j] /= normalization; + if(i) { + for(j = taps_per_input - i; j <= element->workspace.wdpf.sinc_length / 2; j += taps_per_input) + element->workspace.wdpf.sinc_table[j] /= normalization; + } } /* If taps_per_input is even, we need to account for one more normalization without "over-normalizing." */ if(!((taps_per_input) % 2)) { @@ -1023,14 +1038,14 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { * Make a frequency-donain window to roll off low and high frequencies */ - element->workspace.wdpf.fir_window = g_malloc(fd_fir_length * sizeof(*element->workspace.wdpf.fir_window)); + element->workspace.wdpf.fir_window = g_malloc(fd_fft_length * sizeof(*element->workspace.wdpf.fir_window)); /* Initialize to ones */ - for(i = 0; i < fd_fir_length; i++) + for(i = 0; i < fd_fft_length; i++) element->workspace.wdpf.fir_window[i] = 1.0; int f_nyquist = element->rate / 2; - double df_per_hz = (fd_fir_length - 1.0) / f_nyquist; + double df_per_hz = (fd_fft_length - 1.0) / f_nyquist; /* high-pass filter */ /* Remove low frequencies */ @@ -1048,13 +1063,13 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { if(element->low_pass > 0) { /* Apply half of a Hann window */ i_start = (gint64) (element->low_pass * df_per_hz + 0.5); - i_stop = minimum64(element->fir_length, 1.4 * i_start); + i_stop = minimum64(fd_fft_length, 1.4 * i_start); for(i = i_start; i < i_stop; i++) element->workspace.wdpf.fir_window[i] *= pow(cos((M_PI / 2.0) * (i - i_start) / (i_stop - i_start)), 2.0); /* Remove high frequencies */ i_start = i_stop; - i_stop = element->fir_length; + i_stop = fd_fft_length; for(i = i_start; i < i_stop; i++) element->workspace.wdpf.fir_window[i] = 0.0; } @@ -1074,7 +1089,7 @@ static gboolean set_caps(GstBaseSink *sink, GstCaps *caps) { /* flat top of window */ i_stop = element->fir_length - edge_to_corner; for(i = edge_to_corner; i < i_stop; i++) - element->workspace.wdpf.tukey[i] = (double) element->make_fir_filters / element->fir_length; + element->workspace.wdpf.tukey[i] = element->make_fir_filters / element->fir_length; /* last curve of window */ i_start = i_stop; @@ -1190,8 +1205,17 @@ static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer) { success = find_transfer_functions_double(element, (double *) mapinfo.data, mapinfo.size); } - if(!success) + if(!success) { + /* Try again */ element->sample_count = element->update_samples; + if(element->data_type == GSTLAL_TRANSFERFUNCTION_F32) { + element->workspace.wspf.num_ffts_in_avg = 0; + element->workspace.wspf.num_leftover = 0; + } else { + element->workspace.wdpf.num_ffts_in_avg = 0; + element->workspace.wdpf.num_leftover = 0; + } + } } return result; @@ -1355,7 +1379,7 @@ static void set_property(GObject *object, enum property id, const GValue *value, break; case ARG_MAKE_FIR_FILTERS: - element->make_fir_filters = g_value_get_int(value); + element->make_fir_filters = g_value_get_double(value); break; case ARG_FIR_LENGTH: @@ -1381,7 +1405,7 @@ static void set_property(GObject *object, enum property id, const GValue *value, case ARG_LOW_PASS: element->low_pass = g_value_get_int(value); if((!element->make_fir_filters) && (element->high_pass != 0 || element->low_pass != 0)) - GST_WARNING_OBJECT(element, "A FIR filter cutoff frequency is set, but no FIR filter is being produced. Set the property make_fir_filters = True to make FIR filters."); + GST_WARNING_OBJECT(element, "A FIR filter cutoff frequency is set, but no FIR filter is being produced. Set the property make_fir_filters to a nonzero value to make FIR filters."); if(element->high_pass != 0 && element->low_pass != 0 && element->high_pass > element->low_pass) GST_WARNING_OBJECT(element, "The high-pass cutoff frequency of the FIR filters is above the low-pass cutoff frequency. Reset high_pass and/or low_pass to change this."); break; @@ -1445,7 +1469,7 @@ static void get_property(GObject *object, enum property id, GValue *value, GPara break; case ARG_MAKE_FIR_FILTERS: - g_value_set_int(value, element->make_fir_filters); + g_value_set_double(value, element->make_fir_filters); break; case ARG_FIR_LENGTH: @@ -1628,13 +1652,13 @@ static void gstlal_transferfunction_class_init(GSTLALTransferFunctionClass *klas NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT ); - properties[ARG_MAKE_FIR_FILTERS] = g_param_spec_int( + properties[ARG_MAKE_FIR_FILTERS] = g_param_spec_double( "make-fir-filters", "Make FIR Filters", - "If set to 1, FIR filters will be produced each time the transfer functions\n\t\t\t" - "are computed. If set to -1, a minus sign is added to the filters. If unset\n\t\t\t" - "(or set to 0), no FIR filters are produced.", - -1, 1, 0, + "If set to to a non-zero value, FIR filters will be produced each time the\n\t\t\t" + "transfer functions are computed with this gain factor relative to the\n\t\t\t" + "transfer functions. If unset (or set to 0), no FIR filters are produced.\n\t\t\t", + -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT ); properties[ARG_FIR_LENGTH] = g_param_spec_int64( diff --git a/gstlal-calibration/python/calibration_parts.py b/gstlal-calibration/python/calibration_parts.py index 78e5376841..4f6a960415 100644 --- a/gstlal-calibration/python/calibration_parts.py +++ b/gstlal-calibration/python/calibration_parts.py @@ -653,7 +653,7 @@ def update_filter(filter_maker, arg, filter_taker, maker_prop_name, taker_prop_n firfilter = filter_maker.get_property(maker_prop_name)[filter_number][::-1] filter_taker.set_property(taker_prop_name, firfilter) -def clean_data(pipeline, signal, signal_rate, witnesses, witness_rate, fft_length, fft_overlap, num_ffts, update_samples, obsready = None, filename = None): +def clean_data(pipeline, signal, signal_rate, witnesses, witness_rate, fft_length, fft_overlap, num_ffts, update_samples, fir_length, frequency_resolution, obsready = None, filename = None): # # Note: this function can cause pipelines to lock up. Adding queues does not seem to help. @@ -677,7 +677,7 @@ def clean_data(pipeline, signal, signal_rate, witnesses, witness_rate, fft_lengt transfer_functions = mkinterleave(pipeline, numpy.insert(witness_tees, 0, resampled_signal, axis = 0)) if obsready is not None: transfer_functions = mkgate(pipeline, transfer_functions, obsready, 1) - transfer_functions = pipeparts.mkgeneric(pipeline, transfer_functions, "lal_transferfunction", fft_length = fft_length, fft_overlap = fft_overlap, num_ffts = num_ffts, update_samples = update_samples, make_fir_filters = -1, update_after_gap = True, filename = filename) + transfer_functions = pipeparts.mkgeneric(pipeline, transfer_functions, "lal_transferfunction", fft_length = fft_length, fft_overlap = fft_overlap, num_ffts = num_ffts, update_samples = update_samples, make_fir_filters = -1, fir_length = fir_length, frequency_resolution = frequency_resolution, high_pass = 9, update_after_gap = True, filename = filename) signal_minus_noise = [signal_tee] for i in range(0, len(witnesses)): minus_noise = pipeparts.mkgeneric(pipeline, witness_tees[i], "lal_tdwhiten", kernel = default_fir_filter, latency = fft_length / 2, taper_length = 20 * fft_length) diff --git a/gstlal-calibration/tests/lal_transferfunction_test.py b/gstlal-calibration/tests/lal_transferfunction_test.py index 47357245b5..37b9c36fcc 100755 --- a/gstlal-calibration/tests/lal_transferfunction_test.py +++ b/gstlal-calibration/tests/lal_transferfunction_test.py @@ -108,7 +108,7 @@ def lal_transferfunction_02(pipeline, name): rate = 16384 # Hz buffer_length = 1.0 # seconds - test_duration = 100.0 # seconds + test_duration = 500.0 # seconds width = 64 # bits channels = 1 freq = 512 # Hz @@ -126,7 +126,7 @@ def lal_transferfunction_02(pipeline, name): witness1 = calibration_parts.mkadder(pipeline, calibration_parts.list_srcs(pipeline, calibration_parts.highpass(pipeline, hoft, rate, fcut = 400), calibration_parts.lowpass(pipeline, noise, rate, fcut = 400))) witness2 = calibration_parts.mkadder(pipeline, calibration_parts.list_srcs(pipeline, calibration_parts.lowpass(pipeline, hoft, rate, fcut = 600), calibration_parts.highpass(pipeline, noise, rate, fcut = 600))) - clean_data = calibration_parts.clean_data(pipeline, hoft, rate, calibration_parts.list_srcs(pipeline, witness1, witness2), rate, rate / 2, rate / 4, 128, rate * test_duration, filename = "highpass_lowpass_tfs.txt") + clean_data = calibration_parts.clean_data(pipeline, hoft, rate, calibration_parts.list_srcs(pipeline, witness1, witness2), rate, rate / 2, rate / 4, 128, rate * test_duration, int(0.75 * rate), 20.0 / rate, filename = "highpass_lowpass_tfs.txt") pipeparts.mknxydumpsink(pipeline, clean_data, "%s_out.txt" % name) return pipeline -- GitLab