def filter_trace(tr, pre_filt): """ Perform a frequency domain taper mimicing the behavior during the response removal, without a actual response removal. :param tr: input trace :param pre_filt: frequency array(Hz) in ascending order, to define the four corners of filter, for example, [0.01, 0.1, 0.2, 0.5]. :type pre_filt: Numpy.array or list :return: filtered trace """ if type(tr) != obspy.Trace: raise ValueError("First Argument should be trace: %s" % type(tr)) if not check_array_order(pre_filt): raise ValueError("Frequency band should be in ascending order: %s" % pre_filt) data = tr.data.astype(np.float64) # smart calculation of nfft dodging large primes nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:len(data)] # assign processed data and store processing information tr.data = data
def filter_trace(tr, pre_filt): """ Perform a frequency domain taper mimicing the behavior during the response removal, without a actual response removal. :param tr: input trace :param pre_filt: frequency array(Hz) in ascending order, to define the four corners of filter, for example, [0.01, 0.1, 0.2, 0.5]. :type pre_filt: Numpy.array or list :return: filtered trace """ if not isinstance(tr, Trace): raise TypeError("First Argument should be trace: %s" % type(tr)) if not check_array_order(pre_filt): raise ValueError("Frequency band should be in ascending order: %s" % pre_filt) data = tr.data.astype(np.float64) # smart calculation of nfft dodging large primes nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:len(data)] # assign processed data and store processing information tr.data = data
def filter_synt(tr, pre_filt): """ Perform a frequency domain taper like during the response removal just without an actual response... :param tr: :param pre_filt: :return: """ data = tr.data.astype(np.float64) # smart calculation of nfft dodging large primes nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0 : len(data)] # assign processed data and store processing information tr.data = data
def process_function(st, inv): st.detrend("linear") st.detrend("demean") st.taper(max_percentage=0.05, type="hann") # Perform a frequency domain taper like during the response removal # just without an actual response... for tr in st: data = tr.data.astype(np.float64) # smart calculation of nfft dodging large primes from obspy.signal.util import _npts2nfft nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:len(data)] # assign processed data and store processing information tr.data = data st.detrend("linear") st.detrend("demean") st.taper(max_percentage=0.05, type="hann") st.interpolate(sampling_rate=sampling_rate, starttime=starttime, npts=npts) components = [tr.stats.channel[-1] for tr in st] if "N" in components and "E" in components: station_latitude = inv[0][0].latitude station_longitude = inv[0][0].longitude _, baz, _ = gps2DistAzimuth(station_latitude, station_longitude, event_latitude, event_longitude) st.rotate(method="NE->RT", back_azimuth=baz) # Convert to single precision to save space. for tr in st: tr.data = np.require(tr.data, dtype="float32") return st
def process_synthetics(self): lowpass_freq = 1 / 60. highpass_freq = 1 / 120. freqmin = highpass_freq freqmax = lowpass_freq f2 = highpass_freq f3 = lowpass_freq f1 = 0.8 * f2 f4 = 1.2 * f3 pre_filt = (f1, f2, f3, f4) self.tr.differentiate() # self.tr.data = convolve_stf(self.tr.data) self.tr.detrend("linear") self.tr.detrend("demean") self.tr.taper(max_percentage=0.05, type="hann") # Perform a frequency domain taper like during the response removal # just without an actual response... data = self.tr.data.astype(np.float64) orig_len = len(data) # smart calculation of nfft dodging large primes from obspy.signal.util import _npts2nfft from obspy.signal.invsim import c_sac_taper nfft = _npts2nfft(len(data)) fy = 1.0 / (self.tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:orig_len] # assign processed data and store processing information self.tr.data = data
def pre_filter(stream, pre_filt=(0.02, 0.05, 8.0, 10.0)): """ Applies the same filter as remove_response without actually removing the response. """ for tr in stream: data = tr.data.astype(np.float64) nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:tr.stats.npts] # assign processed data and store processing information tr.data = data return stream
def process_synt(datadir, station, event = None, stationxml_dir = None, period_band = None, npts=None, sampling_rate=None, output_dir=None, suffix=None): # ensemble the stream #station_list = generate_station_list(datadir) #for station in station_list: zdatafile = station[0] + "." + station[1] + ".MXZ.sem.sac" ndatafile = station[0] + "." + station[1] + ".MXN.sem.sac" edatafile = station[0] + "." + station[1] + ".MXE.sem.sac" zpath = os.path.join(datadir, zdatafile) npath = os.path.join(datadir, ndatafile) epath = os.path.join(datadir, edatafile) st = read(zpath) st2 = read(npath) st3 = read(epath) #print st #print st2 st.append(st2[0]) st.append(st3[0]) #print "\nProcessing file: %s" %filename # interpolation value #npts = 3630 #sampling_rate = 1.0 # Hz min_period = period_band[0] max_period = period_band[1] f2 = 1.0 / max_period f3 = 1.0 / min_period f1 = 0.8 * f2 f4 = 1.2 * f3 pre_filt = (f1, f2, f3, f4) # fetch event information event_name = get_event_name(event) short_event_name = adjust_event_name(event_name) origin = event.preferred_origin() or event.origins[0] event_latitude = origin.latitude event_longitude = origin.longitude event_time = origin.time event_depth = origin.depth starttime = event_time print "event_time:",event_time #output_path = os.path.join(output_dir, short_event_name) if not os.path.exists(output_dir): os.makedirs(output_dir) nrecords = len(st) # processing for i, tr in enumerate(st): #get component name cmpname = tr.stats.channel #print tr.stats #tr.interpolate(sampling_rate=sampling_rate, starttime=starttime, # npts=npts) #tr.decimate(4, strict_length=False,no_filter=True) print "Processing %d of total %d" %(i+1, nrecords) print "Detrend, Demean and Taper..." tr.detrend("linear") tr.detrend("demean") tr.taper(max_percentage=0.05, type="hann") #print "response show:" #print tr.stats.response # Perform a frequency domain taper like during the response removal # just without an actual response... #for tr in st: print "Filtering..." data = tr.data.astype(np.float64) # smart calculation of nfft dodging large primes from obspy.signal.util import _npts2nfft nfft = _npts2nfft(len(data)) fy = 1.0 / (tr.stats.delta * 2.0) freqs = np.linspace(0, fy, nfft // 2 + 1) # Transform data to Frequency domain data = np.fft.rfft(data, n=nfft) data *= c_sac_taper(freqs, flimit=pre_filt) data[-1] = abs(data[-1]) + 0.0j # transform data back into the time domain data = np.fft.irfft(data)[0:len(data)] # assign processed data and store processing information tr.data = data print "Detrend, Demean and Taper again..." tr.detrend("linear") tr.detrend("demean") tr.taper(max_percentage=0.05, type="hann") print "Interpolate..." try: tr.interpolate(sampling_rate=sampling_rate, starttime=starttime, npts=npts) except: print "Error" return # rotate station_latitude = st[0].stats.sac['stla'] station_longitude = st[0].stats.sac['stlo'] event_latitude = st[0].stats.sac['evla'] event_longitude = st[0].stats.sac['evlo'] #print station_latitude, station_longitude #print station_latitude, station_longitude _, baz, _ = gps2DistAzimuth(station_latitude, station_longitude, event_latitude, event_longitude) print st st.rotate(method="NE->RT", back_azimuth=baz) # write out print st for tr in st: comp = tr.stats.channel outfn = station[0] + "." + station[1] + "." + comp + ".sac" if suffix is not None and suffix != "": outfn = outfn + "." + suffix outpath = os.path.join(output_dir, outfn) print "file saved:", outpath tr.stats.sac['b'] = 0 tr.stats.sac['iztype'] = 9 tr.write(outpath, format="SAC")
def correct_response(st, removeResp=False, removePAZ=False, simPAZ=False, pre_filt=None, cornFreq=0.0083): """ Correct the seismometer response. Seismometer response is given in either a dictionary ``removeResp'' or a dictionary ``removePAZ''. ``removeResp has precedence. The dictionaries have the following structure removeResp: dictionary with Response information to be removed has the following keys: respfile: (str) filename of evalresp response file. units: (str) Units to return response in. Can be either DIS, VEL or ACC start_stage: (int) integer stage numbers of start stage (<0 causes default evalresp bahaviour). stop_stage: (int) integer stage numbers of stop stage removePAZ: dictionary with poles and zeros to be removed has the following keys: poles: (list of complex numbers) location of poles zeros: (list of complex numbers) location of zeros gain: (float) gain sensitivity: (float) sensitivity It can easily be retrieved with obspy.arclink.client.Client.getPAZ if ``removeResp'' is given the response of each trace must be present in the respfile. If ``removePAZ'' is used the response is assumed to be the same for all traces in the stream. A filter specified in pre_filt can be applied in to avoid amplification of noise. The instrument to be simulated is either described in the dictionary simPAZ or if simPAZ is False by the corner frequency ``cornFreq''. Response correction is done in place and original data is overwritten. The input stream ``st'' should be demeaned and tapered. :type st: obspy.core.stream.Stream :param st: data stream to be corrected :type removeResp: dict :param removeResp: Response information to be removed :type removePAZ: dict :param removePAZ: Response information to be removed :type simPAZ: dict :param simPAZ: Response information to be simulated :type cornFreq: float :param cornFreq: corner frequency of instrument to be simulated :type pre_filt: list :param pre_filt: 4 corners of the filter """ for tr in st: starttime = tr.stats['starttime'] endtime = tr.stats['endtime'] network = tr.stats['network'] station = tr.stats['station'] channel = tr.stats['channel'] location = tr.stats['location'] length = tr.stats['npts'] sampling_rate = tr.stats['sampling_rate'] np2l = nextpow2(2.*length) if not simPAZ: simPAZ = cornFreq2Paz(cornFreq, damp=0.70716) simresp, freqs = np.conj(pazToFreqResp(simPAZ['poles'], simPAZ['zeros'], scale_fac=simPAZ['gain']*simPAZ['sensitivity'], t_samp=1./sampling_rate, nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj() if removeResp: freqresp, freqs = evalresp(1./sampling_rate,np2l,removeResp['respfile'], starttime, network=network, station=station, channel=channel, locid=location, start_stage=removeResp['start_stage'], stop_stage=removeResp['stop_stage'], units=removeResp['units'], freq=True) else: freqresp, freqs = np.conj(pazToFreqResp(removePAZ['poles'], removePAZ['zeros'], scale_fac=removePAZ['gain']*removePAZ['sensitivity'], t_samp=1./sampling_rate, nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj() ftr = np.fft.rfft(tr.data,n=np2l) ftr /= freqresp ftr[0] = 0.j # correct the NaN in the DC component ftr *= simresp if pre_filt: ftr *= c_sac_taper(freqs, flimit=pre_filt) tr.data = np.fft.irfft(ftr) tr.trim(starttime,endtime) return
def correct_response(st, removeResp=False, removePAZ=False, simPAZ=False, pre_filt=None, cornFreq=0.0083): """ Correct the seismometer response. Seismometer response is given in either a dictionary ``removeResp'' or a dictionary ``removePAZ''. ``removeResp has precedence. The dictionaries have the following structure removeResp: dictionary with Response information to be removed has the following keys: respfile: (str) filename of evalresp response file. units: (str) Units to return response in. Can be either DIS, VEL or ACC start_stage: (int) integer stage numbers of start stage (<0 causes default evalresp bahaviour). stop_stage: (int) integer stage numbers of stop stage removePAZ: dictionary with poles and zeros to be removed has the following keys: poles: (list of complex numbers) location of poles zeros: (list of complex numbers) location of zeros gain: (float) gain sensitivity: (float) sensitivity It can easily be retrieved with obspy.arclink.client.Client.getPAZ if ``removeResp'' is given the response of each trace must be present in the respfile. If ``removePAZ'' is used the response is assumed to be the same for all traces in the stream. A filter specified in pre_filt can be applied in to avoid amplification of noise. The instrument to be simulated is either described in the dictionary simPAZ or if simPAZ is False by the corner frequency ``cornFreq''. Response correction is done in place and original data is overwritten. The input stream ``st'' should be demeaned and tapered. :type st: obspy.core.stream.Stream :param st: data stream to be corrected :type removeResp: dict :param removeResp: Response information to be removed :type removePAZ: dict :param removePAZ: Response information to be removed :type simPAZ: dict :param simPAZ: Response information to be simulated :type cornFreq: float :param cornFreq: corner frequency of instrument to be simulated :type pre_filt: list :param pre_filt: 4 corners of the filter """ for tr in st: starttime = tr.stats['starttime'] endtime = tr.stats['endtime'] network = tr.stats['network'] station = tr.stats['station'] channel = tr.stats['channel'] location = tr.stats['location'] length = tr.stats['npts'] sampling_rate = tr.stats['sampling_rate'] np2l = nextpow2(2. * length) if not simPAZ: simPAZ = cornFreq2Paz(cornFreq, damp=0.70716) simresp, freqs = np.conj( pazToFreqResp( simPAZ['poles'], simPAZ['zeros'], scale_fac=simPAZ['gain'] * simPAZ['sensitivity'], t_samp=1. / sampling_rate, nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj() if removeResp: freqresp, freqs = evalresp(1. / sampling_rate, np2l, removeResp['respfile'], starttime, network=network, station=station, channel=channel, locid=location, start_stage=removeResp['start_stage'], stop_stage=removeResp['stop_stage'], units=removeResp['units'], freq=True) else: freqresp, freqs = np.conj( pazToFreqResp( removePAZ['poles'], removePAZ['zeros'], scale_fac=removePAZ['gain'] * removePAZ['sensitivity'], t_samp=1. / sampling_rate, nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj() ftr = np.fft.rfft(tr.data, n=np2l) ftr /= freqresp ftr[0] = 0.j # correct the NaN in the DC component ftr *= simresp if pre_filt: ftr *= c_sac_taper(freqs, flimit=pre_filt) tr.data = np.fft.irfft(ftr) tr.trim(starttime, endtime) return