diff --git a/mth5/timeseries/channel_ts.py b/mth5/timeseries/channel_ts.py index 1ee860f0..3bc16073 100644 --- a/mth5/timeseries/channel_ts.py +++ b/mth5/timeseries/channel_ts.py @@ -1078,7 +1078,10 @@ def get_response_correction_operation_and_units(self): return calibration_operation, calibrated_units - def remove_instrument_response(self, **kwargs): + def remove_instrument_response(self, + include_decimation=True, + include_delay=False, + **kwargs): """ Remove instrument response from the given channel response filter @@ -1093,6 +1096,13 @@ def remove_instrument_response(self, **kwargs): 7) undo time window 8) bandpass + :param include_decimation: Include decimation in response, + defaults to True + :type include_decimation: bool, optional + :param include_delay: include delay in complex response, + defaults to False + :type include_delay: bool, optional + **kwargs** :param plot: to plot the calibration process [ False | True ] @@ -1117,6 +1127,8 @@ def remove_instrument_response(self, **kwargs): :type bandpass: dictionary """ + def bool_flip(x): + return bool(int(x)-1) calibrated_ts = ChannelTS() calibrated_ts.__dict__.update(self.__dict__) @@ -1126,6 +1138,11 @@ def remove_instrument_response(self, **kwargs): "No filters to apply to calibrate time series data" ) return calibrated_ts + + # Make a list of the filters whose response will be removed. + # We make the list here so that we have access to the indices to flip + filters_to_remove, indices_to_flip = self.channel_response_filter.get_list_of_filters_to_remove(include_decimation=include_decimation, include_delay=include_delay) + remover = RemoveInstrumentResponse( self.ts, self.time_index, @@ -1135,7 +1152,8 @@ def remove_instrument_response(self, **kwargs): ) calibration_operation, calibrated_units = self.get_response_correction_operation_and_units() - calibrated_ts.ts = remover.remove_instrument_response(operation=calibration_operation) + calibrated_ts.ts = remover.remove_instrument_response(filters_to_remove=filters_to_remove, + operation=calibration_operation) # change applied booleans # TODO use invert on bool, instead of direct assignement to False diff --git a/mth5/timeseries/ts_filters.py b/mth5/timeseries/ts_filters.py index 08c6a1d3..a8a3d36d 100644 --- a/mth5/timeseries/ts_filters.py +++ b/mth5/timeseries/ts_filters.py @@ -187,6 +187,15 @@ def __init__( channel_response_filter, **kwargs, ): + """ + + :param ts: + :param time_array: + :param sample_interval: + :param channel_response_filter: + :param filters_to_remove: optional list of specific filters to remove. If not provided, filters will be + taken from channel_response_filter. + """ self.logger = logger self.ts = ts self.time_array = time_array @@ -205,7 +214,7 @@ def __init__( self.nrows = None self.subplot_dict = {} self.include_decimation = True - self.include_time_delay = False + self.include_delay = False for key, value in kwargs.items(): setattr(self, key, value) @@ -475,7 +484,8 @@ def _get_subplot_count(self): def remove_instrument_response(self, operation="divide", include_decimation=None, - include_time_delay=None): + include_delay=None, + filters_to_remove=[]): """ Remove instrument response following the recipe provided @@ -484,11 +494,20 @@ def remove_instrument_response(self, """ # if filters to include not specified, get from self - if include_decimation is None: - include_decimation = self.include_decimation - if include_time_delay is None: - include_time_delay = self.include_time_delay - + if not filters_to_remove: + self.logger.debug("No explicit list of filters was passed to remove") + self.logger.debug("Will determine filters to remove ... ") + if include_decimation is None: + include_decimation = self.include_decimation + if include_delay is None: + include_delay = self.include_delay + filters_to_remove, _ = self.channel_response_filter.get_list_of_filters_to_remove( + include_decimation=include_decimation, include_delay=include_delay) + if filters_to_remove is []: + raise ValueError("There are no filters in channel_response to remove") + + + ts = np.copy(self.ts) f = np.fft.rfftfreq(ts.size, d=self.sample_interval) step = 1 @@ -537,20 +556,15 @@ def remove_instrument_response(self, ts = self.apply_zero_pad(ts) self.logger.debug(f"Step {step}: Applying Zero Padding") step += 1 - # get the real frequencies of the FFT + # get the real frequencies of the FFT -- zero pad may have changed ts.size f = np.fft.rfftfreq(ts.size, d=self.sample_interval) - if self.channel_response_filter.filters_list is []: - raise ValueError("There are no filters in channel_response to remove") - if self.channel_response_filter.correction_operation == "multiply": - inverse_filters = [x.inverse() for x in self.channel_response_filter.filters_list] - self.channel_response_filter.filters_list = inverse_filters # compute the complex response given the frequency range of the FFT # the complex response assumes frequencies are in reverse order and flip them on input # so we need to flip the complex reponse so it aligns with the fft. cr = self.channel_response_filter.complex_response(f, - include_decimation=include_decimation, - include_time_delay=include_time_delay)[::-1] + filters_list=filters_to_remove, + )[::-1] # remove the DC term at frequency == 0 cr[-1] = abs(cr[-2]) + 0.0j