-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subspace Freq domain statistic #92
Changes from 20 commits
901a515
701dc88
bb4ddfd
dc08366
571261c
5daa1f5
34a8621
c33e294
7d7222c
f3988ff
5b61480
b1935e3
ccd3529
75b99b5
615dc81
0b60356
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ | |
from __future__ import unicode_literals | ||
|
||
import numpy as np | ||
import scipy | ||
import warnings | ||
import time | ||
import h5py | ||
|
@@ -473,7 +472,6 @@ def _detect(detector, st, threshold, trig_int, moveout=0, min_trig=0, | |
:return: list of detections | ||
:rtype: list of eqcorrscan.core.match_filter.Detection | ||
""" | ||
from eqcorrscan.core import subspace_statistic | ||
detections = [] | ||
# First process the stream | ||
if process: | ||
|
@@ -493,27 +491,25 @@ def _detect(detector, st, threshold, trig_int, moveout=0, min_trig=0, | |
stream = [st] | ||
stachans = detector.stachans | ||
outtic = time.clock() | ||
if debug > 0: | ||
print('Computing detection statistics') | ||
# If multiplexed, how many samples do we increment by? | ||
if detector.multiplex: | ||
inc = np.uint32(len(detector.stachans)) | ||
Nc = len(detector.stachans) | ||
else: | ||
inc = np.uint32(1) | ||
# Stats must be same size for multiplexed or non multiplexed! | ||
Nc = 1 | ||
# Here do all ffts | ||
fft_vars = do_ffts(detector, stream, Nc) | ||
if debug > 0: | ||
print('Computing detection statistics') | ||
if debug > 0: | ||
print('Preallocating stats matrix') | ||
stats = np.zeros((len(stream[0]), | ||
(len(stream[0][0]) // inc) - | ||
(len(detector.data[0].T[0]) // inc) + 1), | ||
dtype=np.float32) | ||
# Hard typing in Cython loop requires float32 type. | ||
for det_channel, in_channel, i in zip(detector.data, stream[0], | ||
np.arange(len(stream[0]))): | ||
stats[i] = subspace_statistic.\ | ||
det_statistic(detector=det_channel.astype(np.float32), | ||
data=in_channel.data.astype(np.float32), | ||
inc=inc) | ||
(len(stream[0][0]) // Nc) - (fft_vars[4] // Nc) + 1)) | ||
for det_freq, data_freq_sq, data_freq, i in zip(fft_vars[0], fft_vars[1], | ||
fft_vars[2], | ||
np.arange(len(stream[0]))): | ||
# Calculate det_statistic in frequency domain | ||
stats[i] = det_stat_freq(det_freq, data_freq_sq, data_freq, | ||
fft_vars[3], Nc, fft_vars[4], fft_vars[5]) | ||
if debug >= 1: | ||
print('Stats matrix is shape %s' % str(stats[i].shape)) | ||
if debug >= 3: | ||
|
@@ -525,8 +521,7 @@ def _detect(detector, st, threshold, trig_int, moveout=0, min_trig=0, | |
ax.plot([min(t), max(t)], [threshold, threshold], color='r', lw=1, | ||
label='Threshold') | ||
ax.legend() | ||
plt.title('%s.%s' % (in_channel.stats.station, | ||
in_channel.stats.channel)) | ||
plt.title('%s' % str(stream[0][i].stats.station)) | ||
plt.show() | ||
trig_int_samples = detector.sampling_rate * trig_int | ||
if debug > 0: | ||
|
@@ -586,6 +581,39 @@ def _detect(detector, st, threshold, trig_int, moveout=0, min_trig=0, | |
return detections | ||
|
||
|
||
def do_ffts(detector, stream, Nc): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be a private method? If so it should start with an underscore, if not probably needs a docstring. I think a good rule is to add docstring to all functions. For private functions/methods a simple sentence or two that explains what it does is fine, but all public methods should have fancy formatted docstrings sphinx can use. |
||
min_fftlen = int(stream[0][0].data.shape[0] + | ||
detector.data[0].shape[0] - Nc) | ||
fftlen = 1 << min_fftlen.bit_length() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure this is optimal anymore... I know scipy doesn't require a power of 2 length (although the docs do say it is optimal I suspect it is no longer the case). Consider this (note I am using Anaconda which uses the MLK ): import numpy as np
import scipy.fftpack
ar_len = 3600 * 400 + 12 # a resonable size for a seismic trace
nearest_2 = 1 << (ar_len - 1).bit_length()
nearest_fast = scipy.fftpack.next_fast_len(ar_len)
%time np.fft.fft(ar, n=nearest_2) # takes 386 ms
%time np.fft.fft(ar, n=nearest_fast) # takes 228 ms Moreover, if you are only expecting real inputs (A fair assumption in seismology no?) consider using rfft: %time np.fft.rfft(ar, n=nearest_2) # takes 200 ms
%time np.fft.rfft(ar, n=nearest_fast) # takes 123 ms Using rfft with next_fast_length would give nearly a 4x speed up (similar on ifft) |
||
mplen = stream[0][0].data.shape[0] | ||
ulen = detector.data[0].shape[0] | ||
num_st_fd = [np.fft.fft(tr.data, n=fftlen) | ||
for tr in stream[0]] | ||
denom_st_fd = [np.fft.fft(np.square(tr.data), n=fftlen) | ||
for tr in stream[0]] | ||
# Frequency domain of boxcar | ||
w = np.fft.fft(np.ones(detector.data[0].shape[0]), | ||
n=fftlen) | ||
# This should go into the detector object as in Detex | ||
detector_fd = [] | ||
for dat_mat in detector.data: | ||
detector_fd.append(np.array([np.fft.fft(col[::-1], n=fftlen) | ||
for col in dat_mat.T])) | ||
return detector_fd, denom_st_fd, num_st_fd, w, ulen, mplen | ||
|
||
|
||
def det_stat_freq(det_freq, data_freq_sq, data_freq, w, Nc, ulen, mplen): | ||
num_cor = np.multiply(det_freq, data_freq) # Numerator convolution | ||
den_cor = np.multiply(w, data_freq_sq) # Denominator convolution | ||
# Do inverse fft | ||
# First and last Nt - 1 samples are invalid; clip them off | ||
num_ifft = np.real(np.fft.ifft(num_cor))[:, ulen-1:mplen:Nc] | ||
denominator = np.real(np.fft.ifft(den_cor))[ulen-1:mplen:Nc] | ||
# Ratio of projected to envelope energy = det_stat across all channels | ||
result = np.sum(np.square(num_ifft), axis=0) / denominator | ||
return result | ||
|
||
|
||
def _subspace_process(streams, lowcut, highcut, filt_order, sampling_rate, | ||
multiplex, align, shift_len, reject, no_missed=True, | ||
stachans=None, parallel=False, plot=False): | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maintain indent for comment here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment removed in some recent commit.