def __init__(self, stats, paz=None, parser=None, skip_on_gaps=False, is_rotational_data=False, db_bins=(-200, -50, 1.), ppsd_length=3600., overlap=0.5): """ Initialize the PPSD object setting all fixed information on the station that should not change afterwards to guarantee consistent spectral estimates. The necessary instrument response information can be provided in two ways: * Providing an `obspy.xseed` :class:`~obspy.xseed.parser.Parser`, e.g. containing metadata from a Dataless SEED file. This is the safer way but it might a bit slower because for every processed time segment the response information is extracted from the parser. * Providing a dictionary containing poles and zeros information. Be aware that this leads to wrong results if the instrument's response is changing with data added to the PPSD. Use with caution! :note: When using `is_rotational_data=True` the applied processing steps are changed. Differentiation of data (converting velocity to acceleration data) will be omitted and a flat instrument response is assumed, leaving away response removal and only dividing by `paz['sensitivity']` specified in the provided `paz` dictionary (other keys do not have to be present then). For scaling factors that are usually multiplied to the data remember to use the inverse as `paz['sensitivity']`. :type stats: :class:`~obspy.core.trace.Stats` :param stats: Stats of the station/instrument to process :type paz: dict, optional :param paz: Response information of instrument. If not specified the information is supposed to be present as stats.paz. :type parser: :class:`obspy.xseed.parser.Parser`, optional :param parser: Parser instance with response information (e.g. read from a Dataless SEED volume) :type skip_on_gaps: bool, optional :param skip_on_gaps: Determines whether time segments with gaps should be skipped entirely. [McNamara2004]_ merge gappy traces by filling with zeros. This results in a clearly identifiable outlier psd line in the PPSD visualization. Select `skip_on_gaps=True` for not filling gaps with zeros which might result in some data segments shorter than `ppsd_length` not used in the PPSD. :type is_rotational_data: bool, optional :param is_rotational_data: If set to True adapt processing of data to rotational data. See note for details. :type db_bins: tuple of three ints/floats :param db_bins: Specify the lower and upper boundary and the width of the db bins. The bin width might get adjusted to fit a number of equally spaced bins in between the given boundaries. :type ppsd_length: float, optional :param ppsd_length: Length of data segments passed to psd in seconds. In the paper by [McNamara2004]_ a value of 3600 (1 hour) was chosen. Longer segments increase the upper limit of analyzed periods but decrease the number of analyzed segments. :type overlap: float, optional :param overlap: Overlap of segments passed to psd. Overlap may take values between 0 and 1 and is given as fraction of the length of one segment, e.g. `ppsd_length=3600` and `overlap=0.5` result in an overlap of 1800s of the segments. """ # check if matplotlib is available, no official dependency for # obspy.signal if MATPLOTLIB_VERSION is None: raise ImportError(msg_matplotlib_ImportError) if paz is not None and parser is not None: msg = "Both paz and parser specified. Using parser object for " \ "metadata." warnings.warn(msg) self.id = "%(network)s.%(station)s.%(location)s.%(channel)s" % stats self.network = stats.network self.station = stats.station self.location = stats.location self.channel = stats.channel self.sampling_rate = stats.sampling_rate self.delta = 1.0 / self.sampling_rate self.is_rotational_data = is_rotational_data self.ppsd_length = ppsd_length self.overlap = overlap # trace length for one segment self.len = int(self.sampling_rate * ppsd_length) # set paz either from kwarg or try to get it from stats self.paz = paz self.parser = parser if skip_on_gaps: self.merge_method = -1 else: self.merge_method = 0 # nfft is determined mimicking the fft setup in McNamara&Buland paper: # (they take 13 segments overlapping 75% and truncate to next lower # power of 2) # - take number of points of whole ppsd segment (default 1 hour) self.nfft = ppsd_length * self.sampling_rate # - make 13 single segments overlapping by 75% # (1 full segment length + 25% * 12 full segment lengths) self.nfft = self.nfft / 4.0 # - go to next smaller power of 2 for nfft self.nfft = prevpow2(self.nfft) # - use 75% overlap (we end up with a little more than 13 segments..) self.nlap = int(0.75 * self.nfft) self.times_used = [] self.times = self.times_used self.times_data = [] self.times_gaps = [] self.hist_stack = None self.__setup_bins() # set up the binning for the db scale num_bins = int((db_bins[1] - db_bins[0]) / db_bins[2]) self.spec_bins = np.linspace(db_bins[0], db_bins[1], num_bins + 1, endpoint=True) self.colormap = LinearSegmentedColormap('mcnamara', CDICT, 1024)
def __init__(self, stats, paz=None, parser=None, skip_on_gaps=False, is_rotational_data=False, db_bins=(-200, -50, 1.), ppsd_length=3600., overlap=0.5, water_level=600.0): """ Initialize the PPSD object setting all fixed information on the station that should not change afterwards to guarantee consistent spectral estimates. The necessary instrument response information can be provided in two ways: * Providing an `obspy.xseed` :class:`~obspy.xseed.parser.Parser`, e.g. containing metadata from a Dataless SEED file. This is the safer way but it might a bit slower because for every processed time segment the response information is extracted from the parser. * Providing a dictionary containing poles and zeros information. Be aware that this leads to wrong results if the instrument's response is changing with data added to the PPSD. Use with caution! :note: When using `is_rotational_data=True` the applied processing steps are changed. Differentiation of data (converting velocity to acceleration data) will be omitted and a flat instrument response is assumed, leaving away response removal and only dividing by `paz['sensitivity']` specified in the provided `paz` dictionary (other keys do not have to be present then). For scaling factors that are usually multiplied to the data remember to use the inverse as `paz['sensitivity']`. :type stats: :class:`~obspy.core.trace.Stats` :param stats: Stats of the station/instrument to process :type paz: dict, optional :param paz: Response information of instrument. If not specified the information is supposed to be present as stats.paz. :type parser: :class:`obspy.xseed.parser.Parser`, optional :param parser: Parser instance with response information (e.g. read from a Dataless SEED volume) :type skip_on_gaps: bool, optional :param skip_on_gaps: Determines whether time segments with gaps should be skipped entirely. [McNamara2004]_ merge gappy traces by filling with zeros. This results in a clearly identifiable outlier psd line in the PPSD visualization. Select `skip_on_gaps=True` for not filling gaps with zeros which might result in some data segments shorter than `ppsd_length` not used in the PPSD. :type is_rotational_data: bool, optional :param is_rotational_data: If set to True adapt processing of data to rotational data. See note for details. :type db_bins: tuple of three ints/floats :param db_bins: Specify the lower and upper boundary and the width of the db bins. The bin width might get adjusted to fit a number of equally spaced bins in between the given boundaries. :type ppsd_length: float, optional :param ppsd_length: Length of data segments passed to psd in seconds. In the paper by [McNamara2004]_ a value of 3600 (1 hour) was chosen. Longer segments increase the upper limit of analyzed periods but decrease the number of analyzed segments. :type overlap: float, optional :param overlap: Overlap of segments passed to psd. Overlap may take values between 0 and 1 and is given as fraction of the length of one segment, e.g. `ppsd_length=3600` and `overlap=0.5` result in an overlap of 1800s of the segments. :type water_level: float, optional :param water_level: Water level used in instrument correction. """ if paz is not None and parser is not None: msg = "Both paz and parser specified. Using parser object for " \ "metadata." warnings.warn(msg) self.id = "%(network)s.%(station)s.%(location)s.%(channel)s" % stats self.network = stats.network self.station = stats.station self.location = stats.location self.channel = stats.channel self.sampling_rate = stats.sampling_rate self.delta = 1.0 / self.sampling_rate self.is_rotational_data = is_rotational_data self.ppsd_length = ppsd_length self.overlap = overlap self.water_level = water_level # trace length for one segment self.len = int(self.sampling_rate * ppsd_length) # set paz either from kwarg or try to get it from stats self.paz = paz self.parser = parser if skip_on_gaps: self.merge_method = -1 else: self.merge_method = 0 # nfft is determined mimicking the fft setup in McNamara&Buland paper: # (they take 13 segments overlapping 75% and truncate to next lower # power of 2) # - take number of points of whole ppsd segment (default 1 hour) self.nfft = ppsd_length * self.sampling_rate # - make 13 single segments overlapping by 75% # (1 full segment length + 25% * 12 full segment lengths) self.nfft = self.nfft / 4.0 # - go to next smaller power of 2 for nfft self.nfft = prevpow2(self.nfft) # - use 75% overlap (we end up with a little more than 13 segments..) self.nlap = int(0.75 * self.nfft) self.times_used = [] self.times = self.times_used self.times_data = [] self.times_gaps = [] self.hist_stack = None self.__setup_bins() # set up the binning for the db scale num_bins = int((db_bins[1] - db_bins[0]) / db_bins[2]) self.spec_bins = np.linspace(db_bins[0], db_bins[1], num_bins + 1, endpoint=True) self.colormap = LinearSegmentedColormap('mcnamara', CDICT, 1024)
import numpy as np from obspy.core import read import sys from obspy.signal.util import prevpow2 st = read(sys.argv[1]) print 'Stream read from the following address\n%s\ncontains:\n%s' %(sys.argv[1], st) st = st.merge() tr = st[0] print 'Trace is:\n\n%s' % tr #tr.resample(20.0) #tr.filter('lowpass', freq = 2.0) #tr.filter('highpass', freq = 0.001) samp_rate = tr.stats.sampling_rate nyquist = samp_rate/2. #tr_fft = np.fft.fft(tr.data) #fft_power_amp = tr_fft.real**2 + tr_fft.imag**2 #fft_amp = np.sqrt(fft_power_amp) #tr.data -= tr.data.mean() num = prevpow2((len(tr.data))) fft_amp_new = np.fft.rfft(tr.data, n = num) freq = np.linspace(0, samp_rate, num) #plt.plot(np.log10(freq[0:(len(freq)/2)]), np.log10(fft_amp[0:(len(freq)/2)])) #plt.plot(np.log10(freq[0:(len(freq)/2)]), abs(fft_amp_new[0:(len(freq)/2)])) plt.plot(np.log10(freq[1:(len(freq)/2)]), np.log10(abs(fft_amp_new[1:(len(freq)/2)]))) plt.show()
def __init__(self, stats, paz=None, parser=None, skip_on_gaps=False, is_rotational_data=False, db_bins=[-200, -50, 0.5]): """ Initialize the PPSD object setting all fixed information on the station that should not change afterwards to guarantee consistent spectral estimates. The necessary instrument response information can be provided in two ways: * Providing an `obspy.xseed` :class:`~obspy.xseed.parser.Parser`, e.g. containing metadata from a Dataless SEED file. This is the safer way but it might a bit slower because for every processed time segment the response information is extracted from the parser. * Providing a dictionary containing poles and zeros information. Be aware that this leads to wrong results if the instrument's response is changing with data added to the PPSD. Use with caution! :note: When using `is_rotational_data=True` the applied processing steps are changed. Differentiation of data (converting velocity to acceleration data) will be omitted and a flat instrument response is assumed, leaving away response removal and only dividing by `paz['sensitivity']` specified in the provided `paz` dictionary (other keys do not have to be present then). For scaling factors that are usually multiplied to the data remember to use the inverse as `paz['sensitivity']`. :type stats: :class:`~obspy.core.trace.Stats` :param stats: Stats of the station/instrument to process :type paz: dict (optional) :param paz: Response information of instrument. If not specified the information is supposed to be present as stats.paz. :type parser: :class:`obspy.xseed.parser.Parser` (optional) :param parser: Parser instance with response information (e.g. read from a Dataless SEED volume) :type skip_on_gaps: Boolean (optional) :param skip_on_gaps: Determines whether time segments with gaps should be skipped entirely. McNamara & Buland merge gappy traces by filling with zeros. This results in a clearly identifiable outlier psd line in the PPSD visualization. Select `skip_on_gaps=True` for not filling gaps with zeros which might result in some data segments shorter than 1 hour not used in the PPSD. :type is_rotational_data: Boolean (optional) :param is_rotational_data: If set to True adapt processing of data to rotational data. See note for details. :type db_bins: List of three ints/floats :param db_bins: Specify the lower and upper boundary and the width of the db bins. The bin width might get adjusted to fit a number of equally spaced bins in between the given boundaries. """ # check if matplotlib is available, no official dependency for # obspy.signal if MATPLOTLIB_VERSION is None: raise ImportError(msg_matplotlib_ImportError) if paz is not None and parser is not None: msg = "Both paz and parser specified. Using parser object for " \ "metadata." warnings.warn(msg) self.id = "%(network)s.%(station)s.%(location)s.%(channel)s" % stats self.network = stats.network self.station = stats.station self.location = stats.location self.channel = stats.channel self.sampling_rate = stats.sampling_rate self.delta = 1.0 / self.sampling_rate self.is_rotational_data = is_rotational_data # trace length for one hour piece self.len = int(self.sampling_rate * PPSD_LENGTH) # set paz either from kwarg or try to get it from stats self.paz = paz self.parser = parser if skip_on_gaps: self.merge_method = -1 else: self.merge_method = 0 # nfft is determined mimicing the fft setup in McNamara&Buland paper: # (they take 13 segments overlapping 75% and truncate to next lower # power of 2) # - take number of points of whole ppsd segment (currently 1 hour) self.nfft = PPSD_LENGTH * self.sampling_rate # - make 13 single segments overlapping by 75% # (1 full segment length + 25% * 12 full segment lengths) self.nfft = self.nfft / 4.0 # - go to next smaller power of 2 for nfft self.nfft = prevpow2(self.nfft) # - use 75% overlap (we end up with a little more than 13 segments..) self.nlap = int(0.75 * self.nfft) self.times_used = [] self.times = self.times_used self.times_data = [] self.times_gaps = [] self.hist_stack = None self.__setup_bins() # set up the binning for the db scale num_bins = int((db_bins[1] - db_bins[0]) / db_bins[2]) self.spec_bins = np.linspace(db_bins[0], db_bins[1], num_bins + 1, endpoint=True) self.colormap = LinearSegmentedColormap('mcnamara', CDICT, 1024)
import sys from obspy.signal.util import prevpow2 st = read(sys.argv[1]) print 'Stream read from the following address\n%s\ncontains:\n%s' % ( sys.argv[1], st) st = st.merge() tr = st[0] print 'Trace is:\n\n%s' % tr #tr.resample(20.0) #tr.filter('lowpass', freq = 2.0) #tr.filter('highpass', freq = 0.001) samp_rate = tr.stats.sampling_rate nyquist = samp_rate / 2. #tr_fft = np.fft.fft(tr.data) #fft_power_amp = tr_fft.real**2 + tr_fft.imag**2 #fft_amp = np.sqrt(fft_power_amp) #tr.data -= tr.data.mean() num = prevpow2((len(tr.data))) fft_amp_new = np.fft.rfft(tr.data, n=num) freq = np.linspace(0, samp_rate, num) #plt.plot(np.log10(freq[0:(len(freq)/2)]), np.log10(fft_amp[0:(len(freq)/2)])) #plt.plot(np.log10(freq[0:(len(freq)/2)]), abs(fft_amp_new[0:(len(freq)/2)])) plt.plot(np.log10(freq[1:(len(freq) / 2)]), np.log10(abs(fft_amp_new[1:(len(freq) / 2)]))) plt.show()