def remove_resp(self, trace, paz=None): # removing response... if paz: # ...using paz: if trace.stats.sampling_rate > 10.0: # decimating large trace, else fft crashes factor = int(np.ceil(trace.stats.sampling_rate / 10)) trace.decimate(factor=factor, no_filter=True) trace.simulate(paz_remove=paz, paz_simulate=obspy.signal.cornFreq2Paz(0.01), remove_sensitivity=True, simulate_sensitivity=True, nfft_pow2=True) else: # ...using StationXML: # first band-pass to downsample data before removing response # (else remove_response() method is slow or even hangs) trace.filter(type="bandpass", freqmin=self.freqmin, freqmax=self.freqmax, corners=self.corners, zerophase=self.zerophase) psutils.resample(trace, dt_resample=self.period_resample) trace.remove_response(output="VEL", zero_mean=True) return trace
def time_norm(self, trace, trcopy): if self.onebit_norm: # one-bit normalization trace.data = np.sign(trace.data) else: # normalization of the signal by the running mean # in the earthquake frequency band trcopy.filter(type="bandpass", freqmin=self.freqmin_earthquake, freqmax=self.freqmax_earthquake, corners=self.corners, zerophase=self.zerophase) # decimating trace psutils.resample(trcopy, self.period_resample) # Time-normalization weights from smoothed abs(data) # Note that trace's data can be a masked array halfwindow = int( round(self.window_time * trcopy.stats.sampling_rate / 2)) mask = ~trcopy.data.mask if np.ma.isMA(trcopy.data) else None tnorm_w = psutils.moving_avg(np.abs(trcopy.data), halfwindow=halfwindow, mask=mask) if np.ma.isMA(trcopy.data): # turning time-normalization weights into a masked array s = "[warning: {}.{} trace's data is a masked array]" print s.format(trace.stats.network, trace.stats.station), tnorm_w = np.ma.masked_array(tnorm_w, trcopy.data.mask) if np.any((tnorm_w == 0.0) | np.isnan(tnorm_w)): # illegal normalizing value -> skipping trace raise pserrors.CannotPreprocess("Zero or NaN normalization weight") # time-normalization trace.data /= tnorm_w return trace
def time_norm(self, trace, trcopy): if self.onebit_norm: # one-bit normalization trace.data = np.sign(trace.data) else: # normalization of the signal by the running mean # in the earthquake frequency band trcopy.filter(type="bandpass", freqmin=self.freqmin_earthquake, freqmax=self.freqmax_earthquake, corners=self.corners, zerophase=self.zerophase) # decimating trace psutils.resample(trcopy, self.period_resample) # Time-normalization weights from smoothed abs(data) # Note that trace's data can be a masked array halfwindow = int(round(self.window_time*trcopy.stats.sampling_rate/2)) mask = ~trcopy.data.mask if np.ma.isMA(trcopy.data) else None tnorm_w = psutils.moving_avg(np.abs(trcopy.data), halfwindow=halfwindow, mask=mask) if np.ma.isMA(trcopy.data): # turning time-normalization weights into a masked array s = "[warning: {}.{} trace's data is a masked array]" print s.format(trace.stats.network, trace.stats.station), tnorm_w = np.ma.masked_array(tnorm_w, trcopy.data.mask) if np.any((tnorm_w == 0.0) | np.isnan(tnorm_w)): # illegal normalizing value -> skipping trace raise pserrors.CannotPreprocess("Zero or NaN normalization weight") # time-normalization trace.data /= tnorm_w return trace
def preprocess_trace(self, trace, paz=None, verbose=False): """ Preprocesses a trace (so that it is ready to be cross-correlated), by applying the following steps: - removal of instrument response, mean and trend - band-pass filtering between *freqmin*-*freqmax* - downsampling to *period_resample* secs - time-normalization (one-bit normalization or normalization by the running mean in the earthquake frequency band) - spectral whitening (if running mean normalization) Raises CannotPreprocess exception if: - trace only contains 0 (happens sometimes...) - a normalization weight is 0 or NaN - a Nan appeared in trace data Note that the processing steps are performed in-place. @type trace: L{Trace} @param paz: poles and zeros of instrumental response (set None if response is directly attached to trace) """ # ======================================= # Check if any data to work with to begin # ======================================= if np.all(trace.data == 0.0): # no data -> skipping trace raise pserrors.CannotPreprocess("Only zeros") # ========================== # Remove instrument response # ========================== if RESP_REMOVE: t1 = dt.datetime.now() trace = self.remove_resp(trace, paz=paz) delta = (dt.datetime.now() - t1).total_seconds() if verbose: print "\nRemoved response in {:.1f} seconds".format(delta) #Initialise the AutoTrigger class for the current trace if HIGHAMP_REMOVE: # this check finds high amplitude noise creates a list of where it is located in the signal TRIGGER = AutoTrigger(trace, freqmin=FREQMIN, freqmax=FREQMAX) UTC_events = TRIGGER.trigger_times(check=True) if UTC_events is not None: # set the application to remove these parts from the trace! trace_new = None for event in UTC_events: # event is a list of length 2, start and end times # use trace.trim(starttime=x, endtime=y) # trace 1 is from trace start until the event starttime trace1 = trace.trim(starttime=trace.stats.starttime, endtime=event[0]) trace2 = trace.trim(starttime=event[1], endtime=trace.stats.endtime) if trace_new is None: trace_new = trace1 + trace2 else: trace_new += (trace1 + trace2) # trace_new has removed all high amp. noise from trace original trace = trace_new print trace.data # ============================================== # Check trace data completeness is above MINFILL # ============================================== if COMPLETENESS: # Data fill for current TIME INTERVAL! # CHECK THAT THE get_fill_trace function works! fill = psutils.get_fill_trace(trace) if fill < MINFILL: # not enough data raise pserrors.CannotPreprocess("{:.0f}% fill"\ .format(fill*100)) # ======================== # Trim, demean and detrend # ======================== if TDD: t1 = dt.datetime.now() midt = trace.stats.starttime + (trace.stats.endtime - trace.stats.starttime) / 2.0 t0 = UTCDateTime(midt.date)# date of trace, at time 00h00m00s trace.trim(starttime=t0, endtime=t0 + dt.timedelta(days=1)) trace.detrend(type='constant') trace.detrend(type='linear') delta = (dt.datetime.now() - t1).total_seconds() if verbose: print "\nProcessed trim in {:.1f} seconds".format(delta) # ========= # Band-pass # ========= if BANDPASS: t0 = dt.datetime.now() trace.filter(type="bandpass", freqmin=self.freqmin, freqmax=self.freqmax, corners=self.corners, zerophase=self.zerophase) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "\nProcessed filters in {:.1f} seconds".format(delta) # ============ # Downsampling # ============ if DOWNSAMPLE: if abs(1.0 / trace.stats.sampling_rate - self.period_resample)>EPS: psutils.resample(trace, dt_resample=self.period_resample) # ================== # Time normalization # ================== if TIME_NOMALISATION: t0 = dt.datetime.now() # keeping a copy of the trace for weights of time-normalization trcopy = trace.copy() trace = self.time_norm(trace, trcopy) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "\nProcessed time-normalisation in {:.1f} seconds"\ .format(delta) # ================== # Spectral whitening # ================== if SPEC_WHITENING: t0 = dt.datetime.now() trace = self.spectral_whitening(trace) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "\nProcessed spectral whitening in {:.1f} seconds".\ format(delta) # ============================================== # Verifying that we don't have nan in trace data # ============================================== if np.any(np.isnan(trace.data)): raise pserrors.CannotPreprocess("Got NaN in trace data")
def preprocess_trace(self, trace, paz=None, verbose=False): """ Preprocesses a trace (so that it is ready to be cross-correlated), by applying the following steps: - removal of instrument response, mean and trend - band-pass filtering between *freqmin*-*freqmax* - downsampling to *period_resample* secs - time-normalization (one-bit normalization or normalization by the running mean in the earthquake frequency band) - spectral whitening (if running mean normalization) Raises CannotPreprocess exception if: - trace only contains 0 (happens sometimes...) - a normalization weight is 0 or NaN - a Nan appeared in trace data Note that the processing steps are performed in-place. @type trace: L{Trace} @param paz: poles and zeros of instrumental response (set None if response is directly attached to trace) """ # ======================================= # Check if any data to work with to begin # ======================================= #print type(trace) #print "trace: ", trace if np.all(trace.data == 0.0): # no data -> skipping trace raise pserrors.CannotPreprocess("Only zeros") # ========================== # Remove instrument response # ========================== if RESP_REMOVE: t1 = dt.datetime.now() trace = self.remove_resp(trace, paz=paz) delta = (dt.datetime.now() - t1).total_seconds() if verbose: print "\nRemoved response in {:.1f} seconds".format(delta) #Initialise the AutoTrigger class for the current trace if HIGHAMP_REMOVE: # this check finds high amplitude noise creates a list of where it is located in the signal TRIGGER = AutoTrigger(trace, freqmin=FREQMIN, freqmax=FREQMAX) UTC_events = TRIGGER.trigger_times(check=True) if UTC_events is not None: # set the application to remove these parts from the trace! trace_new = None for event in UTC_events: # event is a list of length 2, start and end times # use trace.trim(starttime=x, endtime=y) # trace 1 is from trace start until the event starttime trace1 = trace.trim(starttime=trace.stats.starttime, endtime=event[0]) trace2 = trace.trim(starttime=event[1], endtime=trace.stats.endtime) if trace_new is None: trace_new = trace1 + trace2 else: trace_new += (trace1 + trace2) # trace_new has removed all high amp. noise from trace original trace = trace_new print trace.data # ============================================== # Check trace data completeness is above MINFILL # ============================================== if COMPLETENESS: # Data fill for current TIME INTERVAL! # CHECK THAT THE get_fill_trace function works! fill = psutils.get_fill_trace(trace) if fill < MINFILL: # not enough data raise pserrors.CannotPreprocess("{:.0f}% fill"\ .format(fill*100)) # ======================== # Trim, demean and detrend # ======================== if TDD: t1 = dt.datetime.now() midt = trace.stats.starttime + (trace.stats.endtime - trace.stats.starttime) / 2.0 t0 = UTCDateTime(midt.date) # date of trace, at time 00h00m00s trace.trim(starttime=t0, endtime=t0 + dt.timedelta(days=1)) trace.detrend(type='constant') trace.detrend(type='linear') delta = (dt.datetime.now() - t1).total_seconds() if verbose: print "Processed trim in {:.1f} seconds".format(delta) #plt.figure() #plt.title("TDD") #plt.plot(trace.data) #plt.show() #plt.clf() # ========= # Band-pass # ========= if BANDPASS: t0 = dt.datetime.now() trace.filter(type="bandpass", freqmin=self.freqmin, freqmax=self.freqmax, corners=self.corners, zerophase=self.zerophase) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "Processed filters in {:.1f} seconds".format(delta) #plt.figure() #plt.title("Bandpass") #plt.plot(trace.data) #plt.show() #plt.clf() # ============ # Downsampling # ============ if DOWNSAMPLE: if abs(1.0 / trace.stats.sampling_rate - self.period_resample) > EPS: psutils.resample(trace, dt_resample=self.period_resample) #plt.figure() #plt.title("DOWNSAMPLE") #plt.plot(trace.data) #plt.show() #plt.clf() # ================== # Time normalization # ================== if TIME_NOMALISATION: t0 = dt.datetime.now() # keeping a copy of the trace for weights of time-normalization trcopy = trace.copy() trace = self.time_norm(trace, trcopy) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "Processed time-normalisation in {:.1f} seconds"\ .format(delta) #plt.figure() #plt.title("NORMALISATION") #plt.plot(trace.data) #plt.show() #plt.clf() # ================== # Spectral whitening # ================== if SPEC_WHITENING: t0 = dt.datetime.now() trace = self.spectral_whitening(trace) delta = (dt.datetime.now() - t0).total_seconds() if verbose: print "Processed spectral whitening in {:.1f} seconds".\ format(delta) #plt.figure() #plt.title("SPECTRAL WHITENING") #plt.plot(trace.data) #plt.show() #plt.clf() # ============================================== # Verifying that we don't have nan in trace data # ============================================== if np.any(np.isnan(trace.data)): raise pserrors.CannotPreprocess("Got NaN in trace data")