def powspecSN(st, stnoise, SNrat=1.5, win=None): """ Return masked arrays of power spectrum, masking where SNratio is greater than SNrat USAGE freqs, amps, ampmask = powspecSN(st, stnoise, SNrat=1.5, freqlim=(0, 25), win=None) INPUTS st = obspy stream object, or trace object stnoise = obspy stream object from time period just before st (or whatever noise window desired, but needs to have same sample rate) win = tuple of time window in seconds (e.g. win=(3., 20.)) over which to compute mean squared frequency, None computes for entire time window in each trace of st OUTPUTS freqs = list of np.arrays of frequency vectors (Hz) amps = list of np.arrays of amplitudes ampmaks = list of np.arrays of masked amplitudes """ import obspy.signal.spectral_estimation as spec st = Stream(st) # turn into a stream object in case st is a trace stnoise = Stream(stnoise) freqs = [] # preallocate amps = [] ampmask = [] for i, trace in enumerate(st): if trace.stats.sampling_rate != stnoise[i].stats.sampling_rate: print 'Signal and noise sample rates are different. Abort!' return Fs = trace.stats.sampling_rate # Time vector dat = trace.data pFs = stnoise[i].stats.sampling_rate pdat = stnoise[i].data tvec = maketvec(trace) # Time vector if win is not None: if win[1] > tvec.max() or win[0] < tvec.min(): print 'Time window specified not compatible with length of time series' return dat = dat[(tvec >= win[0]) & (tvec <= win[1])] trace = trace.trim(trace.stats.starttime + win[0], trace.stats.starttime + win[1]) # Find max nfft of the two and use that for both so they line up maxnfft = np.max((nextpow2(len(dat)), nextpow2(len(pdat)))) Pxx, f = spec.psd(dat, NFFT=maxnfft, Fs=Fs) pPxx, pf = spec.psd(pdat, NFFT=maxnfft, Fs=pFs) idx = (Pxx / pPxx < SNrat) # good values amps.append(Pxx) freqs.append(f) ampmask.append(ma.array(Pxx, mask=idx)) return freqs, amps, ampmask
def powspecSN(st, stnoise, SNrat=1.5, win=None): """ Return masked arrays of power spectrum, masking where SNratio is greater than SNrat USAGE freqs, amps, ampmask = powspecSN(st, stnoise, SNrat=1.5, freqlim=(0, 25), win=None) INPUTS st = obspy stream object, or trace object stnoise = obspy stream object from time period just before st (or whatever noise window desired, but needs to have same sample rate) win = tuple of time window in seconds (e.g. win=(3., 20.)) over which to compute mean squared frequency, None computes for entire time window in each trace of st OUTPUTS freqs = list of np.arrays of frequency vectors (Hz) amps = list of np.arrays of amplitudes ampmaks = list of np.arrays of masked amplitudes """ import obspy.signal.spectral_estimation as spec st = Stream(st) # turn into a stream object in case st is a trace stnoise = Stream(stnoise) freqs = [] # preallocate amps = [] ampmask = [] for i, trace in enumerate(st): if trace.stats.sampling_rate != stnoise[i].stats.sampling_rate: print 'Signal and noise sample rates are different. Abort!' return Fs = trace.stats.sampling_rate # Time vector dat = trace.data pFs = stnoise[i].stats.sampling_rate pdat = stnoise[i].data tvec = maketvec(trace) # Time vector if win is not None: if win[1] > tvec.max() or win[0] < tvec.min(): print 'Time window specified not compatible with length of time series' return dat = dat[(tvec >= win[0]) & (tvec <= win[1])] trace = trace.trim(trace.stats.starttime+win[0], trace.stats.starttime+win[1]) # Find max nfft of the two and use that for both so they line up maxnfft = np.max((nextpow2(len(dat)), nextpow2(len(pdat)))) Pxx, f = spec.psd(dat, NFFT=maxnfft, Fs=Fs) pPxx, pf = spec.psd(pdat, NFFT=maxnfft, Fs=pFs) idx = (Pxx/pPxx < SNrat) # good values amps.append(Pxx) freqs.append(f) ampmask.append(ma.array(Pxx, mask=idx)) return freqs, amps, ampmask
def test_obspy_psd_vs_pitsa(self): """ Test to compare results of PITSA's psd routine to the :func:`matplotlib.mlab.psd` routine wrapped in :func:`obspy.signal.spectral_estimation.psd`. The test works on 8192 samples long Gaussian noise with a standard deviation of 0.1 generated with PITSA, sampling rate for processing in PITSA was 100.0 Hz, length of nfft 512 samples. The overlap in PITSA cannot be controlled directly, instead only the number of overlapping segments can be specified. Therefore the test works with zero overlap to have full control over the data segments used in the psd. It seems that PITSA has one frequency entry more, i.e. the psd is one point longer. I dont know were this can come from, for now this last sample in the psd is ignored. """ SAMPLING_RATE = 100.0 NFFT = 512 NOVERLAP = 0 file_noise = os.path.join(self.path, "pitsa_noise.npy") fn_psd_pitsa = "pitsa_noise_psd_samprate_100_nfft_512_noverlap_0.npy" file_psd_pitsa = os.path.join(self.path, fn_psd_pitsa) noise = np.load(file_noise) # in principle to mimic PITSA's results detrend should be specified as # some linear detrending (e.g. from matplotlib.mlab.detrend_linear) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') psd_obspy, _ = psd(noise, NFFT=NFFT, Fs=SAMPLING_RATE, window=welch_taper, noverlap=NOVERLAP) self.assertEqual(len(w), 1) self.assertTrue( 'This wrapper is no longer necessary.' in str(w[0].message)) psd_pitsa = np.load(file_psd_pitsa) # mlab's psd routine returns Nyquist frequency as last entry, PITSA # seems to omit it and returns a psd one frequency sample shorter. psd_obspy = psd_obspy[:-1] # test results. first couple of frequencies match not as exactly as all # the rest, test them separately with a little more allowance.. np.testing.assert_array_almost_equal(psd_obspy[:3], psd_pitsa[:3], decimal=4) np.testing.assert_array_almost_equal(psd_obspy[1:5], psd_pitsa[1:5], decimal=5) np.testing.assert_array_almost_equal(psd_obspy[5:], psd_pitsa[5:], decimal=6)
def test_obspy_psd_vs_pitsa(self): """ Test to compare results of PITSA's psd routine to the :func:`matplotlib.mlab.psd` routine wrapped in :func:`obspy.signal.spectral_estimation.psd`. The test works on 8192 samples long Gaussian noise with a standard deviation of 0.1 generated with PITSA, sampling rate for processing in PITSA was 100.0 Hz, length of nfft 512 samples. The overlap in PITSA cannot be controlled directly, instead only the number of overlapping segments can be specified. Therefore the test works with zero overlap to have full control over the data segments used in the psd. It seems that PITSA has one frequency entry more, i.e. the psd is one point longer. I dont know were this can come from, for now this last sample in the psd is ignored. """ SAMPLING_RATE = 100.0 NFFT = 512 NOVERLAP = 0 file_noise = os.path.join(self.path, "pitsa_noise.npy") fn_psd_pitsa = "pitsa_noise_psd_samprate_100_nfft_512_noverlap_0.npy" file_psd_pitsa = os.path.join(self.path, fn_psd_pitsa) noise = np.load(file_noise) # in principle to mimic PITSA's results detrend should be specified as # some linear detrending (e.g. from matplotlib.mlab.detrend_linear) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') psd_obspy, _ = psd(noise, NFFT=NFFT, Fs=SAMPLING_RATE, window=welch_taper, noverlap=NOVERLAP) self.assertEqual(len(w), 1) self.assertTrue('This wrapper is no longer necessary.' in str(w[0].message)) psd_pitsa = np.load(file_psd_pitsa) # mlab's psd routine returns Nyquist frequency as last entry, PITSA # seems to omit it and returns a psd one frequency sample shorter. psd_obspy = psd_obspy[:-1] # test results. first couple of frequencies match not as exactly as all # the rest, test them separately with a little more allowance.. np.testing.assert_array_almost_equal(psd_obspy[:3], psd_pitsa[:3], decimal=4) np.testing.assert_array_almost_equal(psd_obspy[1:5], psd_pitsa[1:5], decimal=5) np.testing.assert_array_almost_equal(psd_obspy[5:], psd_pitsa[5:], decimal=6)