Пример #1
0
    def decimate(self,decimation_factor,outfile,taper_width=0.005):
        """
        Decimate the wavefield and save to a new file 
        """
        
        fs_old = self.stats['Fs']
        freq = self.stats['Fs'] * 0.4 / float(decimation_factor)

        # Get filter coeff
        sos = filter.cheby2_lowpass(fs_old,freq)

        # figure out new length
        temp_trace = integer_decimation(self.data[0,:], decimation_factor)
        n = len(temp_trace)
       

        # Get taper
        # The default taper is very narrow, because it is expected that the traces are very long.
        taper = cosine_taper(self.stats['nt'],p=taper_width)

       
        # Need a new file, because the length changes.
        with self.copy_setup(newfile=outfile,nt=n) as newfile:

            for i in range(self.stats['ntraces']):
                
                temp_trace = sosfilt(sos,taper*self.data[i,:])
                newfile.data[i,:] = integer_decimation(temp_trace, decimation_factor)
            
        
            newfile.stats['Fs'] = fs_old / float(decimation_factor)
Пример #2
0
def test_sensitivity_kernel():
    class args(object):
        def __init__(self):
            self.source_model = os.path.join('test', 'testdata_v1',
                                             'testsource_v1')
            self.step = 0
            self.steplengthrun = False,
            self.ignore_network = True

    args = args()
    all_config = config_params(args, comm, size, rank)
    ns = get_ns(all_config)
    p = define_kernel_tasks(all_config, comm, size, rank)
    assert len(p[0]) == 3
    assert p[0][2][1].split()[-1] == 'STA2'

    input_files = input_files_kernel(p[0][1], all_config)

    nsrc = os.path.join('test', 'testdata_v1', 'testsource_v1',
                        'spectral_model.h5')
    output_file = "test"
    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off wherever the solver stopped running.
    taper = cosine_taper(ns[0], p=0.01)
    taper[0:ns[0] // 2] = 1.0
    kernel = compute_kernel(input_files[0], output_file, all_config,
                            NoiseSource(nsrc), ns, taper)
    np.save("newtestkernel.npy", kernel)
    saved_kernel = np.load(
        os.path.join('test', 'testdata_v1', 'testdata',
                     'NET.STA1..MXZ--NET.STA2..MXZ.0.npy'))
    assert np.allclose(kernel / kernel.max(),
                       saved_kernel / saved_kernel.max())
Пример #3
0
def corrCodas(a, b, shortWin, overlap, df=20, corr_method='crosscoherence', stack_method='linear'):

    """Moving window correlation function
    :rtype: numpy.array
    :param a, b: the codas to be correlated
    :type a, b: numpy.array
    :param shortWin: short time window for moving wind
    :type shortWin: int, float
    :param step: step to iterate (i.e., for overlap)
    :type step: int
    :rparam: the correlated function of lenght equal to shortWin*2-1.
    """
    N = len(a)
    c = np.zeros(shortWin*2-1)
    cp = cosine_taper(shortWin, 0.1)
    data = np.zeros(len(c))

    for i in xrange(0, N-shortWin, overlap):
        winA = a[i: i+shortWin]
        winB = b[i: i+shortWin]
        cp *= winA; cp*=winB

        if corr_method == 'crosscoherence':
            cc = crosscoherence(winB, winA)
        elif corr_method == 'correlation':
            cc = correlation(winB, winA)
        elif corr_method == 'convolution':
            cc = convolution(winB, winA)

        data = np.vstack((data,cc))

    corr = stack(data, stack_method=stack_method, df=df)

    return corr#/np.max(np.abs(c))
Пример #4
0
    def decimate(self, decimation_factor, outfile, taper_width=0.005):
        """
        Decimate the wavefield and save to a new file 
        """

        fs_old = self.stats['Fs']
        freq = self.stats['Fs'] * 0.4 / float(decimation_factor)

        # Get filter coeff
        sos = filter.cheby2_lowpass(fs_old, freq)

        # figure out new length
        temp_trace = integer_decimation(self.data[0, :], decimation_factor)
        n = len(temp_trace)

        # Get taper
        # The default taper is very narrow, because it is expected that the traces are very long.
        taper = cosine_taper(self.stats['nt'], p=taper_width)

        # Need a new file, because the length changes.
        with self.copy_setup(newfile=outfile, nt=n) as newfile:

            for i in range(self.stats['ntraces']):

                temp_trace = sosfilt(sos, taper * self.data[i, :])
                newfile.data[i, :] = integer_decimation(
                    temp_trace, decimation_factor)

            newfile.stats['Fs'] = fs_old / float(decimation_factor)
Пример #5
0
def check_and_phase_shift(trace):
    # print trace
    taper_length = 20.0
    if trace.stats.npts < 4 * taper_length*trace.stats.sampling_rate:
        trace.data = np.zeros(trace.stats.npts)
        return trace

    dt = np.mod(trace.stats.starttime.datetime.microsecond*1.0e-6,
                trace.stats.delta)
    if (trace.stats.delta - dt) <= np.finfo(float).eps:
        dt = 0
    if dt != 0:
        if dt <= (trace.stats.delta / 2.):
            dt = -dt
#            direction = "left"
        else:
            dt = (trace.stats.delta - dt)
#            direction = "right"
        trace.detrend(type="demean")
        trace.detrend(type="simple")
        taper_1s = taper_length * float(trace.stats.sampling_rate) / trace.stats.npts
        cp = cosine_taper(trace.stats.npts, taper_1s)
        trace.data *= cp

        n = int(2**nextpow2(len(trace.data)))
        FFTdata = scipy.fftpack.fft(trace.data, n=n)
        fftfreq = scipy.fftpack.fftfreq(n, d=trace.stats.delta)
        FFTdata = FFTdata * np.exp(1j * 2. * np.pi * fftfreq * dt)
        trace.data = np.real(scipy.fftpack.ifft(FFTdata, n=n)[:len(trace.data)])
        trace.stats.starttime += dt
        return trace
    else:
        return trace
Пример #6
0
 def test_cosineTaper(self):
     # SAC trace was generated with:
     # taper type cosine width 0.05
     for i in [99, 100]:
         sac_taper = os.path.join(self.path, "ones_trace_%d_tapered.sac" % i)
         tr = read(sac_taper)[0]
         tap = cosine_taper(i, p=0.1, halfcosine=False, sactaper=True)
         np.testing.assert_array_almost_equal(tap, tr.data, decimal=6)
Пример #7
0
def tapering(st_aux):
    [ch, samp] = st_aux.shape
    try:
        cosVal = inv.cosTaper(int(samp), p=0.1)
    except:
        cosVal = inv.cosine_taper(int(samp), p=0.1)
    for ii in range(ch):
        st_aux[ii, :] = st_aux[ii, :] * cosVal
    return st_aux
Пример #8
0
def fft_taper(data):
    """
    Cosine taper, 10 percent at each end (like done by [McNamara2004]_).

    .. warning::
        Inplace operation, so data should be float.
    """
    data *= cosine_taper(len(data), 0.2)
    return data
Пример #9
0
def _fft_taper(data):
    """
    Cosine taper, 10 percent at each end (like done by [McNamara2004]_).

    .. warning::
        Inplace operation, so data should be float.
    """
    data *= cosine_taper(len(data), 0.2)
    return data
Пример #10
0
 def test_cosine_taper(self):
     # SAC trace was generated with:
     # taper type cosine width 0.05
     for i in [99, 100]:
         sac_taper = os.path.join(self.path,
                                  'ones_trace_%d_tapered.sac' % i)
         tr = read(sac_taper)[0]
         tap = cosine_taper(i, p=0.1, halfcosine=False, sactaper=True)
         np.testing.assert_array_almost_equal(tap, tr.data, decimal=6)
Пример #11
0
 def __call__(self, tr):
     try:
         if tr.stats.npts > 1:
             tr.data *= cosine_taper(tr.stats.npts, 0.01)
             FFT = fft(tr.data)
             tr.data = ifft(FFT / abs(FFT)).real
     except ValueError:
         print "ERROR"
         print tr.stats.npts
     return tr
Пример #12
0
def get_ph_misfit(period,freqmin,freqmax,stacode1,stacode2,vel,indir='/work3/wang/JdF/Denoised_Stack'):
	""" Calculate phase misfit between the positive and negative lags of a given cross-correlogram
	
	"""
	xcorr_file = indir+'/'+stacode1+'/'+'COR_'+stacode1+'_'+stacode2+'.SAC'
	if not os.path.isfile(xcorr_file): return 9999.9;
	tr = obspy.core.read(xcorr_file)[0]
	npts = tr.stats.sac.npts
	delta = tr.stats.sac.delta
	dist = tr.stats.sac.dist
	L = int((npts-1)/2)+1
	arrival = dist/vel
	data_neg = tr.data[:L]
	data_neg = data_neg[::-1]
	data_pos = tr.data[L-1:]
	#butter_b, butter_a = scipy.signal.butter(4,[freqmin*2*delta,freqmax*2*delta],btype='band')
	#data_pos = scipy.signal.lfilter(butter_b,butter_a,data_pos)
	#data_neg = scipy.signal.lfilter(butter_b,butter_a,data_neg)
	ind0 = max(0, int((arrival-1*period)/delta))
	ind1 = min(L, int((arrival+1*period)/delta))
	window_length = ind1 - ind0
	taper = cosine_taper(window_length,0.85)
	ccp = data_pos[ind0:ind1]
	ccp = scipy.signal.detrend(ccp, type='linear')
	ccp *= taper
	ccn = data_neg[ind0:ind1]
	ccn = scipy.signal.detrend(ccn, type='linear')
	ccn *= taper
	ns = 1<<(ind1-ind0).bit_length()
	fpos = scipy.fftpack.fft(ccp, n=ns)[:ns // 2]
	fneg = scipy.fftpack.fft(ccn, n=ns)[:ns // 2]
	fpos2 = np.real(fpos) ** 2 + np.imag(fpos) ** 2
	fneg2 = np.real(fneg) ** 2 + np.imag(fneg) ** 2
	X = fpos*(fneg.conj())
	dpos = np.sqrt(fpos2)
	dneg = np.sqrt(fneg2)
	dcs = np.abs(X)
	freq_vec = scipy.fftpack.fftfreq(len(X)*2, delta)[:ns // 2]
	index_range = np.argwhere(np.logical_and(freq_vec>=freqmin, freq_vec<=freqmax))
	n = len(dcs)
	coh = np.zeros(n).astype('complex')
	valids = np.argwhere(np.logical_and(np.abs(dpos)>0,np.abs(dneg)>0))
	coh[valids] = dcs[valids] / (dpos[valids] * dneg[valids])
	coh[coh > (1.+0j)] = 1.0+0j
	w = 1./(1./(coh[index_range] ** 2)-1.)
	w[coh[index_range] >= 0.99] = 1./ (1./0.9801 - 1.)
	w = np.sqrt(w*np.sqrt(dcs[index_range]))
	w = np.real(w)
	v = np.real(freq_vec[index_range])*2*np.pi
	phi = np.angle(X)
	phi[0] = 0.
	phi = np.unwrap(phi)
	phi = phi[index_range]
	m,_ = linear_regression(v.flatten(),phi.flatten(),w.flatten())
	return m
Пример #13
0
    def spectrum_from_parameters(self, freq, parameters):

        mu = parameters['mean_frequency_Hz']
        sig = parameters['standard_deviation_Hz']
        taper = cosine_taper(len(freq), parameters['taper_percent'] / 100.)
        spec = taper * np.exp(-((freq - mu)**2) / (2 * sig**2))

        if not parameters['normalize_spectrum_to_unity']:
            spec = spec / (sig * sqrt(2. * pi))

        return (spec)
Пример #14
0
def run_kern(args, comm, size, rank):

    args.steplengthrun = False  # by default
    all_conf = config_params(args, comm, size, rank)

    kernel_tasks, n_p_p, n_p = define_kernel_tasks(all_conf, comm, size, rank)
    if len(kernel_tasks) == 0:
        return ()
    if all_conf.config['verbose']:
        print('Rank number %g' % rank)
        print('working on pair nr. %g to %g of %g.' %
              (rank * n_p_p, rank * n_p_p + n_p_p, n_p))

    # Current model for the noise source
    nsrc = os.path.join(all_conf.source_config['project_path'],
                        all_conf.source_config['source_name'],
                        'spectral_model.h5')

    # Smart numbers
    all_ns = get_ns(all_conf)  # ntime, n, n_corr, Fs

    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off wherever the solver stopped running.
    taper = cosine_taper(all_ns[0], p=0.01)
    taper[0:all_ns[0] // 2] = 1.0

    with NoiseSource(nsrc) as nsrc:
        for kp in kernel_tasks:
            try:
                input_files = add_input_files(kp, all_conf)
                output_file = add_output_file(kp, all_conf)
            except (IOError, IndexError):
                if all_conf.config['verbose']:
                    print('Could not find input for: %s\
\nCheck if wavefield .h5 file and base_model file are available.' % kp)
                continue

            kern = compute_kernel(input_files, all_conf, nsrc, all_ns, taper)
            if kern is None:
                continue

            for ix_f in range(all_conf.filtcnt):
                if kern[:, ix_f, :, :].sum() != 0:
                    filename = output_file + '.{}.npy'.format(ix_f)
                    np.save(filename, kern[:, ix_f, :, :])
    return ()
Пример #15
0
    def filter(self):
        """ Filter data for each band.
    """
        n_bands = self._N_bands()
        LEN = self.tr.stats.npts
        df = self.tr.stats.sampling_rate

        # create zeros 2D array for BF
        BF = np.zeros(shape=(n_bands, LEN))

        for j in range(n_bands):
            octave_high = (self.freqmin + self.freqmin * 2.0) / 2.0 * (2 ** j)
            octave_low = octave_high / 2.0
            BF[j] = bandpass(self.tr.data, octave_low, octave_high, df, corners=self.cnr, zerophase=False)
            BF[j] = cosine_taper(LEN, self.perc_taper) * BF[j]

        return BF
Пример #16
0
def source(t,sourcetype='random'):
    """
    returns the frequency domain representation of the source time function.
    It is possible to introduce also other types of source, for example a
    wavelet.
    """
    n = len(t)
#    damp=0.05
    if sourcetype=='random':
        signal = (np.random.rand(n)-0.5)  
    #    signal*= t**0.3*exp(-damp*t)
        signal*= cosine_taper(len(signal),0.01)
    elif sourcetype=='spike':
        signal = np.zeros(len(t))
        signal[0] = 1.
    else:
        raise Exception("Did not understand the source type. Choose either 'random' or 'spike'.")
    return np.fft.rfft(signal)
Пример #17
0
def test_stretching_vect():
    t = np.linspace(0., 9.95, 2500)  # 0.5 % perturbation
    original_signal = np.sin(t * 10.) * cosine_taper(2500, p=0.75)

    t_stretch = np.linspace(0., 10.0, 2500)
    stretched_signal = np.interp(t, t_stretch, original_signal)


    para = {}
    para["dt"] = 1. / 250.
    para["twin"] = [0., 10.]
    para["freq"] = [9.9, 10.1]

    dvv,  error, cc, cdp = stretching_vect(ref=original_signal, cur=stretched_signal,
                                      dv_range=0.05, nbtrial=100, para=para)

    assert pytest.approx(cc) == 1.0
    assert dvv + 0.5 < para["dt"] # assert result is -0.5%
Пример #18
0
def run_corr(args, comm, size, rank):

    all_conf = config_params(args, comm, size, rank)
    # Distributing the tasks
    correlation_tasks, n_p_p, n_p = define_correlation_tasks(
        all_conf, comm, size, rank)
    if len(correlation_tasks) == 0:
        return ()
    if all_conf.config['verbose']:
        print('Rank number %g' % rank)
        print('working on pair nr. %g to %g of %g.' %
              (rank * n_p_p, rank * n_p_p + n_p_p, n_p))

    # Current model for the noise source
    nsrc = os.path.join(all_conf.source_config['project_path'],
                        all_conf.source_config['source_name'],
                        'iteration_' + str(all_conf.step), 'starting_model.h5')

    # Smart numbers
    all_ns = get_ns(all_conf)  # ntime, n, n_corr, Fs

    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off wherever the solver stopped running.
    taper = cosine_taper(all_ns[0], p=0.01)
    taper[0:all_ns[0] // 2] = 1.0

    with NoiseSource(nsrc) as nsrc:
        for cp in correlation_tasks:
            try:
                input_files = add_input_files(cp, all_conf)

                output_file = add_output_file(cp, all_conf)
            except (IndexError, FileNotFoundError):
                if all_conf.config['verbose']:
                    print('Could not determine correlation for: %s\
    \nCheck if wavefield .h5 file is available.' % cp)
                continue

            correlation, sta1, sta2 = compute_correlation(
                input_files, all_conf, nsrc, all_ns, taper)
            add_metadata_and_write(correlation, sta1, sta2, output_file,
                                   all_ns[3])

    return ()
Пример #19
0
def stream2mult_array(str,wlen,overlap):
    """ turn obspy stream into array of short 2D arrays

    the data from a stream is extracted, sliced, and copied to 2D numpy arrays
     - ** parameters**, **types**, **return**, and **return types**::
         :param str: stream to be converted
        :param wlen: length of short arrays
        :param overlap: length of overlap between short arrays

        :type str: obspy stream
        :type wlen: length of windows in seconds
        :type overlap: length of overlap in seconds

        :return: 2D array with time series for all channels
        :rtype: numpy array

        :return: array of times of the beginning of the windows
        :rtype: list of UTCDateTime

        :return: array of window lengths
        :rtype: list of seconds
    """
    arr=stream2array(str)
    sps=str[0].stats.sampling_rate
    npts=str[0].stats.npts
    timeI=str[0].stats.starttime
    wlen_sam=sps*wlen
    overlap_sam=sps*overlap
    curr=0
    mat=[]
    time=[]
    lenA=[]
    try:
        cosVal=inv.cosTaper(int(wlen_sam),p=0.1)
    except:
        cosVal=inv.cosine_taper(int(wlen_sam),p=0.1)
    while curr+wlen_sam<=npts:
        mat.append(arr[:,int(curr):int(curr+wlen_sam)]*cosVal)
        time.append(UTCDateTime(float(timeI)+float(curr)/sps))
        lenA.append(len(arr[0,int(curr):int(curr+wlen_sam)]))
        curr=curr+wlen_sam-overlap_sam
    mat=np.asarray(mat)
    return mat,time,lenA
Пример #20
0
def spect_norm(x):
    """ Computes the spectral normalization of  1D numpy array x

    This function divides the amplitude of the x spectrum by its absolute value

    :type x: :class:`~numpy.ndarray`
    :param x: 1d array

    :rtype: :class:`~numpy.ndarray`
    :return: **x_copy**: Whitened version of x
    """

    x_copy = x.copy()

    x_copy *= cosine_taper(len(x_copy), 0.01)

    FFT = fft(x_copy)

    x_copy = ifft(FFT / abs(FFT)).real

    return x_copy
Пример #21
0
def test_forward_model():
    class args(object):
        def __init__(self):
            self.source_model = os.path.join('test', 'testdata_v1',
                                             'testsource_v1')
            self.step = 0
            self.steplengthrun = False,
            self.ignore_network = True

    args = args()
    all_config = config_params(args, comm, size, rank)
    assert all_config.auto_corr

    ns = get_ns(all_config)
    assert (ns[0] == 3600)
    assert (ns[1] == 7200)

    p = define_correlationpairs(all_config.source_config['project_path'],
                                all_config.auto_corr)
    assert len(p) == 3
    assert p[0][0].split()[-1] == 'STA1'

    input_files = add_input_files(p[1], all_config)[0]
    assert os.path.basename(input_files[0]) == 'NET.STA1..MXZ.h5'

    nsrc = os.path.join('test', 'testdata_v1', 'testsource_v1', 'iteration_0',
                        'starting_model.h5')
    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off wherever the solver stopped running.
    taper = cosine_taper(ns[0], p=0.01)
    taper[0:ns[0] // 2] = 1.0
    correlation, sta1, sta2 = compute_correlation(input_files, all_config,
                                                  NoiseSource(nsrc), ns, taper)
    corr_saved = np.load(
        os.path.join('test', 'testdata_v1', 'testdata',
                     'NET.STA1..MXZ--NET.STA2..MXZ.npy'))

    assert np.allclose(correlation, corr_saved)
Пример #22
0
def calc_fourier_window(stream, offset=0, taper = None, taper_param = 4, raw=False, prewhiten = False):
    spoint = np.zeros(len(stream))
    nsamp = len(stream[0])
    nfft = next_pow_2(nsamp)
    nlow = 1
    nhigh = nfft // 2 - 1
    nf = nhigh - nlow + 1  # include upper and lower frequency
    freqList = np.arange(nlow, nlow+nf)/(nfft * stream[0].stats.delta)
    if (taper is None) or (taper.lower() == 'tukey'):
        taper = cosine_taper(nsamp, p=0.22)
    ft = np.empty((len(stream), nf), dtype=np.complex128)
    for i, tr in enumerate(stream):
        dat = tr.data[int(spoint[i] + offset):int(spoint[i] + offset + nsamp)]
        if (type(taper) is str) and (taper.lower() == 'multitaper'):
            ft[i, :] = mtspec(dat, stream[0].stats.delta, time_bandwidth = taper_param, nfft=nfft)[nlow:nlow + nf]
        else:
            if not raw:
                dat = scipy.signal.detrend(dat) * taper
            ft[i, :] = np.fft.rfft(dat, nfft)[nlow:nlow + nf]
    ft *= np.sqrt(2*stream[0].stats.delta / nsamp) # one-sided spectrum with physical amplitude units
    if prewhiten:
        eps = np.min(np.abs(ft)[ft != 0])
        ft /= np.abs(ft) + eps # apply a tiny waterlevel to avoid divide-by-zero
    return ft, freqList
Пример #23
0
def mwcs(current,
         reference,
         freqmin,
         freqmax,
         df,
         tmin,
         window_length,
         step,
         smoothing_half_win=5):
    """The `current` time series is compared to the `reference`.
Both time series are sliced in several overlapping windows.
Each slice is mean-adjusted and cosine-tapered (85% taper) before being Fourier-
transformed to the frequency domain.
:math:`F_{cur}(\\nu)` and :math:`F_{ref}(\\nu)` are the first halves of the
Hermitian symmetric Fourier-transformed segments. The cross-spectrum
:math:`X(\\nu)` is defined as
:math:`X(\\nu) = F_{ref}(\\nu) F_{cur}^*(\\nu)`

in which :math:`{}^*` denotes the complex conjugation.
:math:`X(\\nu)` is then smoothed by convolution with a Hanning window.
The similarity of the two time-series is assessed using the cross-coherency
between energy densities in the frequency domain:

:math:`C(\\nu) = \\frac{|\overline{X(\\nu))}|}{\sqrt{|\overline{F_{ref}(\\nu)|^2} |\overline{F_{cur}(\\nu)|^2}}}`


in which the over-line here represents the smoothing of the energy spectra for
:math:`F_{ref}` and :math:`F_{cur}` and of the spectrum of :math:`X`. The mean
coherence for the segment is defined as the mean of :math:`C(\\nu)` in the
frequency range of interest. The time-delay between the two cross correlations
is found in the unwrapped phase, :math:`\phi(\nu)`, of the cross spectrum and is
linearly proportional to frequency:

:math:`\phi_j = m. \nu_j, m = 2 \pi \delta t`

The time shift for each window between two signals is the slope :math:`m` of a
weighted linear regression of the samples within the frequency band of interest.
The weights are those introduced by [Clarke2011]_,
which incorporate both the cross-spectral amplitude and cross-coherence, unlike
[Poupinet1984]_. The errors are estimated using the weights (thus the
coherence) and the squared misfit to the modelled slope:

:math:`e_m = \sqrt{\sum_j{(\\frac{w_j \\nu_j}{\sum_i{w_i \\nu_i^2}})^2}\sigma_{\phi}^2}`

where :math:`w` are weights, :math:`\\nu` are cross-coherences and
:math:`\sigma_{\phi}^2` is the squared misfit of the data to the modelled slope
and is calculated as :math:`\sigma_{\phi}^2 = \\frac{\sum_j(\phi_j - m \\nu_j)^2}{N-1}`

The output of this process is a table containing, for each moving window: the
central time lag, the measured delay, its error and the mean coherence of the
segment.

.. warning::

    The time series will not be filtered before computing the cross-spectrum!
    They should be band-pass filtered around the `freqmin`-`freqmax` band of
    interest beforehand.

:type current: :class:`numpy.ndarray`
:param current: The "Current" timeseries
:type reference: :class:`numpy.ndarray`
:param reference: The "Reference" timeseries
:type freqmin: float
:param freqmin: The lower frequency bound to compute the dephasing (in Hz)
:type freqmax: float
:param freqmax: The higher frequency bound to compute the dephasing (in Hz)
:type df: float
:param df: The sampling rate of the input timeseries (in Hz)
:type tmin: float
:param tmin: The leftmost time lag (used to compute the "time lags array")
:type window_length: float
:param window_length: The moving window length (in seconds)
:type step: float
:param step: The step to jump for the moving window (in seconds)
:type smoothing_half_win: int
:param smoothing_half_win: If different from 0, defines the half length of
    the smoothing hanning window.


:rtype: :class:`numpy.ndarray`
:returns: [time_axis,delta_t,delta_err,delta_mcoh]. time_axis contains the
    central times of the windows. The three other columns contain dt, error and
    mean coherence for each window.
    """
    delta_t = []
    delta_err = []
    delta_mcoh = []
    time_axis = []

    window_length_samples = np.int(window_length * df)
    # try:
    #     from scipy.fftpack.helper import next_fast_len
    # except ImportError:
    #     from obspy.signal.util import next_pow_2 as next_fast_len
    from msnoise.api import nextpow2
    padd = int(2**(nextpow2(window_length_samples) + 2))
    # padd = next_fast_len(window_length_samples)
    count = 0
    tp = cosine_taper(window_length_samples, 0.85)
    minind = 0
    maxind = window_length_samples
    while maxind <= len(current):
        cci = current[minind:(minind + window_length_samples)]
        cci = scipy.signal.detrend(cci, type='linear')
        cci *= tp

        cri = reference[minind:(minind + window_length_samples)]
        cri = scipy.signal.detrend(cri, type='linear')
        cri *= tp

        minind += int(step * df)
        maxind += int(step * df)

        fcur = scipy.fftpack.fft(cci, n=padd)[:padd // 2]
        fref = scipy.fftpack.fft(cri, n=padd)[:padd // 2]

        fcur2 = np.real(fcur)**2 + np.imag(fcur)**2
        fref2 = np.real(fref)**2 + np.imag(fref)**2

        # Calculate the cross-spectrum
        X = fref * (fcur.conj())
        if smoothing_half_win != 0:
            dcur = np.sqrt(
                smooth(fcur2, window='hanning', half_win=smoothing_half_win))
            dref = np.sqrt(
                smooth(fref2, window='hanning', half_win=smoothing_half_win))
            X = smooth(X, window='hanning', half_win=smoothing_half_win)
        else:
            dcur = np.sqrt(fcur2)
            dref = np.sqrt(fref2)

        dcs = np.abs(X)

        # Find the values the frequency range of interest
        freq_vec = scipy.fftpack.fftfreq(len(X) * 2, 1. / df)[:padd // 2]
        index_range = np.argwhere(
            np.logical_and(freq_vec >= freqmin, freq_vec <= freqmax))

        # Get Coherence and its mean value
        coh = getCoherence(dcs, dref, dcur)
        mcoh = np.mean(coh[index_range])

        # Get Weights
        w = 1.0 / (1.0 / (coh[index_range]**2) - 1.0)
        w[coh[index_range] >= 0.99] = 1.0 / (1.0 / 0.9801 - 1.0)
        w = np.sqrt(w * np.sqrt(dcs[index_range]))
        w = np.real(w)

        # Frequency array:
        v = np.real(freq_vec[index_range]) * 2 * np.pi

        # Phase:
        phi = np.angle(X)
        phi[0] = 0.
        phi = np.unwrap(phi)
        phi = phi[index_range]

        # Calculate the slope with a weighted least square linear regression
        # forced through the origin
        # weights for the WLS must be the variance !
        m, em = linear_regression(v.flatten(), phi.flatten(), w.flatten())

        delta_t.append(m)

        # print phi.shape, v.shape, w.shape
        e = np.sum((phi - m * v)**2) / (np.size(v) - 1)
        s2x2 = np.sum(v**2 * w**2)
        sx2 = np.sum(w * v**2)
        e = np.sqrt(e * s2x2 / sx2**2)

        delta_err.append(e)
        delta_mcoh.append(np.real(mcoh))
        time_axis.append(tmin + window_length / 2. + count * step)
        count += 1

        del fcur, fref
        del X
        del freq_vec
        del index_range
        del w, v, e, s2x2, sx2, m, em

    if maxind > len(current) + step * df:
        logging.warning("The last window was too small, but was computed")

    return np.array([time_axis, delta_t, delta_err, delta_mcoh]).T
Пример #24
0
def array_processing(stream,
                     win_len,
                     win_frac,
                     sll_x,
                     slm_x,
                     sll_y,
                     slm_y,
                     sl_s,
                     semb_thres,
                     vel_thres,
                     frqlow,
                     frqhigh,
                     stime,
                     etime,
                     prewhiten,
                     verbose=False,
                     coordsys='lonlat',
                     timestamp='mlabday',
                     method=0,
                     store=None):
    """
    Method for Seismic-Array-Beamforming/FK-Analysis/Capon

    :param stream: Stream object, the trace.stats dict like class must
        contain an :class:`~obspy.core.util.attribdict.AttribDict` with
        'latitude', 'longitude' (in degrees) and 'elevation' (in km), or 'x',
        'y', 'elevation' (in km) items/attributes. See param ``coordsys``.
    :type win_len: float
    :param win_len: Sliding window length in seconds
    :type win_frac: float
    :param win_frac: Fraction of sliding window to use for step
    :type sll_x: float
    :param sll_x: slowness x min (lower)
    :type slm_x: float
    :param slm_x: slowness x max
    :type sll_y: float
    :param sll_y: slowness y min (lower)
    :type slm_y: float
    :param slm_y: slowness y max
    :type sl_s: float
    :param sl_s: slowness step
    :type semb_thres: float
    :param semb_thres: Threshold for semblance
    :type vel_thres: float
    :param vel_thres: Threshold for velocity
    :type frqlow: float
    :param frqlow: lower frequency for fk/capon
    :type frqhigh: float
    :param frqhigh: higher frequency for fk/capon
    :type stime: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param stime: Start time of interest
    :type etime: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param etime: End time of interest
    :type prewhiten: int
    :param prewhiten: Do prewhitening, values: 1 or 0
    :param coordsys: valid values: 'lonlat' and 'xy', choose which stream
        attributes to use for coordinates
    :type timestamp: str
    :param timestamp: valid values: 'julsec' and 'mlabday'; 'julsec' returns
        the timestamp in seconds since 1970-01-01T00:00:00, 'mlabday'
        returns the timestamp in days (decimals represent hours, minutes
        and seconds) since '0001-01-01T00:00:00' as needed for matplotlib
        date plotting (see e.g. matplotlib's num2date)
    :type method: int
    :param method: the method to use 0 == bf, 1 == capon
    :type store: function
    :param store: A custom function which gets called on each iteration. It is
        called with the relative power map and the time offset as first and
        second arguments and the iteration number as third argument. Useful for
        storing or plotting the map for each iteration. For this purpose the
        dump function of this module can be used.
    :return: :class:`numpy.ndarray` of timestamp, relative relpow, absolute
        relpow, backazimuth, slowness
    """
    res = []
    eotr = True

    # check that sampling rates do not vary
    fs = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=fs)):
        msg = 'in sonic sampling rates of traces in stream are not equal'
        raise ValueError(msg)

    grdpts_x = int(((slm_x - sll_x) / sl_s + 0.5) + 1)
    grdpts_y = int(((slm_y - sll_y) / sl_s + 0.5) + 1)

    geometry = get_geometry(stream, coordsys=coordsys, verbose=verbose)

    if verbose:
        print("geometry:")
        print(geometry)
        print("stream contains following traces:")
        print(stream)
        print("stime = " + str(stime) + ", etime = " + str(etime))

    time_shift_table = get_timeshift(geometry, sll_x, sll_y, sl_s, grdpts_x,
                                     grdpts_y)
    # offset of arrays
    spoint, _epoint = get_spoint(stream, stime, etime)
    #
    # loop with a sliding window over the dat trace array and apply bbfk
    #
    nstat = len(stream)
    fs = stream[0].stats.sampling_rate
    nsamp = int(win_len * fs)
    nstep = int(nsamp * win_frac)

    # generate plan for rfftr
    nfft = next_pow_2(nsamp)
    deltaf = fs / float(nfft)
    nlow = int(frqlow / float(deltaf) + 0.5)
    nhigh = int(frqhigh / float(deltaf) + 0.5)
    nlow = max(1, nlow)  # avoid using the offset
    nhigh = min(nfft // 2 - 1, nhigh)  # avoid using nyquist
    nf = nhigh - nlow + 1  # include upper and lower frequency
    # to speed up the routine a bit we estimate all steering vectors in advance
    steer = np.empty((nf, grdpts_x, grdpts_y, nstat), dtype=np.complex128)
    clibsignal.calcSteer(nstat, grdpts_x, grdpts_y, nf, nlow, deltaf,
                         time_shift_table, steer)
    _r = np.empty((nf, nstat, nstat), dtype=np.complex128)
    ft = np.empty((nstat, nf), dtype=np.complex128)
    newstart = stime
    # 0.22 matches 0.2 of historical C bbfk.c
    tap = cosine_taper(nsamp, p=0.22)
    offset = 0
    relpow_map = np.empty((grdpts_x, grdpts_y), dtype=np.float64)
    abspow_map = np.empty((grdpts_x, grdpts_y), dtype=np.float64)
    while eotr:
        try:
            for i, tr in enumerate(stream):
                dat = tr.data[spoint[i] + offset:spoint[i] + offset + nsamp]
                dat = (dat - dat.mean()) * tap
                ft[i, :] = np.fft.rfft(dat, nfft)[nlow:nlow + nf]
        except IndexError:
            break
        ft = np.ascontiguousarray(ft, np.complex128)
        relpow_map.fill(0.)
        abspow_map.fill(0.)
        # computing the covariances of the signal at different receivers
        dpow = 0.
        for i in range(nstat):
            for j in range(i, nstat):
                _r[:, i, j] = ft[i, :] * ft[j, :].conj()
                if method == 1:
                    _r[:, i, j] /= np.abs(_r[:, i, j].sum())
                if i != j:
                    _r[:, j, i] = _r[:, i, j].conjugate()
                else:
                    dpow += np.abs(_r[:, i, j].sum())
        dpow *= nstat
        if method == 1:
            # P(f) = 1/(e.H R(f)^-1 e)
            for n in range(nf):
                _r[n, :, :] = np.linalg.pinv(_r[n, :, :], rcond=1e-6)

        errcode = clibsignal.generalizedBeamformer(relpow_map, abspow_map,
                                                   steer, _r, nstat, prewhiten,
                                                   grdpts_x, grdpts_y, nf,
                                                   dpow, method)
        if errcode != 0:
            msg = 'generalizedBeamforming exited with error %d'
            raise Exception(msg % errcode)
        ix, iy = np.unravel_index(relpow_map.argmax(), relpow_map.shape)
        relpow, abspow = relpow_map[ix, iy], abspow_map[ix, iy]
        if store is not None:
            store(relpow_map, abspow_map, offset)
        # here we compute baz, slow
        slow_x = sll_x + ix * sl_s
        slow_y = sll_y + iy * sl_s

        slow = np.sqrt(slow_x**2 + slow_y**2)
        if slow < 1e-8:
            slow = 1e-8
        azimut = 180 * math.atan2(slow_x, slow_y) / math.pi
        baz = azimut % -360 + 180
        if relpow > semb_thres and 1. / slow > vel_thres:
            res.append(
                np.array([newstart.timestamp, relpow, abspow, baz, slow]))
            if verbose:
                print(newstart, (newstart + (nsamp / fs)), res[-1][1:])
        if (newstart + (nsamp + nstep) / fs) > etime:
            eotr = False
        offset += nstep

        newstart += nstep / fs
    res = np.array(res)
    if timestamp == 'julsec':
        pass
    elif timestamp == 'mlabday':
        # 719163 == days between 1970 and 0001 + 1
        res[:, 0] = res[:, 0] / (24. * 3600) + 719163
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
Пример #25
0
    ext = '*.h5'
    wavefield_path = config['wavefield_path']

wfs = glob(os.path.join(wavefield_path, ext))
if wfs != []:
    print 'Found wavefield.'

with WaveField(wfs[0]) as wf:
    df = wf.stats['Fs']
    nt = wf.stats['nt']
    # The number of points for the fft is larger due to zeropadding --> apparent higher frequency sampling\n",
    n = next_fast_len(2 * nt - 1)

    freq = np.fft.rfftfreq(n, d=1. / df)

    taper = cosine_taper(len(freq), 0.01)
    print 'Determined frequency axis.'


def get_distance(grid, location):
    def f(lat, lon, location):
        return abs(gps2dist_azimuth(lat, lon, location[0], location[1])[0])

    dist = np.array(
        [f(lat, lon, location) for lat, lon in zip(grid[1], grid[0])])
    return dist


    # Use Basemap to figure out where ocean is
def get_ocean_mask():
    from mpl_toolkits.basemap import Basemap
Пример #26
0
    stats.attrs['nt'] = int(new_npts)

    # DATASET NR 2: Source grid
    sources = f_out.create_dataset('sourcegrid', data=f_sources[0:2])

    # DATASET Nr 3: Seismograms itself
    traces_h5 = f_out.create_dataset('data', (ntraces, new_npts),
                                     dtype=np.float32)

# Define processing
# half-sided tukey taper
try:
    taper = tukey(nstep, 0.1)
except NameError:
    taper = cosine_taper(nstep, 0.1)

if process_taper['only_trace_end']:
    taper[:nstep // 2] = 1.

# filter
if process_filter['type'] == 'lowpass':
    sos = lowpass(freq=process_filter['freq_max'],
                  df=Fs,
                  corners=process_filter['corners'])
elif process_filter['type'] == 'cheby2_lowpass':
    sos = cheby2_lowpass(freq=process_filter['freq_max'],
                         df=Fs,
                         maxorder=process_filter['max_order'])
elif process_filter['type'] == 'bandpass':
    sos = bandpass(freqmin=process_filter['freq_min'],
Пример #27
0
def preprocess(db, stations, comps, goal_day, params, tramef_Z, tramef_E = np.array([]), tramef_N = np.array([])):
    datafilesZ = {}
    datafilesE = {}
    datafilesN = {}

    for station in stations:
        datafilesZ[station] = []
        datafilesE[station] = []
        datafilesN[station] = []
        net, sta = station.split('.')
        gd = datetime.datetime.strptime(goal_day, '%Y-%m-%d')
        files = get_data_availability(
            db, net=net, sta=sta, starttime=gd, endtime=gd)
        for file in files:
            comp = file.comp
            fullpath = os.path.join(file.path, file.file)
            if comp[-1] == 'Z':
                datafilesZ[station].append(fullpath)
            elif comp[-1] == 'E':
                datafilesE[station].append(fullpath)
            elif comp[-1] == 'N':
                datafilesN[station].append(fullpath)

    j = 0
    for istation, station in enumerate(stations):
        for comp in comps:
            files = eval("datafiles%s['%s']" % (comp, station))
            if len(files) != 0:
                logging.debug("%s.%s Reading %i Files" %
                              (station, comp, len(files)))
                stream = Stream()
                for file in sorted(files):
                    st = read(file, dytpe=np.float,
                              starttime=UTCDateTime(gd),
                              endtime=UTCDateTime(gd)+86400)
                    for tr in st:
                        tr.data = tr.data.astype(np.float)
                    stream += st
                    del st

                logging.debug("Checking sample alignment")
                for i, trace in enumerate(stream):
                    stream[i] = check_and_phase_shift(trace)

                stream.sort()
                logging.debug("Checking Gaps")
                if len(getGaps(stream)) > 0:
                    max_gap = 10
                    only_too_long=False
                    while getGaps(stream) and not only_too_long:
                        too_long = 0
                        gaps = getGaps(stream)
                        for gap in gaps:
                            if int(gap[-1]) <= max_gap:
                                stream[gap[0]] = stream[gap[0]].__add__(stream[gap[1]], method=0, fill_value="interpolate")
                                stream.remove(stream[gap[1]])
                                break
                            else:
                                too_long += 1
                        if too_long == len(gaps):
                            only_too_long = True

                taper_length = 20.0 #seconds
                for trace in stream:
                    if trace.stats.npts < 4 * taper_length*trace.stats.sampling_rate:
                        trace.data = np.zeros(trace.stats.npts)
                    else:
                        trace.detrend(type="demean")
                        trace.detrend(type="linear")
                        taper_1s = taper_length * float(trace.stats.sampling_rate) / trace.stats.npts
                        cp = cosine_taper(trace.stats.npts, taper_1s)
                        trace.data *= cp
                try:
                    stream.merge(method=0, fill_value=0.0)
                except:
                    continue

                logging.debug("%s.%s Slicing Stream to %s:%s" % (station, comp, utcdatetime.UTCDateTime(
                    goal_day.replace('-', '')), utcdatetime.UTCDateTime(goal_day.replace('-', '')) + params.goal_duration - stream[0].stats.delta))
                stream[0].trim(utcdatetime.UTCDateTime(goal_day.replace('-', '')), utcdatetime.UTCDateTime(
                    goal_day.replace('-', '')) + params.goal_duration - stream[0].stats.delta, pad=True, fill_value=0.0,
                    nearest_sample=False)


                if get_config(db, 'remove_response', isbool=True):
                    logging.debug('Removing instrument response')
                    response_format = get_config(db, 'response_format')
                    response_prefilt = eval(get_config(db, 'response_prefilt'))
                    files = glob.glob(os.path.join(get_config(db,
                                                              'response_path'),
                                                   "*"))
                    if response_format == "inventory":
                        firstinv = True
                        inventory = None
                        for file in files:
                            try:
                                inv = read_inventory(file)
                                if firstinv:
                                    inventory = inv
                                    firstinv = False
                                else:
                                    inventory += inv
                            except:
                                traceback.print_exc()
                                pass
                        if inventory:
                            stream.attach_response(inventory)
                            stream.remove_response(output='VEL',
                                               pre_filt=response_prefilt)
                    elif response_format == "dataless":
                        for file in files:
                            p = Parser(file)
                            try:
                                p.getPAZ(stream[0].id,
                                         datetime=UTCDateTime(gd))
                                break
                            except:
                                traceback.print_exc()
                                del p
                                continue
                        stream.simulate(seedresp={'filename': p, "units":"VEL"},
                                        pre_filt=response_prefilt,
                                        paz_remove=None,
                                        paz_simulate=None,)
                    elif response_format == "paz":
                        msg = "Unexpected type for `response_format`: %s" % \
                              response_format
                        raise TypeError(msg)
                    elif response_format == "resp":
                        msg = "Unexpected type for `response_format`: %s" % \
                              response_format
                        raise TypeError(msg)
                    else:
                        msg = "Unexpected type for `response_format`: %s" % \
                              response_format
                        raise TypeError(msg)
                trace = stream[0]

                logging.debug(
                    "%s.%s Highpass at %.2f Hz" % (station, comp, params.preprocess_highpass))
                trace.filter("highpass", freq=params.preprocess_highpass, zerophase=True)
                
                if trace.stats.sampling_rate != params.goal_sampling_rate:
                    logging.debug(
                        "%s.%s Lowpass at %.2f Hz" % (station, comp, params.preprocess_lowpass))
                    trace.filter("lowpass", freq=params.preprocess_lowpass, zerophase=True)

                    

                    if params.resampling_method == "Resample":
                        logging.debug("%s.%s Downsample to %.1f Hz" %
                                      (station, comp, params.goal_sampling_rate))
                        trace.data = resample(
                            trace.data, params.goal_sampling_rate / trace.stats.sampling_rate, 'sinc_fastest')

                    elif params.resampling_method == "Decimate":
                        logging.debug("%s.%s Decimate by a factor of %i" %
                                      (station, comp, params.decimation_factor))
                        trace.data = trace.data[::params.decimation_factor]
                    trace.stats.sampling_rate = params.goal_sampling_rate

                year, month, day, hourf, minf, secf, wday, yday, isdst = trace.stats.starttime.utctimetuple()

                if j == 0:
                    t = time.strptime("%04i:%02i:%02i:%02i:%02i:%02i" %
                                      (year, month, day, hourf, minf, secf), "%Y:%m:%d:%H:%M:%S")
                    basetime = calendar.timegm(t)

                if len(trace.data) % 2 != 0:
                    trace.data = np.append(trace.data, 0.)
                if len(trace.data) != len(tramef_Z[istation]):
                    missing = len(tramef_Z[istation])- len(trace.data)
                    for i in range(missing):
                        trace.data = np.append(trace.data, 0.)
                if comp == "Z":
                    tramef_Z[istation] = trace.data
                elif comp == "E":
                    tramef_E[istation] = trace.data
                elif comp == "N":
                    tramef_N[istation] = trace.data

                del trace, stream
    if len(tramef_E) != 0:
        return basetime, tramef_Z, tramef_E, tramef_N
    else:
        return basetime, tramef_Z
Пример #28
0
def deconvolve_traces(signal, divisor, eps, freq=[], residual=False):
    """ Deconvolve a time series from a set of time series.

    The function is a wrapper for the :class:`scipy.signal.convolve`
    function.
    
    :type signal: :class:`~obspy.core.stream.Stream`
    :param signal: signal from which the divisor is to be deconvolved
    :type divisor: :class:`~obspy.core.trace.Trace`
    :param divisor: time series that is to be deconvolved from signal
    :type eps: float
    :param eps: fraction of spectral mean used as a water level to 
        avoid spectral holes in the deconvolution.
    :type freq: two element array-like
    :param freq: frequency range for the estimation of the mean power
        that is scaled with ``eps`` to obtian the water level  
    :type residual: bool
    :param residual: return residual if True, defaults to False

    :rtype: obspy.core.stream
    :return: **(dcst, rst)**: decorrelated stream and residual (only
        if ``residual=True``

    """

    
    zerotime = UTCDateTime(1971,1,1)
    # trace length is taken from signal (must be even to use real fft)
    if signal[0].stats['npts'] % 2:
        trlen = signal[0].stats['npts']+1
    else:
        trlen = signal[0].stats['npts']
    delta = divisor.stats['delta']
    
    
    # prepare divisor
    divisor.detrend(type='constant')
    taper = cosine_taper(divisor.stats['npts'],p=0.05)
    divisor.data *= taper

    divisor.trim(starttime=divisor.stats['starttime'],endtime=divisor.stats['starttime']+
                 (trlen-1)*delta,pad=True,fill_value=0,nearest_sample=False)
    # FFT divisor
    fd = np.fft.fftpack.rfft(divisor.data)
    # estimate the waterlevel to stabilize deconvolution
    if freq:
        f = np.linspace(-signal[0].stats['sampling_rate']/2., signal[0].stats['sampling_rate']/2.,len(fd))
        ind = np.nonzero(np.all([f>freq[0],f<freq[1]],axis=0))
        wl = eps * np.mean((fd*fd.conj())[ind])
    else:
        wl = eps * np.mean((fd*fd.conj()))
    
    # create the output stream
    dcst = Stream()
    rst = Stream()
    for tr in signal:
        if tr.stats['sampling_rate'] != divisor.stats['sampling_rate']:
            print "Sampling rates don't match for \n %s" % tr
            continue
        
        # prepare nuerator
        tr.detrend('constant')
        taper = cosine_taper(tr.stats['npts'])
        tr.trim(starttime=tr.stats['starttime'], endtime=tr.stats['starttime']+
                (trlen-1)*delta,pad=True,fill_value=0,nearest_sample=False)
        tr.data *= taper
        # fft numerator
        sf = np.fft.fftpack.rfft(tr.data)
        
        # calculate deconvolution
        fdc = sf*fd/(fd**2+wl)
        dc = np.fft.fftpack.irfft(fdc)

        # template to hold results
        dctr = tr.copy()
        # propagate metadata
        dctr.stats = combine_stats(tr,divisor)
        dctr.data = dc
        dctr.stats['npts'] = len(dc)
        dctr.stats['starttime'] = zerotime - (divisor.stats['starttime']-tr.stats['starttime'])
        dctr.stats_tr1 = tr.stats
        dctr.stats_tr2 = divisor.stats
        
        # append to output stream
        dcst.append(dctr)
        
        if residual:
            # residual
            rtr = dctr.copy()
            rtr.data = tr.data - np.fft.fftpack.irfft(fdc * fd)
            # append to output stream
            rst.append(rtr)
            return (dcst, rst)
        
        return dcst
Пример #29
0
def fk_freq(data, fs, rij, vmin, vmax, fmin, fmax, nvel, ntheta):
    r"""
    :math:`f`–:math:`k` beamforming with loop over frequency bands.

    Args:
        data: ``(m, n)`` array; time series with ``m`` samples from ``n``
            traces as columns
        rij: ``(d, n)`` array; ``n`` sensor coordinates as [northing, easting,
            {elevation}] column vectors in ``d`` dimensions
        fs (int or float): Sample rate [Hz]
        vmin (int or float): Min velocity in km/s, suggest 0.25
        vmax (int or float): Max velocity in km/s, suggest 0.45
        fmin (int or float): Minimum frequency in Hz
        fmax (int or float): Maximum frequency in Hz
        nvel (int or float): Number of velocity iterations, suggest 100–200
        ntheta (int or float): Number of azimuth iterations, suggest 100–200

    Returns:
        ``(ntheta, nvel)`` array; beamformed slowness map, not normalized. Can
        find max using

        .. code-block:: python

            ix, iy = np.unravel_index(bmpwr.argmax(), bmpwr.shape)
    """

    #reshape rij from standard setup
    rij = np.transpose(rij)
    rij[:, 0] = rij[:, 0] - np.mean(rij[:, 0])
    rij[:, 1] = rij[:, 1] - np.mean(rij[:, 1])

    # Getting the size of the data
    [m, nsta] = np.shape(data)

    # set up velocity/slowness and theta vectors
    sits = np.linspace(1/vmax, 1/vmin, int(nvel))
    theta = np.linspace(0, 2*np.pi, ntheta)

    # Getting initial time shifts
    # x time delay
    cost = np.cos(theta)
    Tx1 = np.outer(sits, np.transpose(cost))
    Txm = Tx1[:, :, None] * np.transpose(rij[:, 1])

    # y time delay
    sint = np.sin(theta)
    Ty1 = np.outer(sits, np.transpose(sint))
    Tym = Ty1[:, :, None] * np.transpose(rij[:, 0])

    # All possible time delays
    TT = Txm + Tym

    # Computing the next power of 2 for fft input
    n2 = ceil(np.log2(m))
    nfft = int(pow(2, n2))

    # Frequency increment
    deltaf = fs / nfft

    # Getting frequency bands
    nlow = int(fmin / float(deltaf) + 0.5)
    nhigh = int(fmax / float(deltaf) + 0.5)
    nlow = max(1, nlow)  # avoid using the offset
    nhigh = min(nfft // 2 - 1, nhigh)  # avoid using Nyquist
    nf = nhigh - nlow + 1  # include upper and lower frequency

    # Apply a 22% Cosine Taper
    taper = cosine_taper(m, p=0.22)

    # Calculated the FFT of each trace
    # ft are complex Fourier coefficients
    # is this faster in scipy?
    ft = np.empty((nsta, nf), dtype=np.complex128)
    for jj in range(nsta):
        data[:, jj] = data[:, jj] - np.mean(data[:, jj])
        dat = data[:, jj] * taper
        ft[jj, :] = np.fft.rfft(dat, nfft)[nlow:nlow + nf]

    # Change data structure for performance boost --> Check this.
    ft = np.ascontiguousarray(ft, np.complex128)

    # Pre-allocating
    freqrange = np.linspace(fmin, fmax, nf)
    pow_mapt = np.zeros((int(nvel), int(ntheta)), dtype=np.float64, order='C')
    pow_mapb = np.zeros((int(nvel), int(ntheta)), dtype=np.float64, order='C')
    flen = len(freqrange)

    # loop entire slowness map over frequencies
    # compute covariance
    for ii in range(flen):
        # Generating the exponentials - steering vectors
        freq = freqrange[ii]
        expo = -1j * 2 * np.pi * freq * TT
        Master = np.exp(expo)
        # Broadcasting the Fourier coefficients at each station
        fcoeff = ft[:, ii]
        Master = Master * fcoeff[None, None, :]
        Top = np.sum(Master, axis=2)
        Top2 = np.real(np.multiply(Top.conj(), Top))
        Bot = np.real(np.multiply(Master.conj(), Master))
        Bot = np.sum(Bot, axis=2)
        pow_mapt += Top2
        pow_mapb += Bot
    pow_map = pow_mapt/pow_mapb

    return pow_map
Пример #30
0
def polarization_analysis(stream, win_len, win_frac, frqlow, frqhigh, stime,
                          etime, verbose=False, method="pm", var_noise=0.0):
    """
    Method carrying out polarization analysis with the [Flinn1965b]_,
    [Jurkevics1988]_, ParticleMotion, or [Vidale1986]_ algorithm.

    :param stream: 3 component input data.
    :type stream: :class:`~obspy.core.stream.Stream`
    :param win_len: Sliding window length in seconds.
    :type win_len: float
    :param win_frac: Fraction of sliding window to use for step.
    :type win_frac: float
    :param var_noise: resembles a sphere of noise in PM where the 3C is
        excluded
    :type var_noise: float
    :param frqlow: lower frequency for PM
    :type frqlow: float
    :param frqhigh: higher frequency for PM
    :type frqhigh: float
    :param stime: Start time of interest
    :type stime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param etime: End time of interest
    :type etime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param method: the method to use. one of ``"pm"``, ``"flinn"`` or
        ``"vidale"``.
    :type method: str
    :rtype: dict
    :returns: Dictionary with keys ``"timestamp"`` (POSIX timestamp, can be
        used to initialize :class:`~obspy.core.utcdatetime.UTCDateTime`
        objects), ``"azimuth"``, ``"incidence"`` (incidence angle) and
        additional keys depending on used method: ``"azimuth_error"`` and
        ``"incidence_error"`` (for method ``"pm"``), ``"rectilinearity"`` and
        ``"planarity"`` (for methods ``"flinn"`` and ``"vidale"``) and
        ``"ellipticity"`` (for method ``"flinn"``). Under each key a
        :class:`~numpy.ndarray` is stored, giving the respective values
        corresponding to the ``"timestamp"`` :class:`~numpy.ndarray`.
    """
    if method.lower() not in ["pm", "flinn", "vidale"]:
        msg = "Invalid method ('%s')" % method
        raise ValueError(msg)

    res = []

    # check that sampling rates do not vary
    fs = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=fs)):
        msg = "sampling rates of traces in stream are not equal"
        raise ValueError(msg)

    if verbose:
        print("stream contains following traces:")
        print(stream)
        print("stime = " + str(stime) + ", etime = " + str(etime))

    spoint, _epoint = _get_s_point(stream, stime, etime)
    if method.lower() == "vidale":
        res = vidale_adapt(stream, var_noise, fs, frqlow, frqhigh, spoint,
                           stime, etime)
    else:
        nsamp = int(win_len * fs)
        nstep = int(nsamp * win_frac)
        newstart = stime
        tap = cosine_taper(nsamp, p=0.22)
        offset = 0
        while (newstart + (nsamp + nstep) / fs) < etime:
            try:
                data = []
                Z = []
                N = []
                E = []
                for i, tr in enumerate(stream):
                    dat = tr.data[spoint[i] + offset:
                                  spoint[i] + offset + nsamp]
                    dat = (dat - dat.mean()) * tap
                    if "Z" in tr.stats.channel:
                        Z = dat.copy()
                    if "N" in tr.stats.channel:
                        N = dat.copy()
                    if "E" in tr.stats.channel:
                        E = dat.copy()

                data.append(Z)
                data.append(N)
                data.append(E)
            except IndexError:
                break

            # we plot against the centre of the sliding window
            if method.lower() == "pm":
                azimuth, incidence, error_az, error_inc = \
                    particle_motion_odr(data, var_noise)
                res.append(np.array([newstart.timestamp + float(nstep) / fs,
                           azimuth, incidence, error_az, error_inc]))
            if method.lower() == "flinn":
                azimuth, incidence, reclin, plan = flinn(data, var_noise)
                res.append(np.array([newstart.timestamp + float(nstep) / fs,
                                    azimuth, incidence, reclin, plan]))

            if verbose:
                print(newstart, newstart + nsamp / fs, res[-1][1:])
            offset += nstep

            newstart += float(nstep) / fs

    res = np.array(res)

    result_dict = {"timestamp": res[:, 0],
                   "azimuth": res[:, 1],
                   "incidence": res[:, 2]}
    if method.lower() == "pm":
        result_dict["azimuth_error"] = res[:, 3]
        result_dict["incidence_error"] = res[:, 4]
    elif method.lower() == "vidale":
        result_dict["rectilinearity"] = res[:, 3]
        result_dict["planarity"] = res[:, 4]
        result_dict["ellipticity"] = res[:, 5]
    elif method.lower() == "flinn":
        result_dict["rectilinearity"] = res[:, 3]
        result_dict["planarity"] = res[:, 4]
    return result_dict
Пример #31
0
def polarization_analysis(stream,
                          win_len,
                          win_frac,
                          frqlow,
                          frqhigh,
                          stime,
                          etime,
                          verbose=False,
                          method="pm",
                          var_noise=0.0,
                          adaptive=True):
    """
    Method carrying out polarization analysis with the [Flinn1965b]_,
    [Jurkevics1988]_, ParticleMotion, or [Vidale1986]_ algorithm.

    :param stream: 3 component input data.
    :type stream: :class:`~obspy.core.stream.Stream`
    :param win_len: Sliding window length in seconds.
    :type win_len: float
    :param win_frac: Fraction of sliding window to use for step.
    :type win_frac: float
    :param var_noise: resembles a sphere of noise in PM where the 3C is
        excluded
    :type var_noise: float
    :param frqlow: lower frequency. Only used for ``method='vidale'``.
    :type frqlow: float
    :param frqhigh: higher frequency. Only used for ``method='vidale'``.
    :type frqhigh: float
    :param stime: Start time of interest
    :type stime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param etime: End time of interest
    :type etime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param method: the method to use. one of ``"pm"``, ``"flinn"`` or
        ``"vidale"``.
    :type method: str
    :param adaptive: switch for adaptive window estimation (defaults to
        ``True``). If set to ``False``, the window will be estimated as
        ``3 * max(1/(fhigh-flow), 1/flow)``.
    :type adaptive: bool
    :rtype: dict
    :returns: Dictionary with keys ``"timestamp"`` (POSIX timestamp, can be
        used to initialize :class:`~obspy.core.utcdatetime.UTCDateTime`
        objects), ``"azimuth"``, ``"incidence"`` (incidence angle) and
        additional keys depending on used method: ``"azimuth_error"`` and
        ``"incidence_error"`` (for method ``"pm"``), ``"rectilinearity"`` and
        ``"planarity"`` (for methods ``"flinn"`` and ``"vidale"``) and
        ``"ellipticity"`` (for method ``"flinn"``). Under each key a
        :class:`~numpy.ndarray` is stored, giving the respective values
        corresponding to the ``"timestamp"`` :class:`~numpy.ndarray`.
    """
    if method.lower() not in ["pm", "flinn", "vidale"]:
        msg = "Invalid method ('%s')" % method
        raise ValueError(msg)

    res = []

    if stream.get_gaps():
        msg = 'Input stream must not include gaps:\n' + str(stream)
        raise ValueError(msg)

    if len(stream) != 3:
        msg = 'Input stream expected to be three components:\n' + str(stream)
        raise ValueError(msg)

    # check that sampling rates do not vary
    fs = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=fs)):
        msg = "sampling rates of traces in stream are not equal"
        raise ValueError(msg)

    if verbose:
        print("stream contains following traces:")
        print(stream)
        print("stime = " + str(stime) + ", etime = " + str(etime))

    spoint, _epoint = _get_s_point(stream, stime, etime)
    if method.lower() == "vidale":
        res = vidale_adapt(stream, var_noise, fs, frqlow, frqhigh, spoint,
                           stime, etime)
    else:
        nsamp = int(win_len * fs)
        nstep = int(nsamp * win_frac)
        newstart = stime
        tap = cosine_taper(nsamp, p=0.22)
        offset = 0
        while (newstart + (nsamp + nstep) / fs) < etime:
            try:
                for i, tr in enumerate(stream):
                    dat = tr.data[spoint[i] + offset:spoint[i] + offset +
                                  nsamp]
                    dat = (dat - dat.mean()) * tap
                    if tr.stats.channel[-1].upper() == "Z":
                        z = dat.copy()
                    elif tr.stats.channel[-1].upper() == "N":
                        n = dat.copy()
                    elif tr.stats.channel[-1].upper() == "E":
                        e = dat.copy()
                    else:
                        msg = "Unexpected channel code '%s'" % tr.stats.channel
                        raise ValueError(msg)

                data = [z, n, e]
            except IndexError:
                break

            # we plot against the centre of the sliding window
            if method.lower() == "pm":
                azimuth, incidence, error_az, error_inc = \
                    particle_motion_odr(data, var_noise)
                res.append(
                    np.array([
                        newstart.timestamp + float(nstep) / fs, azimuth,
                        incidence, error_az, error_inc
                    ]))
            if method.lower() == "flinn":
                azimuth, incidence, reclin, plan = flinn(data, var_noise)
                res.append(
                    np.array([
                        newstart.timestamp + float(nstep) / fs, azimuth,
                        incidence, reclin, plan
                    ]))

            if verbose:
                print(newstart, newstart + nsamp / fs, res[-1][1:])
            offset += nstep

            newstart += float(nstep) / fs

    res = np.array(res)

    result_dict = {
        "timestamp": res[:, 0],
        "azimuth": res[:, 1],
        "incidence": res[:, 2]
    }
    if method.lower() == "pm":
        result_dict["azimuth_error"] = res[:, 3]
        result_dict["incidence_error"] = res[:, 4]
    elif method.lower() == "vidale":
        result_dict["rectilinearity"] = res[:, 3]
        result_dict["planarity"] = res[:, 4]
        result_dict["ellipticity"] = res[:, 5]
    elif method.lower() == "flinn":
        result_dict["rectilinearity"] = res[:, 3]
        result_dict["planarity"] = res[:, 4]
    return result_dict
Пример #32
0
    # evaluate (time-domain) forward and backward spectrum separately to check the data quality
    phasevel_curves = []
    for qualitycheck in ["symmetric", "forward", "backward"]:

        if qualitycheck == "forward":
            TCORR = A
        elif qualitycheck == "backward":
            TCORR = B
        else:
            TCORR = np.fft.irfft(np.real(spectrum))
        """ applying velocity filter and SNR filter"""
        if velocity_filter:
            idx_tmin = int(
                (dist / max_vel) / dt * 0.95)  # 5percent extra for taper
            idx_tmax = int((dist / min_vel) / dt * 1.05)  # 5% extra for taper
            vel_filt_window = cosine_taper(idx_tmax - idx_tmin, p=0.1)
            win_samples = int((len(spectrum) - 1) * 2)
            vel_filt = np.zeros(win_samples)
            vel_filt[idx_tmin:idx_tmax] = vel_filt_window
            vel_filt[-idx_tmax:-idx_tmin] = vel_filt_window
            #TCORR = np.fft.irfft(spectrum[:,1])#+1j*spectrum[:,2])

            if snr_filter_time_domain:
                snr_filt_td = snr_cc(
                    TCORR,
                    1. / dt,
                    dist,
                    min_vel,
                    max_vel,
                    intervals,
                    plotting=statpair) > snr_filter_threshold_td
Пример #33
0
def g1g2_kern(wf1str, wf2str, kernel, adjt, src, source_conf, insta):

    measr_conf = json.load(
        open(os.path.join(source_conf['source_path'], 'measr_config.json')))

    bandpass = measr_conf['bandpass']

    if bandpass == None:
        filtcnt = 1
    elif type(bandpass) == list:
        if type(bandpass[0]) != list:
            filtcnt = 1
        else:
            filtcnt = len(bandpass)

    ntime, n, n_corr, Fs = get_ns(wf1str, source_conf, insta)
    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off whereever the solver stopped running.
    taper = cosine_taper(ntime, p=0.01)
    taper[0:ntime // 2] = 1.0

    ########################################################################
    # Prepare filenames and adjoint sources
    ########################################################################

    filenames = []
    adjt_srcs = []
    adjt_srcs_cnt = 0

    for ix_f in range(filtcnt):

        filename = kernel + '.{}.npy'.format(ix_f)
        filenames.append(filename)
        #if os.path.exists(filename):
        #   continue

        f = Stream()
        for a in adjt:
            adjtfile = a + '*.{}.sac'.format(ix_f)
            adjtfile = glob(adjtfile)
            try:
                f += read(adjtfile[0])[0]
                f[-1].data = my_centered(f[-1].data, n_corr)
                adjt_srcs_cnt += 1
            except IndexError:
                print('No adjoint source found: {}\n'.format(a))
                break

        adjt_srcs.append(f)


########################################################################
# Compute the kernels
########################################################################

    with NoiseSource(src) as nsrc:

        ntraces = nsrc.src_loc[0].shape[0]

        if insta:
            # open database
            dbpath = json.load(
                open(os.path.join(source_conf['project_path'],
                                  'config.json')))['wavefield_path']
            # open and determine Fs, nt
            db = instaseis.open_db(dbpath)
            # get receiver locations
            lat1 = geograph_to_geocent(float(wf1[2]))
            lon1 = float(wf1[3])
            rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1)
            lat2 = geograph_to_geocent(float(wf2[2]))
            lon2 = float(wf2[3])
            rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2)

        else:
            wf1 = WaveField(wf1str)
            wf2 = WaveField(wf2str)

        kern = np.zeros((filtcnt, ntraces, len(adjt)))

        ########################################################################
        # Loop over locations
        ########################################################################
        for i in range(ntraces):

            # noise source spectrum at this location
            # For the kernel, this contains only the basis functions of the
            # spectrum without weights; might still be location-dependent,
            # for example when constraining sensivity to ocean
            S = nsrc.get_spect(i)

            if S.sum() == 0.:
                # The spectrum has 0 phase so only checking absolute value here
                continue

            ####################################################################
            # Get synthetics
            ####################################################################
            if insta:
                # get source locations
                lat_src = geograph_to_geocent(nsrc.src_loc[1, i])
                lon_src = nsrc.src_loc[0, i]
                fsrc = instaseis.ForceSource(latitude=lat_src,
                                             longitude=lon_src,
                                             f_r=1.e12)

                s1 = np.ascontiguousarray(
                    db.get_seismograms(
                        source=fsrc,
                        receiver=rec1,
                        dt=1. / source_conf['sampling_rate'])[0].data * taper)
                s2 = np.ascontiguousarray(
                    db.get_seismograms(
                        source=fsrc,
                        receiver=rec2,
                        dt=1. / source_conf['sampling_rate'])[0].data * taper)

            else:
                s1 = np.ascontiguousarray(wf1.data[i, :] * taper)
                s2 = np.ascontiguousarray(wf2.data[i, :] * taper)

            spec1 = np.fft.rfft(s1, n)
            spec2 = np.fft.rfft(s2, n)

            g1g2_tr = np.multiply(np.conjugate(spec1), spec2)
            c = np.multiply(g1g2_tr, S)

            #######################################################################
            # Get Kernel at that location
            #######################################################################
            corr_temp = my_centered(np.fft.ifftshift(np.fft.irfft(c, n)),
                                    n_corr)

            #######################################################################
            # Apply the 'adjoint source'
            #######################################################################
            for ix_f in range(filtcnt):
                f = adjt_srcs[ix_f]

                if f == None:
                    continue
                for j in range(len(f)):
                    delta = f[j].stats.delta

                    kern[ix_f, i, j] = np.dot(corr_temp, f[j].data) * delta

                    #elif measr_conf['mtype'] in ['envelope']:
                    #    if j == 0:
                    #        corr_temp_h = corr_temp
                    #        print(corr_temp_h)
                    #    if j == 1:
                    #        corr_temp_h = hilbert(corr_temp)
                    #        print(corr_temp_h)
                    #
                    #    kern[ix_f,i,j] = np.dot(corr_temp,f[j].data) * delta

            if i % 50000 == 0:
                print("Finished {} source locations.".format(i))

    if not insta:
        wf1.file.close()
        wf2.file.close()

    for ix_f in range(filtcnt):
        filename = filenames[ix_f]
        if kern[ix_f, :, :].sum() != 0:
            np.save(filename, kern[ix_f, :, :])
    return ()
Пример #34
0
def fft_taper(data):
    """
    Cosine taper, 10 percent at each end.
    """
    data *= cosine_taper(len(data), 0.2)
    return data
Пример #35
0
def main():
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s [%(levelname)s] %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

    logging.info('*** Starting: Compute CC ***')

    # Connection to the DB
    db = connect()

    if len(get_filters(db, all=False)) == 0:
        logging.info("NO FILTERS DEFINED, exiting")
        sys.exit()

    # Get Configuration
    params = Params()
    params.goal_sampling_rate = float(get_config(db, "cc_sampling_rate"))
    params.goal_duration = float(get_config(db, "analysis_duration"))
    params.overlap = float(get_config(db, "overlap"))
    params.maxlag = float(get_config(db, "maxlag"))
    params.min30 = float(get_config(db, "corr_duration")) * params.goal_sampling_rate
    params.windsorizing = float(get_config(db, "windsorizing"))
    params.resampling_method = get_config(db, "resampling_method")
    params.decimation_factor = int(get_config(db, "decimation_factor"))
    params.preprocess_lowpass = float(get_config(db, "preprocess_lowpass"))
    params.preprocess_highpass = float(get_config(db, "preprocess_highpass"))
    params.keep_all = get_config(db, 'keep_all', isbool=True)
    params.keep_days = get_config(db, 'keep_days', isbool=True)
    params.components_to_compute = get_components_to_compute(db)

    params.stack_method = get_config(db, 'stack_method')
    params.pws_timegate = float(get_config(db, 'pws_timegate'))
    params.pws_power = float(get_config(db, 'pws_power'))


    logging.info("Will compute %s" % " ".join(params.components_to_compute))

    while is_next_job(db, jobtype='CC'):
        jobs = get_next_job(db, jobtype='CC')
        stations = []
        pairs = []
        refs = []

        for job in jobs:
            refs.append(job.ref)
            pairs.append(job.pair)
            netsta1, netsta2 = job.pair.split(':')
            stations.append(netsta1)
            stations.append(netsta2)
            goal_day = job.day

        stations = np.unique(stations)

        logging.info("New CC Job: %s (%i pairs with %i stations)" %
                     (goal_day, len(pairs), len(stations)))
        jt = time.time()

        xlen = int(params.goal_duration * params.goal_sampling_rate)

        if ''.join(params.components_to_compute).count('R') > 0 or ''.join(params.components_to_compute).count('T') > 0:
            comps = ['Z', 'E', 'N']
            tramef_Z = np.zeros((len(stations), xlen))
            tramef_E = np.zeros((len(stations), xlen))
            tramef_N = np.zeros((len(stations), xlen))
            basetime, tramef_Z, tramef_E, tramef_N = preprocess(db, stations, comps, goal_day, params, tramef_Z, tramef_E, tramef_N)

        else:
            comps = ['Z']
            tramef_Z = np.zeros((len(stations), xlen))
            basetime, tramef_Z = preprocess(db, stations, comps, goal_day, params, tramef_Z)


        # print '##### STREAMS ARE ALL PREPARED AT goal Hz #####'
        dt = 1. / params.goal_sampling_rate
        # Calculate the number of slices

        slices = int(params.goal_duration * params.goal_sampling_rate / params.min30)
        begins = []
        ends = []
        i = 0
        while i <=  (params.goal_duration - params.min30/params.goal_sampling_rate):
            begins.append(int(i * params.goal_sampling_rate))
            ends.append(int(i * params.goal_sampling_rate + params.min30))
            i += int(params.min30/params.goal_sampling_rate * (1.0-params.overlap))
        slices = len(begins)

        #
        # Computing only ZZ components ? Then we can be much faster:
        #

        if False:
        #if len(params.components_to_compute) == 1 and params.components_to_compute[0] == "ZZ":
            Nfft = params.min30
            if params.min30 / 2 % 2 != 0:
                Nfft = params.min30 + 2
            cp = cosine_taper(int(params.min30), 0.04)

            logging.info("Pre-Whitening Traces")
            whitened_slices = np.zeros((len(stations), len(get_filters(db, all=False)), slices, int(Nfft)), dtype=np.complex)
            for istation, station in enumerate(stations):
                for islice, (begin, end) in enumerate(zip(begins,ends)):
                    tmp = tramef_Z[istation, begin:end]
                    rmsmat = np.std(np.abs(tmp))
                    if params.windsorizing == -1:
                        tmp = np.sign(tmp)
                    elif params.windsorizing != 0:
                        indexes = np.where(
                            np.abs(tmp) > (params.windsorizing * rmsmat))[0]
                        tmp[indexes] = (tmp[indexes] / np.abs(
                            tmp[indexes])) * params.windsorizing * rmsmat
                    tmp *= cp
                    for ifilter, filter in enumerate(get_filters(db, all=False)):
                        whitened_slices[istation, ifilter, islice,:] = whiten(tmp, Nfft, dt, float(filter.low), float(filter.high), plot=False)
                    del tmp
            del tramef_Z
            logging.info("Processing CC")
            for ifilter, filter in enumerate(get_filters(db, all=False)):
                for pair in pairs:
                    orig_pair = pair
                    if params.keep_all:
                        allcorr = {}
                    if params.keep_days:
                        daycorr = np.zeros(get_maxlag_samples(db,))
                        ndaycorr = 0
                    station1, station2 = pair.split(':')
                    pair = (np.where(stations == station1)
                            [0][0], np.where(stations == station2)[0][0])
                    for islice in range(slices):
                        tmp = np.vstack((whitened_slices[pair[0], ifilter, islice],
                                         whitened_slices[pair[1], ifilter, islice]))
                        corr = myCorr(tmp, np.ceil(params.maxlag / dt), plot=False)
                        tmptime = time.gmtime(basetime + begins[islice] /
                                                  params.goal_sampling_rate)
                        thisdate = time.strftime("%Y-%m-%d", tmptime)
                        thistime = time.strftime("%Y-%m-%d %H:%M:%S",
                                                 tmptime)
                        if not np.any(np.isnan(corr)) and not np.any(np.isinf(corr)):
                            if params.keep_all:
                                ccfid = "%s_%s_%s_%s_%s" % (station1, station2,
                                                            filter.ref, 'ZZ',
                                                            thisdate)
                                if ccfid not in allcorr:
                                    allcorr[ccfid] = {}
                                allcorr[ccfid][thistime] = corr

                            if params.keep_days:
                                daycorr += corr
                                ndaycorr += 1

                    if params.keep_all:
                        for ccfid in allcorr.keys():
                            export_allcorr(db, ccfid, allcorr[ccfid])

                    if params.keep_days:
                        thisdate = time.strftime(
                            "%Y-%m-%d", time.gmtime(basetime))
                        thistime = time.strftime(
                            "%H_%M", time.gmtime(basetime))
                        add_corr(
                            db, station1.replace(
                                '.', '_'), station2.replace('.', '_'), filter.ref,
                            thisdate, thistime, params.min30 / params.goal_sampling_rate, 'ZZ', daycorr, params.goal_sampling_rate, day=True, ncorr=ndaycorr)
                    update_job(db, goal_day, orig_pair, 'CC', 'D')
            logging.info("Job Finished. It took %.2f seconds" % (time.time() - jt))

        else:
            # ITERATING OVER PAIRS #####
            for pair in pairs:
                orig_pair = pair

                logging.info('Processing pair: %s' % pair.replace(':', ' vs '))
                tt = time.time()
                station1, station2 = pair.split(':')
                pair = (np.where(stations == station1)
                        [0][0], np.where(stations == station2)[0][0])

                s1 = get_station(db, station1.split('.')[0], station1.split('.')[1])
                s2 = get_station(db, station2.split('.')[0], station2.split('.')[1])

                if s1.X:
                    X0 = s1.X
                    Y0 = s1.Y
                    c0 = s1.coordinates

                    X1 = s2.X
                    Y1 = s2.Y
                    c1 = s2.coordinates

                    if c0 == c1:
                        coordinates = c0
                    else:
                        coordinates = 'MIX'

                    cplAz = np.deg2rad(azimuth(coordinates, X0, Y0, X1, Y1))
                    logging.debug("Azimuth=%.1f"%np.rad2deg(cplAz))
                else:
                    # logging.debug('No Coordinates found! Skipping azimuth calculation!')
                    cplAz = 0.

                for components in params.components_to_compute:
                    
                    if components == "ZZ":
                        t1 = tramef_Z[pair[0]]
                        t2 = tramef_Z[pair[1]]
                    elif components[0] == "Z":
                        t1 = tramef_Z[pair[0]]
                        t2 = tramef_E[pair[1]]
                    elif components[1] == "Z":
                        t1 = tramef_E[pair[0]]
                        t2 = tramef_Z[pair[1]]
                    else:
                        t1 = tramef_E[pair[0]]
                        t2 = tramef_E[pair[1]]
                    if np.all(t1 == 0) or np.all(t2 == 0):
                        logging.debug("%s contains empty trace(s), skipping"%components)
                        continue
                    del t1, t2
                    
                    if components[0] == "Z":
                        t1 = tramef_Z[pair[0]]
                    elif components[0] == "R":
                        if cplAz != 0:
                            t1 = tramef_N[pair[0]] * np.cos(cplAz) +\
                                 tramef_E[pair[0]] * np.sin(cplAz)
                        else:
                            t1 = tramef_E[pair[0]]

                    elif components[0] == "T":
                        if cplAz != 0:
                            t1 = tramef_N[pair[0]] * np.sin(cplAz) -\
                                 tramef_E[pair[0]] * np.cos(cplAz)
                        else:
                            t1 = tramef_N[pair[0]]

                    if components[1] == "Z":
                        t2 = tramef_Z[pair[1]]
                    elif components[1] == "R":
                        if cplAz != 0:
                            t2 = tramef_N[pair[1]] * np.cos(cplAz) +\
                                 tramef_E[pair[1]] * np.sin(cplAz)
                        else:
                            t2 = tramef_E[pair[1]]
                    elif components[1] == "T":
                        if cplAz != 0:
                            t2 = tramef_N[pair[1]] * np.sin(cplAz) -\
                                 tramef_E[pair[1]] * np.cos(cplAz)
                        else:
                            t2 = tramef_N[pair[1]]

                    trames = np.vstack((t1, t2))
                    del t1, t2

                    daycorr = {}
                    ndaycorr = {}
                    allcorr = {}
                    for filterdb in get_filters(db, all=False):
                        filterid = filterdb.ref
                        daycorr[filterid] = np.zeros(get_maxlag_samples(db,))
                        ndaycorr[filterid] = 0

                    for islice, (begin, end) in enumerate(zip(begins, ends)):
                        # print "Progress: %#2d/%2d"% (islice+1,slices)
                        trame2h = trames[:, begin:end]

                        rmsmat = np.std(trame2h, axis=1)
                        for filterdb in get_filters(db, all=False):
                            filterid = filterdb.ref
                            low = float(filterdb.low)
                            high = float(filterdb.high)
                            rms_threshold = filterdb.rms_threshold

                            Nfft = int(params.min30)
                            if params.min30 / 2 % 2 != 0:
                                Nfft = params.min30 + 2

                            trames2hWb = np.zeros((2, int(Nfft)), dtype=np.complex)
                            skip = False
                            for i, station in enumerate(pair):
                                if rmsmat[i] > rms_threshold:
                                    cp = cosine_taper(len(trame2h[i]),0.04)
                                    trame2h[i] -= trame2h[i].mean()
                                    
                                    if params.windsorizing == -1:
                                        trame2h[i] = np.sign(trame2h[i])
                                    elif params.windsorizing != 0:
                                        indexes = np.where(
                                            np.abs(trame2h[i]) > (params.windsorizing * rmsmat[i]))[0]
                                        # clipping at windsorizing*rms
                                        trame2h[i][indexes] = (trame2h[i][indexes] / np.abs(
                                            trame2h[i][indexes])) * params.windsorizing * rmsmat[i]

                                    trames2hWb[i] = whiten(
                                        trame2h[i]*cp, Nfft, dt, low, high, plot=False)
                                else:
                                    trames2hWb[i] = np.zeros(int(Nfft))
                                    skip = True
                                    logging.debug('Slice is Zeros!')
                            if not skip:
                                corr = myCorr(trames2hWb, np.ceil(params.maxlag / dt), plot=False)
                                tmptime = time.gmtime(basetime + begin /
                                                      params.goal_sampling_rate)
                                thisdate = time.strftime("%Y-%m-%d", tmptime)
                                thistime = time.strftime("%Y-%m-%d %H:%M:%S",
                                                         tmptime)
                                if params.keep_all or params.keep_days:
                                    ccfid = "%s_%s_%s_%s_%s" % (station1, station2,
                                                             filterid, components,
                                                             thisdate)
                                    if ccfid not in allcorr:
                                        allcorr[ccfid] = {}
                                    allcorr[ccfid][thistime] = corr

                                if params.keep_days:
                                    if not np.any(np.isnan(corr)) and \
                                            not np.any(np.isinf(corr)):
                                        daycorr[filterid] += corr
                                        ndaycorr[filterid] += 1

                                del corr, thistime, trames2hWb

                    if params.keep_all:
                        for ccfid in allcorr.keys():
                            export_allcorr(db, ccfid, allcorr[ccfid])

                    if params.keep_days:
                        for ccfid in allcorr.keys():
                            station1, station2, filterid, components, date = ccfid.split('_')

                            corrs = np.asarray(list(allcorr[ccfid].values()))
                            corr = stack(db, corrs)

                            thisdate = time.strftime(
                                        "%Y-%m-%d", time.gmtime(basetime))
                            thistime = time.strftime(
                                        "%H_%M", time.gmtime(basetime))
                            add_corr(
                                    db, station1.replace('.', '_'),
                                    station2.replace('.', '_'), int(filterid),
                                    thisdate, thistime,  params.min30 /
                                    params.goal_sampling_rate,
                                    components, corr,
                                    params.goal_sampling_rate, day=True,
                                    ncorr=corrs.shape[0])
                    # try:
                        #     for filterdb in get_filters(db, all=False):
                        #         filterid = filterdb.ref
                        #         corr = daycorr[filterid]
                        #         ncorr = ndaycorr[filterid]
                        #         if ncorr > 0:
                        #             logging.debug(
                        #                 "Saving daily CCF for filter %02i, comp %s (stack of %02i CCF)" % (filterid, components, ncorr))
                        #
                        #             thisdate = time.strftime(
                        #                 "%Y-%m-%d", time.gmtime(basetime))
                        #             thistime = time.strftime(
                        #                 "%H_%M", time.gmtime(basetime))
                        #             add_corr(
                        #                 db, station1.replace('.', '_'),
                        #                 station2.replace('.', '_'), filterid,
                        #                 thisdate, thistime,  params.min30 /
                        #                 params.goal_sampling_rate,
                        #                 components, corr,
                        #                 params.goal_sampling_rate, day=True,
                        #                 ncorr=ncorr)
                        #         del corr, ncorr
                        # except Exception as e:
                        #     logging.debug(str(e))
                    del trames, daycorr, ndaycorr
                logging.debug("Updating Job")
                update_job(db, goal_day, orig_pair, 'CC', 'D')

                logging.info("Finished processing this pair. It took %.2f seconds" %
                              (time.time() - tt))
            logging.info("Job Finished. It took %.2f seconds" % (time.time() - jt))
    logging.info('*** Finished: Compute CC ***')
Пример #36
0
def run_corr(args, comm, size, rank):

    all_conf = config_params(args, comm, size, rank)
    # Distributing the tasks
    correlation_tasks, n_p_p, n_p = define_correlation_tasks(all_conf,
                                                             comm, size, rank)
    if len(correlation_tasks) == 0:
        return()
    if all_conf.config['verbose']:
        print('Rank number %g' % rank)
        print('working on pair nr. %g to %g of %g.' % (rank * n_p_p,
                                                       rank * n_p_p +
                                                       n_p_p, n_p))

    # Current model for the noise source
    it_dir = os.path.join(all_conf.source_config['project_path'],
                        all_conf.source_config['source_name'],
                        'iteration_' + str(all_conf.step))
    nsrc = os.path.join(it_dir,'starting_model.h5')

    # Smart numbers
    all_ns = get_ns(all_conf)  # ntime, n, n_corr, Fs

    # use a one-sided taper: The seismogram probably has a non-zero end,
    # being cut off wherever the solver stopped running.
    taper = cosine_taper(all_ns[0], p=0.01)
    taper[0: all_ns[0] // 2] = 1.0

    with NoiseSource(nsrc) as nsrc:
        for cp in correlation_tasks:
            try:
                input_files_list = add_input_files(cp, all_conf)

                output_files = add_output_files(cp, all_conf)
            except (IndexError, FileNotFoundError):
                if all_conf.config['verbose']:
                    print('Could not determine correlation for: %s\
    \nCheck if wavefield .h5 file is available.' % cp)
                continue

            if type(input_files_list[0]) != list:
                input_files_list = [input_files_list]

            for i, input_files in enumerate(input_files_list):
                correlation, sta1, sta2 = compute_correlation(input_files,
                                                              all_conf, nsrc,
                                                              all_ns, taper)
                add_metadata_and_write(correlation, sta1, sta2,
                                       output_files[i], all_ns[3])

            if all_conf.source_config["rotate_horizontal_components"]:
                fls = glob(os.path.join(it_dir, "corr", "*{}*{}*.sac".format(cp[0].split()[1],
                                                                            cp[1].split()[1])))
                fls.sort()
                apply_rotation(fls,
                               stationlistfile=os.path.join(all_conf.source_config['project_path'],
                               "stationlist.csv"), output_directory=os.path.join(it_dir, "corr"))

    comm.barrier()
    if rank == 0:
        if all_conf.source_config["rotate_horizontal_components"]:
            fls_to_remove = glob(os.path.join(it_dir, "corr", "*MX[E,N]*MX[E,N]*.sac"))
            fls_to_remove.extend(glob(os.path.join(it_dir, "corr", "*MX[E,N]*MXZ*.sac")))
            fls_to_remove.extend(glob(os.path.join(it_dir, "corr", "*MXZ*MX[E,N]*.sac")))
            for f in fls_to_remove:
                os.system("rm " + f)


    return()
Пример #37
0
def polarization_analysis(stream, win_len, win_frac, frqlow, frqhigh, stime,
                          etime, verbose=False, timestamp="mlabday",
                          method="pm", var_noise=0.0):
    """
    Method carrying out polarization analysis with the Flinn, Jurkevics,
    ParticleMotion, or Vidale algorithm.

    :param stream: 3 component input data.
    :type stream: :class:`~obspy.core.stream.Stream`
    :param win_len: Sliding window length in seconds.
    :type win_len: float
    :param win_frac: Fraction of sliding window to use for step.
    :type win_frac: float
    :param var_noise: resembles a sphere of noise in PM where the 3C is
        excluded
    :type var_noise: float
    :param frqlow: lower frequency for PM
    :type frqlow: float
    :param frqhigh: higher frequency for PM
    :type frqhigh: float
    :param stime: Start time of interest
    :type stime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param etime: End time of interest
    :type etime: :class:`obspy.core.utcdatetime.UTCDateTime`
    :param timestamp: valid values: ``"julsec"`` and ``"mlabday"``;
        ``"julsec"`` returns the timestamp in seconds since
        ``1970-01-01T00:00:00``, ``"mlabday"`` returns the timestamp in days
        (decimals represent hours, minutes and seconds) since
        ``0001-01-01T00:00:00`` as needed for matplotlib date plotting (see
        e.g. matplotlibs num2date)
    :type timestamp: str
    :param method: the method to use. one of ``"pm"``, ``"flinn"`` or
        ``"vidale"``.
    :type method: str
    :returns: Dictionary with azimuth, incidence angle, errors,
        rectilinearity, planarity, and/or ellipticity (the returned values
        depend on the used method).
    """
    if method.lower() not in ["pm", "flinn", "vidale"]:
        msg = "Invalid method ('%s')" % method
        raise ValueError(msg)

    res = []

    # check that sampling rates do not vary
    fs = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=fs)):
        msg = "in array sampling rates of traces in stream are not equal"
        raise ValueError(msg)

    if verbose:
        print("stream contains following traces:")
        print(stream)
        print("stime = " + str(stime) + ", etime = " + str(etime))

    # offset of arrays
    spoint, _epoint = _get_s_point(stream, stime, etime)
    if method.lower() == "vidale":
        res = vidale_adapt(stream, var_noise, fs, frqlow, frqhigh, spoint,
                           stime, etime)
    else:
        nsamp = int(win_len * fs)
        nstep = int(nsamp * win_frac)
        newstart = stime
        tap = cosine_taper(nsamp, p=0.22)
        offset = 0
        while (newstart + (nsamp + nstep) / fs) < etime:
            try:
                data = []
                Z = []
                N = []
                E = []
                for i, tr in enumerate(stream):
                    dat = tr.data[spoint[i] + offset:
                                  spoint[i] + offset + nsamp]
                    dat = (dat - dat.mean()) * tap
                    if "Z" in tr.stats.channel:
                        Z = dat.copy()
                    if "N" in tr.stats.channel:
                        N = dat.copy()
                    if "E" in tr.stats.channel:
                        E = dat.copy()

                data.append(Z)
                data.append(N)
                data.append(E)
            except IndexError:
                break

            if method.lower() == "pm":
                azimuth, incidence, error_az, error_inc = \
                    particle_motion_odr(data, var_noise)
                if abs(error_az) < 0.1 and abs(error_inc) < 0.1:
                    res.append(np.array([newstart.timestamp + nsamp / fs,
                                         azimuth, incidence, error_az,
                                         error_inc]))
            if method.lower() == "flinn":
                azimuth, incidence, reclin, plan = flinn(data, var_noise)
                res.append(np.array([newstart.timestamp + nsamp / fs, azimuth,
                                     incidence, reclin, plan]))

            if verbose:
                print(newstart, newstart + nsamp / fs, res[-1][1:])
            offset += nstep

            newstart += nstep / fs
    res = np.array(res)
    # XXX: not used for any return
    if timestamp == "julsec":
        pass
    elif timestamp == "mlabday":
        # 719163 == hours between 1970 and 0001 + 1
        res[:, 0] = res[:, 0] / (24. * 3600) + 719163
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)

    npt = len(res[:, 0])
    npt //= 2

    if method.lower() == "pm":
        return {
            "azimuth": res[npt, 1],
            "incidence": res[npt, 2],
            "azimuth_error": res[npt, 3],
            "incidence_error": res[npt, 4]
        }
    elif method.lower() == "vidale":
        return {
            "azimuth": res[npt, 1],
            "incidence": res[npt, 2],
            "rectilinearity": res[npt, 3],
            "planarity": res[npt, 4],
            "ellipticity": res[npt, 5]
        }
    elif method.lower() == "flinn":
        return {
            "azimuth": res[npt, 1],
            "incidence": res[npt, 2],
            "rectilinearity": res[npt, 3],
            "planarity": res[npt, 4],
        }
    else:
        raise NotImplementedError
Пример #38
0
## add another sinusoid to signal with freq2 Hz
#dat = dat + np.sin(freq2 * 2.0 * np.pi * temp + np.pi/3)
#noise_amplitude = 0.7
## add noise to the signal
#dat = dat + np.random.randn(len(dat)) * noise_amplitude
# determine max. amplitude of data (for plotting)
maximum = max(dat)

print('Before Taper')
print('amplitude of first sample point:%6.1f' % dat[0])
print('amplitude of last sample point:%6.1f' % (dat[len(dat) - 1]))

# percentage of taper applied [0. ; 1.] (initial: 0.1)
taper_percentage = 0.1
# define taper window
taper = cosine_taper(samp, taper_percentage)
# taper the signal
dat_taper = dat * taper

print('After Taper')
print('amplitude of first sample point:%6.1f' % dat_taper[0])
print('amplitude of last sample point:%6.1f' % (dat_taper[len(dat_taper) - 1]))

# FFT data into frequency-domain
Fdat = np.fft.rfft(dat, n=samp)
Fdat_taper = np.fft.rfft(dat_taper, n=samp)
# x-axis in f-domain for plotting
xf = np.linspace(0.0, 1.0 / (2.0 * delta), (samp / 2) + 1)

# plot
plt.subplot(211)
Пример #39
0
def mwcs(ccCurrent, ccReference, fmin, fmax, sampRate, tmin, windL, step,
         plot=False):
    """...

    :type ccCurrent: :class:`numpy.ndarray`
    :param ccCurrent: The "Current" timeseries
    :type ccReference: :class:`numpy.ndarray`
    :param ccReference: The "Reference" timeseries
    :type fmin: float
    :param fmin: The lower frequency bound to compute the dephasing
    :type fmax: float
    :param fmax: The higher frequency bound to compute the dephasing
    :type sampRate: float
    :param sampRate: The sample rate of the input timeseries
    :type tmin: float
    :param tmin: The leftmost time lag (used to compute the "time lags array")
    :type windL: float
    :param windL: The moving window length
    :type step: float
    :param step: The step to jump for the moving window
    :type plot: bool
    :param plot: If True, plots the MWCS result for each window. Defaults to
        False

    :rtype: :class:`numpy.ndarray`
    :returns: [Taxis,deltaT,deltaErr,deltaMcoh]. Taxis contains the central
        times of the windows. The three other columns contain dt, error and
        mean coherence for each window.
    """

    windL = np.int(windL * sampRate)
    step = np.int(step * sampRate)
    count = 0
    deltaT = []
    deltaErr = []
    deltaMcoh = []
    Taxis = []
    padd = 2 ** (nextpow2(windL) + 2)
    padd = next_fast_len(windL)

    # Tentative checking if enough point are used to compute the FFT
    freqVec = scipy.fftpack.fftfreq(int(padd), 1. / sampRate)[:int(padd) // 2]
    indRange = np.argwhere(np.logical_and(freqVec >= fmin,
                                          freqVec <= fmax))
    if len(indRange) < 2:
        padd = 2 ** (nextpow2(windL) + 3)

    tp = cosine_taper(windL, .85)

    timeaxis = (np.arange(len(ccCurrent)) / float(sampRate)) + tmin
    minind = 0
    maxind = windL
    while maxind <= len(ccCurrent):
        ind = minind

        cci = ccCurrent[ind:(ind + windL)].copy()
        cci = scipy.signal.detrend(cci, type='linear')
        cci -= cci.min()
        cci /= cci.max()
        cci -= np.mean(cci)
        cci *= tp

        cri = ccReference[ind:(ind + windL)].copy()
        cri = scipy.signal.detrend(cri, type='linear')
        cri -= cri.min()
        cri /= cri.max()
        cri -= np.mean(cri)
        cri *= tp

        Fcur = scipy.fftpack.fft(cci, n=int(padd))[:int(padd) // 2]
        Fref = scipy.fftpack.fft(cri, n=int(padd))[:int(padd) // 2]

        Fcur2 = np.real(Fcur) ** 2 + np.imag(Fcur) ** 2
        Fref2 = np.real(Fref) ** 2 + np.imag(Fref) ** 2

        smoother = 5

        dcur = np.sqrt(smooth(Fcur2, window='hanning', half_win=smoother))
        dref = np.sqrt(smooth(Fref2, window='hanning', half_win=smoother))

        # Calculate the cross-spectrum
        X = Fref * (Fcur.conj())
        X = smooth(X, window='hanning', half_win=smoother)
        dcs = np.abs(X)

        # Find the values the frequency range of interest
        freqVec = scipy.fftpack.fftfreq(len(X) * 2, 1. / sampRate)[
                  :int(padd) // 2]
        indRange = np.argwhere(np.logical_and(freqVec >= fmin,
                                              freqVec <= fmax))

        # Get Coherence and its mean value
        coh = getCoherence(dcs, dref, dcur)
        mcoh = np.mean(coh[indRange])

        # Get Weights
        w = 1.0 / (1.0 / (coh[indRange] ** 2) - 1.0)
        w[coh[indRange] >= 0.99] = 1.0 / (1.0 / 0.9801 - 1.0)
        w = np.sqrt(w * np.sqrt(dcs[indRange]))
        # w /= (np.sum(w)/len(w)) #normalize
        w = np.real(w)

        # Frequency array:
        v = np.real(freqVec[indRange]) * 2 * np.pi
        vo = np.real(freqVec) * 2 * np.pi

        # Phase:
        phi = np.angle(X)
        phi[0] = 0.
        phi = np.unwrap(phi)
        # phio = phi.copy()
        phi = phi[indRange]

        # Calculate the slope with a weighted least square linear regression
        # forced through the origin
        # weights for the WLS must be the variance !
        res = sm.regression.linear_model.WLS(phi, v, w ** 2).fit()

        # print "forced", np.real(res.params[0])
        # print "!forced", np.real(res2.params[0])

        m = np.real(res.params[0])
        deltaT.append(m)

        # print phi.shape, v.shape, w.shape
        e = np.sum((phi - m * v) ** 2) / (np.size(v) - 1)
        s2x2 = np.sum(v ** 2 * w ** 2)
        sx2 = np.sum(w * v ** 2)
        e = np.sqrt(e * s2x2 / sx2 ** 2)
        # print w.shape
        if plot:
            plt.figure()
            plt.suptitle('%.1fs' % (timeaxis[ind + windL // 2]))
            plt.subplot(311)
            plt.plot(cci)
            plt.plot(cri)
            ax = plt.subplot(312)
            plt.plot(vo / (2 * np.pi), phio)
            plt.scatter(v / (2 * np.pi), phi, c=w, edgecolor='none',
                        vmin=0.6, vmax=1)
            plt.subplot(313, sharex=ax)
            plt.plot(v / (2 * np.pi), coh[indRange])
            plt.axhline(mcoh, c='r')
            plt.axhline(1.0, c='k', ls='--')
            plt.xlim(-0.1, 1.5)
            plt.ylim(0, 1.5)
            plt.show()

        deltaErr.append(e)
        deltaMcoh.append(np.real(mcoh))
        Taxis.append(timeaxis[ind + windL // 2])
        count += 1

        minind += step
        maxind += step
        del Fcur, Fref
        del X
        del freqVec
        del indRange
        del w, v, e, s2x2
        del res

    if maxind > len(ccCurrent) + step:
        logging.warning("The last window was too small, but was computed")

    return np.array([Taxis, deltaT, deltaErr, deltaMcoh]).T
Пример #40
0
def array_processing(stream, win_len, win_frac, sll_x, slm_x, sll_y, slm_y,
                     sl_s, semb_thres, vel_thres, frqlow, frqhigh, stime,
                     etime, prewhiten, verbose=False, coordsys='lonlat',
                     timestamp='mlabday', method=0, store=None):
    """
    Method for Seismic-Array-Beamforming/FK-Analysis/Capon

    :param stream: Stream object, the trace.stats dict like class must
        contain an :class:`~obspy.core.util.attribdict.AttribDict` with
        'latitude', 'longitude' (in degrees) and 'elevation' (in km), or 'x',
        'y', 'elevation' (in km) items/attributes. See param ``coordsys``.
    :type win_len: float
    :param win_len: Sliding window length in seconds
    :type win_frac: float
    :param win_frac: Fraction of sliding window to use for step
    :type sll_x: float
    :param sll_x: slowness x min (lower)
    :type slm_x: float
    :param slm_x: slowness x max
    :type sll_y: float
    :param sll_y: slowness y min (lower)
    :type slm_y: float
    :param slm_y: slowness y max
    :type sl_s: float
    :param sl_s: slowness step
    :type semb_thres: float
    :param semb_thres: Threshold for semblance
    :type vel_thres: float
    :param vel_thres: Threshold for velocity
    :type frqlow: float
    :param frqlow: lower frequency for fk/capon
    :type frqhigh: float
    :param frqhigh: higher frequency for fk/capon
    :type stime: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param stime: Start time of interest
    :type etime: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param etime: End time of interest
    :type prewhiten: int
    :param prewhiten: Do prewhitening, values: 1 or 0
    :param coordsys: valid values: 'lonlat' and 'xy', choose which stream
        attributes to use for coordinates
    :type timestamp: str
    :param timestamp: valid values: 'julsec' and 'mlabday'; 'julsec' returns
        the timestamp in seconds since 1970-01-01T00:00:00, 'mlabday'
        returns the timestamp in days (decimals represent hours, minutes
        and seconds) since '0001-01-01T00:00:00' as needed for matplotlib
        date plotting (see e.g. matplotlib's num2date)
    :type method: int
    :param method: the method to use 0 == bf, 1 == capon
    :type store: function
    :param store: A custom function which gets called on each iteration. It is
        called with the relative power map and the time offset as first and
        second arguments and the iteration number as third argument. Useful for
        storing or plotting the map for each iteration. For this purpose the
        dump function of this module can be used.
    :return: :class:`numpy.ndarray` of timestamp, relative relpow, absolute
        relpow, backazimuth, slowness
    """
    res = []
    eotr = True

    # check that sampling rates do not vary
    fs = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=fs)):
        msg = 'in sonic sampling rates of traces in stream are not equal'
        raise ValueError(msg)

    grdpts_x = int(((slm_x - sll_x) / sl_s + 0.5) + 1)
    grdpts_y = int(((slm_y - sll_y) / sl_s + 0.5) + 1)

    geometry = get_geometry(stream, coordsys=coordsys, verbose=verbose)

    if verbose:
        print("geometry:")
        print(geometry)
        print("stream contains following traces:")
        print(stream)
        print("stime = " + str(stime) + ", etime = " + str(etime))

    time_shift_table = get_timeshift(geometry, sll_x, sll_y,
                                     sl_s, grdpts_x, grdpts_y)
    # offset of arrays
    spoint, _epoint = get_spoint(stream, stime, etime)
    #
    # loop with a sliding window over the dat trace array and apply bbfk
    #
    nstat = len(stream)
    fs = stream[0].stats.sampling_rate
    nsamp = int(win_len * fs)
    nstep = int(nsamp * win_frac)

    # generate plan for rfftr
    nfft = next_pow_2(nsamp)
    deltaf = fs / float(nfft)
    nlow = int(frqlow / float(deltaf) + 0.5)
    nhigh = int(frqhigh / float(deltaf) + 0.5)
    nlow = max(1, nlow)  # avoid using the offset
    nhigh = min(nfft // 2 - 1, nhigh)  # avoid using nyquist
    nf = nhigh - nlow + 1  # include upper and lower frequency
    # to speed up the routine a bit we estimate all steering vectors in advance
    steer = np.empty((nf, grdpts_x, grdpts_y, nstat), dtype=np.complex128)
    clibsignal.calcSteer(nstat, grdpts_x, grdpts_y, nf, nlow,
                         deltaf, time_shift_table, steer)
    _r = np.empty((nf, nstat, nstat), dtype=np.complex128)
    ft = np.empty((nstat, nf), dtype=np.complex128)
    newstart = stime
    # 0.22 matches 0.2 of historical C bbfk.c
    tap = cosine_taper(nsamp, p=0.22)
    offset = 0
    relpow_map = np.empty((grdpts_x, grdpts_y), dtype=np.float64)
    abspow_map = np.empty((grdpts_x, grdpts_y), dtype=np.float64)
    while eotr:
        try:
            for i, tr in enumerate(stream):
                dat = tr.data[spoint[i] + offset:
                              spoint[i] + offset + nsamp]
                dat = (dat - dat.mean()) * tap
                ft[i, :] = np.fft.rfft(dat, nfft)[nlow:nlow + nf]
        except IndexError:
            break
        ft = np.ascontiguousarray(ft, np.complex128)
        relpow_map.fill(0.)
        abspow_map.fill(0.)
        # computing the covariances of the signal at different receivers
        dpow = 0.
        for i in range(nstat):
            for j in range(i, nstat):
                _r[:, i, j] = ft[i, :] * ft[j, :].conj()
                if method == 1:
                    _r[:, i, j] /= np.abs(_r[:, i, j].sum())
                if i != j:
                    _r[:, j, i] = _r[:, i, j].conjugate()
                else:
                    dpow += np.abs(_r[:, i, j].sum())
        dpow *= nstat
        if method == 1:
            # P(f) = 1/(e.H R(f)^-1 e)
            for n in range(nf):
                _r[n, :, :] = np.linalg.pinv(_r[n, :, :], rcond=1e-6)

        errcode = clibsignal.generalizedBeamformer(
            relpow_map, abspow_map, steer, _r, nstat, prewhiten,
            grdpts_x, grdpts_y, nf, dpow, method)
        if errcode != 0:
            msg = 'generalizedBeamforming exited with error %d'
            raise Exception(msg % errcode)
        ix, iy = np.unravel_index(relpow_map.argmax(), relpow_map.shape)
        relpow, abspow = relpow_map[ix, iy], abspow_map[ix, iy]
        if store is not None:
            store(relpow_map, abspow_map, offset)
        # here we compute baz, slow
        slow_x = sll_x + ix * sl_s
        slow_y = sll_y + iy * sl_s

        slow = np.sqrt(slow_x ** 2 + slow_y ** 2)
        if slow < 1e-8:
            slow = 1e-8
        azimut = 180 * math.atan2(slow_x, slow_y) / math.pi
        baz = azimut % -360 + 180
        if relpow > semb_thres and 1. / slow > vel_thres:
            res.append(np.array([newstart.timestamp, relpow, abspow, baz,
                                 slow]))
            if verbose:
                print(newstart, (newstart + (nsamp / fs)), res[-1][1:])
        if (newstart + (nsamp + nstep) / fs) > etime:
            eotr = False
        offset += nstep

        newstart += nstep / fs
    res = np.array(res)
    if timestamp == 'julsec':
        pass
    elif timestamp == 'mlabday':
        # 719163 == days between 1970 and 0001 + 1
        res[:, 0] = res[:, 0] / (24. * 3600) + 719163
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
Пример #41
0
def g1g2_kern(wf1str,wf2str,kernel,adjt,
    src,source_conf,insta):
        
    measr_conf = json.load(open(os.path.join(source_conf['source_path'],
        'measr_config.json')))


    bandpass = measr_conf['bandpass']

    if bandpass == None:
        filtcnt = 1
    elif type(bandpass) == list:
        if type(bandpass[0]) != list:
            filtcnt = 1
        else:
            filtcnt = len(bandpass)    
    
    ntime, n, n_corr, Fs = get_ns(wf1str,source_conf,insta)
    # use a one-sided taper: The seismogram probably has a non-zero end, 
    # being cut off whereever the solver stopped running.
    taper = cosine_taper(ntime,p=0.01)
    taper[0:ntime//2] = 1.0

    
########################################################################
# Prepare filenames and adjoint sources
########################################################################   

    filenames = []
    adjt_srcs = []
    adjt_srcs_cnt = 0

    for ix_f in range(filtcnt):
    
        filename = kernel+'.{}.npy'.format(ix_f)
        filenames.append(filename)
        #if os.path.exists(filename):
         #   continue

        f = Stream()
        for a in adjt:
            adjtfile = a + '*.{}.sac'.format(ix_f)
            adjtfile = glob(adjtfile)
            try:    
                f += read(adjtfile[0])[0]
                f[-1].data = my_centered(f[-1].data,n_corr)
                adjt_srcs_cnt += 1
            except IndexError:
                print('No adjoint source found: {}\n'.format(a))
                break

        adjt_srcs.append(f)
        
    

########################################################################
# Compute the kernels
######################################################################## 


    with NoiseSource(src) as nsrc:

        
        ntraces = nsrc.src_loc[0].shape[0]


        if insta:
            # open database
            dbpath = json.load(open(os.path.join(source_conf['project_path'],
                'config.json')))['wavefield_path']
            # open and determine Fs, nt
            db = instaseis.open_db(dbpath)
            # get receiver locations
            lat1 = geograph_to_geocent(float(wf1[2]))
            lon1 = float(wf1[3])
            rec1 = instaseis.Receiver(latitude=lat1,longitude=lon1)
            lat2 = geograph_to_geocent(float(wf2[2]))
            lon2 = float(wf2[3])
            rec2 = instaseis.Receiver(latitude=lat2,longitude=lon2)

        else:
            wf1 = WaveField(wf1str)
            wf2 = WaveField(wf2str)

        kern = np.zeros((filtcnt,ntraces,len(adjt)))

    

        
            
        
        ########################################################################
        # Loop over locations
        ########################################################################            
        for i in range(ntraces):

            # noise source spectrum at this location
            # For the kernel, this contains only the basis functions of the 
            # spectrum without weights; might still be location-dependent, 
            # for example when constraining sensivity to ocean
            S = nsrc.get_spect(i)
            

            if S.sum() == 0.: 
            # The spectrum has 0 phase so only checking absolute value here
                continue

            ####################################################################
            # Get synthetics
            ####################################################################                
            if insta:
            # get source locations
                lat_src = geograph_to_geocent(nsrc.src_loc[1,i])
                lon_src = nsrc.src_loc[0,i]
                fsrc = instaseis.ForceSource(latitude=lat_src,
                    longitude=lon_src,f_r=1.e12)
                
                s1 = np.ascontiguousarray(db.get_seismograms(source=fsrc,
                    receiver=rec1,
                    dt=1./source_conf['sampling_rate'])[0].data*taper)
                s2 = np.ascontiguousarray(db.get_seismograms(source=fsrc,
                    receiver=rec2,
                    dt=1./source_conf['sampling_rate'])[0].data*taper)
                

            else:
                s1 = np.ascontiguousarray(wf1.data[i,:]*taper)
                s2 = np.ascontiguousarray(wf2.data[i,:]*taper)
            
            

            spec1 = np.fft.rfft(s1,n)
            spec2 = np.fft.rfft(s2,n)
            
          
            g1g2_tr = np.multiply(np.conjugate(spec1),spec2)
            c = np.multiply(g1g2_tr,S)

        #######################################################################
        # Get Kernel at that location
        #######################################################################   
            corr_temp = my_centered(np.fft.ifftshift(np.fft.irfft(c,n)),n_corr)
            
        #######################################################################
        # Apply the 'adjoint source'
        #######################################################################
            for ix_f in range(filtcnt):
                f = adjt_srcs[ix_f]

                if f==None:
                    continue
                for j in range(len(f)):
                    delta = f[j].stats.delta
                    
                    kern[ix_f,i,j] = np.dot(corr_temp,f[j].data) * delta
                    

                    #elif measr_conf['mtype'] in ['envelope']:
                    #    if j == 0:
                    #        corr_temp_h = corr_temp
                    #        print(corr_temp_h)
                    #    if j == 1:
                    #        corr_temp_h = hilbert(corr_temp)
                    #        print(corr_temp_h)
                    #    
                    #    kern[ix_f,i,j] = np.dot(corr_temp,f[j].data) * delta
                    
           
            
            if i%50000 == 0:
                print("Finished {} source locations.".format(i))


    if not insta:
        wf1.file.close()
        wf2.file.close()

    for ix_f in range(filtcnt):
        filename = filenames[ix_f]
        if kern[ix_f,:,:].sum() != 0:
            np.save(filename,kern[ix_f,:,:]) 
    return()
Пример #42
0
def deconvolve_traces_autocorr(signal, divisor, eps, freq=[], residual=False):
    """ Deconvolve a time series from a set of time series.

    This function is imported from miic https://github.com/miic-sw/miic

    The function is a wrapper for the :class:`scipy.signal.convolve`
    function.
    
    :type signal: :class:`~obspy.core.stream.Stream`
    :param signal: signal from which the divisor is to be deconvolved
    :type divisor: :class:`~obspy.core.trace.Trace`
    :param divisor: time series that is to be deconvolved from signal
    :type eps: float
    :param eps: fraction of spectral mean used as a water level to 
        avoid spectral holes in the deconvolution.
    :type freq: two element array-like
    :param freq: frequency range for the estimation of the mean power
        that is scaled with ``eps`` to obtian the water level  
    :type residual: bool
    :param residual: return residual if True, defaults to False

    :rtype: obspy.core.stream
    :return: **(dcst, rst)**: decorrelated stream and residual (only
        if ``residual=True``

    """

    
    #zerotime = UTCDateTime(1971,1,1)
    # trace length is taken from signal (must be even to use real fft)
    if signal[0].stats['npts'] % 2:
        trlen = signal[0].stats['npts']+1
        delsamp=True
    else:
        trlen = signal[0].stats['npts']
        delsamp=False
    delta = divisor.stats['delta']
    
    
    # prepare divisor
    divisor.detrend(type='constant')

    divisor.trim(starttime=divisor.stats['starttime'],endtime=divisor.stats['starttime']+
                 (trlen-1)*delta,pad=True,fill_value=0,nearest_sample=False)
    # FFT divisor
    fd = np.fft.rfft(divisor.data)
    # estimate the waterlevel to stabilize deconvolution
    if freq:
        f = np.linspace(-signal[0].stats['sampling_rate']/2., signal[0].stats['sampling_rate']/2.,len(fd))
        ind = np.nonzero(np.all([f>freq[0],f<freq[1]],axis=0))
        wl = eps * np.mean((fd*fd.conj())[ind])
    else:
        wl = eps * np.mean((fd*fd.conj()))
    
    # create the output stream
    dcst = Stream()
    rst = Stream()
    for tr in signal:
        if tr.stats['sampling_rate'] != divisor.stats['sampling_rate']:
            print("Sampling rates don't match for \n %s") % tr
            continue
        
        # prepare nuerator
        tr.detrend('constant')
        tr.trim(starttime=tr.stats['starttime'], endtime=tr.stats['starttime']+
                (trlen-1)*delta,pad=True,fill_value=0,nearest_sample=False)
        taper = cosine_taper(tr.stats['npts'])
        tr.data *= taper
        # fft numerator
        sf = np.fft.rfft(tr.data)
        
        # calculate deconvolution
        fdc = sf*fd/(fd**2+wl)
        dc = np.fft.irfft(fdc)

        # template to hold results
        dctr = tr.copy()
        # propagate metadata
        dctr.stats = tr.stats#combine_stats(tr,divisor)
        if delsamp:
            dc=np.delete(dc,len(dc)-1)
        dctr.data = dc
        dctr.stats['npts'] = len(dc)
        #dctr.stats['starttime'] = tr.stats['starttime']#zerotime - (divisor.stats['starttime']-tr.stats['starttime'])
        #dctr.stats_tr1 = tr.stats
        #dctr.stats_tr2 = divisor.stats
        
        # append to output stream
        dcst.append(dctr)
        
        if residual:
            # residual
            rtr = dctr.copy()
            rtr.data = tr.data - np.fft.irfft(fdc * fd)
            # append to output stream
            rst.append(rtr)
            return (dcst, rst)
        
        return dcst
Пример #43
0
def g1g2_corr(wf1,wf2,corr_file,src,source_conf,insta):
    """
    Compute noise cross-correlations from two .h5 'wavefield' files.
    Noise source distribution and spectrum is given by starting_model.h5
    It is assumed that noise sources are delta-correlated in space.
    """
    
    
    #ToDo: check whether to include autocorrs from user (now hardcoded off)
    #ToDo: Parallel loop(s)
    #ToDo tests
    

    # Metainformation: Include the reference station names for both stations
    # from wavefield files, if possible. Do not include geographic information
    # from .csv file as this might be error-prone. Just add the geographic 
    # info later if needed.

    with NoiseSource(src) as nsrc:

        ntime, n, n_corr, Fs = get_ns(wf1,source_conf,insta)

    # use a one-sided taper: The seismogram probably has a non-zero end, 
    # being cut off whereever the solver stopped running.
        taper = cosine_taper(ntime,p=0.01)
        taper[0:ntime//2] = 1.0
        ntraces = nsrc.src_loc[0].shape[0]
        print(taper.shape)
        correlation = np.zeros(n_corr)

        if insta:
            # open database
            dbpath = json.load(open(os.path.join(source_conf['project_path'],
                'config.json')))['wavefield_path']
            # open and determine Fs, nt
            db = instaseis.open_db(dbpath)
            # get receiver locations
            lat1 = geograph_to_geocent(float(wf1[2]))
            lon1 = float(wf1[3])
            rec1 = instaseis.Receiver(latitude=lat1,longitude=lon1)
            lat2 = geograph_to_geocent(float(wf2[2]))
            lon2 = float(wf2[3])
            rec2 = instaseis.Receiver(latitude=lat2,longitude=lon2)

        else:
            wf1 = WaveField(wf1)
            wf2 = WaveField(wf2)

            
        # Loop over source locations
        for i in range(ntraces):

            # noise source spectrum at this location
            S = nsrc.get_spect(i)
            

            if S.sum() == 0.: 
            #If amplitude is 0, continue. (Spectrum has 0 phase anyway. )
                continue

           
            if insta:
            # get source locations
                lat_src = geograph_to_geocent(nsrc.src_loc[1,i])
                lon_src = nsrc.src_loc[0,i]
                fsrc = instaseis.ForceSource(latitude=lat_src,
                    longitude=lon_src,f_r=1.e12)
                
                s1 = np.ascontiguousarray(db.get_seismograms(source=fsrc,
                    receiver=rec1,
                    dt=1./source_conf['sampling_rate'])[0].data*taper)
                s2 = np.ascontiguousarray(db.get_seismograms(source=fsrc,
                    receiver=rec2,
                    dt=1./source_conf['sampling_rate'])[0].data*taper)
                

            else:
            # read Green's functions
                s1 = np.ascontiguousarray(wf1.data[i,:]*taper)
                s2 = np.ascontiguousarray(wf2.data[i,:]*taper)
            
            
            # Fourier transform for greater ease of convolution
            spec1 = np.fft.rfft(s1,n)
            spec2 = np.fft.rfft(s2,n)
            
            # convolve G1G2
            g1g2_tr = np.multiply(np.conjugate(spec1),spec2)
            
            # convolve noise source
            c = np.multiply(g1g2_tr,S)
            
            # transform back    
            correlation += my_centered(np.fft.ifftshift(np.fft.irfft(c,n)),
                n_corr) * nsrc.surf_area[i]
            
            # occasional info
            if i%50000 == 0:
                print("Finished {} source locations.".format(i))
###################### end of loop over all source locations ###################

        if not insta:
            wf1.file.close()
            wf2.file.close()

        # save output
        trace = Trace()
        trace.stats.sampling_rate = Fs
        trace.data = correlation
# try to add some meta data
        try:
            sta1 = wf1.stats['reference_station']
            sta2 = wf2.stats['reference_station']
            trace.stats.station = sta1.split('.')[1]
            trace.stats.network = sta1.split('.')[0]
            trace.stats.location = sta1.split('.')[2]
            trace.stats.channel = sta1.split('.')[3]
            trace.stats.sac = {}
            trace.stats.sac['kuser0']  =   sta2.split('.')[1]
            trace.stats.sac['kuser1']  =   sta2.split('.')[0]
            trace.stats.sac['kuser2']  =  sta2.split('.')[2]
            trace.stats.sac['kevnm']   =   sta2.split('.')[3]
        except:
            pass

        trace.write(filename=corr_file,format='SAC')
Пример #44
0
def mwcs(current, reference, freqmin, freqmax, df, tmin, window_length, step,
         smoothing_half_win=5):
    """The `current` time series is compared to the `reference`.
Both time series are sliced in several overlapping windows.
Each slice is mean-adjusted and cosine-tapered (85% taper) before being Fourier-
transformed to the frequency domain.
:math:`F_{cur}(\\nu)` and :math:`F_{ref}(\\nu)` are the first halves of the
Hermitian symmetric Fourier-transformed segments. The cross-spectrum
:math:`X(\\nu)` is defined as
:math:`X(\\nu) = F_{ref}(\\nu) F_{cur}^*(\\nu)`

in which :math:`{}^*` denotes the complex conjugation.
:math:`X(\\nu)` is then smoothed by convolution with a Hanning window.
The similarity of the two time-series is assessed using the cross-coherency
between energy densities in the frequency domain:

:math:`C(\\nu) = \\frac{|\overline{X(\\nu))}|}{\sqrt{|\overline{F_{ref}(\\nu)|^2} |\overline{F_{cur}(\\nu)|^2}}}`


in which the over-line here represents the smoothing of the energy spectra for
:math:`F_{ref}` and :math:`F_{cur}` and of the spectrum of :math:`X`. The mean
coherence for the segment is defined as the mean of :math:`C(\\nu)` in the
frequency range of interest. The time-delay between the two cross correlations
is found in the unwrapped phase, :math:`\phi(\nu)`, of the cross spectrum and is
linearly proportional to frequency:

:math:`\phi_j = m. \nu_j, m = 2 \pi \delta t`

The time shift for each window between two signals is the slope :math:`m` of a
weighted linear regression of the samples within the frequency band of interest.
The weights are those introduced by [Clarke2011]_,
which incorporate both the cross-spectral amplitude and cross-coherence, unlike
[Poupinet1984]_. The errors are estimated using the weights (thus the
coherence) and the squared misfit to the modelled slope:

:math:`e_m = \sqrt{\sum_j{(\\frac{w_j \\nu_j}{\sum_i{w_i \\nu_i^2}})^2}\sigma_{\phi}^2}`

where :math:`w` are weights, :math:`\\nu` are cross-coherences and
:math:`\sigma_{\phi}^2` is the squared misfit of the data to the modelled slope
and is calculated as :math:`\sigma_{\phi}^2 = \\frac{\sum_j(\phi_j - m \\nu_j)^2}{N-1}`

The output of this process is a table containing, for each moving window: the
central time lag, the measured delay, its error and the mean coherence of the
segment.

.. warning::

    The time series will not be filtered before computing the cross-spectrum!
    They should be band-pass filtered around the `freqmin`-`freqmax` band of
    interest beforehand.

:type current: :class:`numpy.ndarray`
:param current: The "Current" timeseries
:type reference: :class:`numpy.ndarray`
:param reference: The "Reference" timeseries
:type freqmin: float
:param freqmin: The lower frequency bound to compute the dephasing (in Hz)
:type freqmax: float
:param freqmax: The higher frequency bound to compute the dephasing (in Hz)
:type df: float
:param df: The sampling rate of the input timeseries (in Hz)
:type tmin: float
:param tmin: The leftmost time lag (used to compute the "time lags array")
:type window_length: float
:param window_length: The moving window length (in seconds)
:type step: float
:param step: The step to jump for the moving window (in seconds)
:type smoothing_half_win: int
:param smoothing_half_win: If different from 0, defines the half length of
    the smoothing hanning window.


:rtype: :class:`numpy.ndarray`
:returns: [time_axis,delta_t,delta_err,delta_mcoh]. time_axis contains the
    central times of the windows. The three other columns contain dt, error and
    mean coherence for each window.
    """
    delta_t = []
    delta_err = []
    delta_mcoh = []
    time_axis = []

    window_length_samples = np.int(window_length * df)
    # try:
    #     from scipy.fftpack.helper import next_fast_len
    # except ImportError:
    #     from obspy.signal.util import next_pow_2 as next_fast_len
    from msnoise.api import nextpow2
    padd = int(2 ** (nextpow2(window_length_samples) + 2))
    # padd = next_fast_len(window_length_samples)
    count = 0
    tp = cosine_taper(window_length_samples, 0.85)
    minind = 0
    maxind = window_length_samples
    while maxind <= len(current):
        cci = current[minind:(minind + window_length_samples)]
        cci = scipy.signal.detrend(cci, type='linear')
        cci *= tp

        cri = reference[minind:(minind + window_length_samples)]
        cri = scipy.signal.detrend(cri, type='linear')
        cri *= tp

        minind += int(step*df)
        maxind += int(step*df)

        fcur = scipy.fftpack.fft(cci, n=padd)[:padd // 2]
        fref = scipy.fftpack.fft(cri, n=padd)[:padd // 2]

        fcur2 = np.real(fcur) ** 2 + np.imag(fcur) ** 2
        fref2 = np.real(fref) ** 2 + np.imag(fref) ** 2

        # Calculate the cross-spectrum
        X = fref * (fcur.conj())
        if smoothing_half_win != 0:
            dcur = np.sqrt(smooth(fcur2, window='hanning',
                                  half_win=smoothing_half_win))
            dref = np.sqrt(smooth(fref2, window='hanning',
                                  half_win=smoothing_half_win))
            X = smooth(X, window='hanning',
                       half_win=smoothing_half_win)
        else:
            dcur = np.sqrt(fcur2)
            dref = np.sqrt(fref2)

        dcs = np.abs(X)

        # Find the values the frequency range of interest
        freq_vec = scipy.fftpack.fftfreq(len(X) * 2, 1. / df)[:padd // 2]
        index_range = np.argwhere(np.logical_and(freq_vec >= freqmin,
                                                 freq_vec <= freqmax))

        # Get Coherence and its mean value
        coh = getCoherence(dcs, dref, dcur)
        mcoh = np.mean(coh[index_range])

        # Get Weights
        w = 1.0 / (1.0 / (coh[index_range] ** 2) - 1.0)
        w[coh[index_range] >= 0.99] = 1.0 / (1.0 / 0.9801 - 1.0)
        w = np.sqrt(w * np.sqrt(dcs[index_range]))
        w = np.real(w)

        # Frequency array:
        v = np.real(freq_vec[index_range]) * 2 * np.pi

        # Phase:
        phi = np.angle(X)
        phi[0] = 0.
        phi = np.unwrap(phi)
        phi = phi[index_range]

        # Calculate the slope with a weighted least square linear regression
        # forced through the origin
        # weights for the WLS must be the variance !
        m, em = linear_regression(v.flatten(), phi.flatten(), w.flatten())

        delta_t.append(m)

        # print phi.shape, v.shape, w.shape
        e = np.sum((phi - m * v) ** 2) / (np.size(v) - 1)
        s2x2 = np.sum(v ** 2 * w ** 2)
        sx2 = np.sum(w * v ** 2)
        e = np.sqrt(e * s2x2 / sx2 ** 2)

        delta_err.append(e)
        delta_mcoh.append(np.real(mcoh))
        time_axis.append(tmin+window_length/2.+count*step)
        count += 1

        del fcur, fref
        del X
        del freq_vec
        del index_range
        del w, v, e, s2x2, sx2, m, em

    if maxind > len(current) + step*df:
        logging.warning("The last window was too small, but was computed")

    return np.array([time_axis, delta_t, delta_err, delta_mcoh]).T
Пример #45
0
        df = wf.stats['Fs']
        nt = wf.stats['nt']
        
else:
    df = float(input('Sampling rate of synthetic Greens functions in Hz?\n'))
    nt = int(input('Nr of time steps in synthetic Greens functions?\n'))





#s for the fft is larger due to zeropadding --> apparent higher frequency sampling\n",
    # n = next_fast_len(2*nt-1)
n = next_fast_len(2*nt-1)    
freq = np.fft.rfftfreq(n,d=1./df)
taper = cosine_taper(len(freq),0.01)
print('Determined frequency axis.')

def get_distance(grid,location):
    def f(lat,lon,location):
        return abs(gps2dist_azimuth(lat,lon,location[0],location[1])[0])
    dist = np.array([f(lat,lon,location) for lat,lon in zip(grid[1],grid[0])])
    return dist

# Use Basemap to figure out where ocean is
def get_ocean_mask():
    print('Getting ocean mask...')
    from mpl_toolkits.basemap import Basemap
    latmin = grd[1].min()
    latmax = grd[1].max()
    lonmin = grd[0].min()
Пример #46
0
def xcorr_pick_correction(pick1, trace1, pick2, trace2, t_before, t_after,
                          cc_maxlag, filter=None, filter_options={},
                          plot=False, filename=None):
    """
    Calculate the correction for the differential pick time determined by cross
    correlation of the waveforms in narrow windows around the pick times.
    For details on the fitting procedure refer to [Deichmann1992]_.

    The parameters depend on the epicentral distance and magnitude range. For
    small local earthquakes (Ml ~0-2, distance ~3-10 km) with consistent manual
    picks the following can be tried::

        t_before=0.05, t_after=0.2, cc_maxlag=0.10,
        filter="bandpass", filter_options={'freqmin': 1, 'freqmax': 20}

    The appropriate parameter sets can and should be determined/verified
    visually using the option `plot=True` on a representative set of picks.

    To get the corrected differential pick time calculate: ``((pick2 +
    pick2_corr) - pick1)``. To get a corrected differential travel time using
    origin times for both events calculate: ``((pick2 + pick2_corr - ot2) -
    (pick1 - ot1))``

    :type pick1: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param pick1: Time of pick for `trace1`.
    :type trace1: :class:`~obspy.core.trace.Trace`
    :param trace1: Waveform data for `pick1`. Add some time at front/back.
            The appropriate part of the trace is used automatically.
    :type pick2: :class:`~obspy.core.utcdatetime.UTCDateTime`
    :param pick2: Time of pick for `trace2`.
    :type trace2: :class:`~obspy.core.trace.Trace`
    :param trace2: Waveform data for `pick2`. Add some time at front/back.
            The appropriate part of the trace is used automatically.
    :type t_before: float
    :param t_before: Time to start cross correlation window before pick times
            in seconds.
    :type t_after: float
    :param t_after: Time to end cross correlation window after pick times in
            seconds.
    :type cc_maxlag: float
    :param cc_maxlag: Maximum lag/shift time tested during cross correlation in
        seconds.
    :type filter: str
    :param filter: `None` for no filtering or name of filter type
            as passed on to :meth:`~obspy.core.Trace.trace.filter` if filter
            should be used. To avoid artifacts in filtering provide
            sufficiently long time series for `trace1` and `trace2`.
    :type filter_options: dict
    :param filter_options: Filter options that get passed on to
            :meth:`~obspy.core.Trace.trace.filter` if filtering is used.
    :type plot: bool
    :param plot: If `True`, a plot window illustrating the alignment of the two
        traces at best cross correlation will be shown. This can and should be
        used to verify the used parameters before running automatedly on large
        data sets.
    :type filename: str
    :param filename: If plot option is selected, specifying a filename here
            (e.g. 'myplot.pdf' or 'myplot.png') will output the plot to a file
            instead of opening a plot window.
    :rtype: (float, float)
    :returns: Correction time `pick2_corr` for `pick2` pick time as a float and
            corresponding correlation coefficient.
    """
    # perform some checks on the traces
    if trace1.stats.sampling_rate != trace2.stats.sampling_rate:
        msg = "Sampling rates do not match: %s != %s" % \
            (trace1.stats.sampling_rate, trace2.stats.sampling_rate)
        raise Exception(msg)
    if trace1.id != trace2.id:
        msg = "Trace ids do not match: %s != %s" % (trace1.id, trace2.id)
        warnings.warn(msg)
    samp_rate = trace1.stats.sampling_rate
    # don't modify existing traces with filters
    if filter:
        trace1 = trace1.copy()
        trace2 = trace2.copy()
    # check data, apply filter and take correct slice of traces
    slices = []
    for _i, (t, tr) in enumerate(((pick1, trace1), (pick2, trace2))):
        start = t - t_before - (cc_maxlag / 2.0)
        end = t + t_after + (cc_maxlag / 2.0)
        duration = end - start
        # check if necessary time spans are present in data
        if tr.stats.starttime > start:
            msg = "Trace %s starts too late." % _i
            raise Exception(msg)
        if tr.stats.endtime < end:
            msg = "Trace %s ends too early." % _i
            raise Exception(msg)
        if filter and start - tr.stats.starttime < duration:
            msg = "Artifacts from signal processing possible. Trace " + \
                  "%s should have more additional data at the start." % _i
            warnings.warn(msg)
        if filter and tr.stats.endtime - end < duration:
            msg = "Artifacts from signal processing possible. Trace " + \
                  "%s should have more additional data at the end." % _i
            warnings.warn(msg)
        # apply signal processing and take correct slice of data
        if filter:
            tr.data = tr.data.astype(np.float64)
            tr.detrend(type='demean')
            tr.data *= cosine_taper(len(tr), 0.1)
            tr.filter(type=filter, **filter_options)
        slices.append(tr.slice(start, end))
    # cross correlate
    shift_len = int(cc_maxlag * samp_rate)
    cc = correlate(slices[0].data, slices[1].data, shift_len, method='direct')
    _cc_shift, cc_max = xcorr_max(cc)
    cc_curvature = np.concatenate((np.zeros(1), np.diff(cc, 2), np.zeros(1)))
    cc_convex = np.ma.masked_where(np.sign(cc_curvature) >= 0, cc)
    cc_concave = np.ma.masked_where(np.sign(cc_curvature) < 0, cc)
    # check results of cross correlation
    if cc_max < 0:
        msg = "Absolute maximum is negative: %.3f. " % cc_max + \
              "Using positive maximum: %.3f" % max(cc)
        warnings.warn(msg)
        cc_max = max(cc)
    if cc_max < 0.8:
        msg = "Maximum of cross correlation lower than 0.8: %s" % cc_max
        warnings.warn(msg)
    # make array with time shifts in seconds corresponding to cc function
    cc_t = np.linspace(-cc_maxlag, cc_maxlag, shift_len * 2 + 1)
    # take the subportion of the cross correlation around the maximum that is
    # convex and fit a parabola.
    # use vertex as subsample resolution best cc fit.
    peak_index = cc.argmax()
    first_sample = peak_index
    # XXX this could be improved..
    while first_sample > 0 and cc_curvature[first_sample - 1] <= 0:
        first_sample -= 1
    last_sample = peak_index
    while last_sample < len(cc) - 1 and cc_curvature[last_sample + 1] <= 0:
        last_sample += 1
    if first_sample == 0 or last_sample == len(cc) - 1:
        msg = "Fitting at maximum lag. Maximum lag time should be increased."
        warnings.warn(msg)
    # work on subarrays
    num_samples = last_sample - first_sample + 1
    if num_samples < 3:
        msg = "Less than 3 samples selected for fit to cross " + \
              "correlation: %s" % num_samples
        raise Exception(msg)
    if num_samples < 5:
        msg = "Less than 5 samples selected for fit to cross " + \
              "correlation: %s" % num_samples
        warnings.warn(msg)
    # quadratic fit for small subwindow
    coeffs, residual = scipy.polyfit(
        cc_t[first_sample:last_sample + 1],
        cc[first_sample:last_sample + 1], deg=2, full=True)[:2]
    # check results of fit
    if coeffs[0] >= 0:
        msg = "Fitted parabola opens upwards!"
        warnings.warn(msg)
    if residual > 0.1:
        msg = "Residual in quadratic fit to cross correlation maximum " + \
              "larger than 0.1: %s" % residual
        warnings.warn(msg)
    # X coordinate of vertex of parabola gives time shift to correct
    # differential pick time. Y coordinate gives maximum correlation
    # coefficient.
    dt = -coeffs[1] / 2.0 / coeffs[0]
    coeff = (4 * coeffs[0] * coeffs[2] - coeffs[1] ** 2) / (4 * coeffs[0])
    # this is the shift to apply on the time axis of `trace2` to align the
    # traces. Actually we do not want to shift the trace to align it but we
    # want to correct the time of `pick2` so that the traces align without
    # shifting. This is the negative of the cross correlation shift.
    dt = -dt
    pick2_corr = dt
    # plot the results if selected
    if plot is True:
        with MatplotlibBackend(filename and "AGG" or None, sloppy=True):
            import matplotlib.pyplot as plt
            fig = plt.figure()
            ax1 = fig.add_subplot(211)
            tmp_t = np.linspace(0, len(slices[0]) / samp_rate, len(slices[0]))
            ax1.plot(tmp_t, slices[0].data / float(slices[0].data.max()), "k",
                     label="Trace 1")
            ax1.plot(tmp_t, slices[1].data / float(slices[1].data.max()), "r",
                     label="Trace 2")
            ax1.plot(tmp_t - dt, slices[1].data / float(slices[1].data.max()),
                     "g", label="Trace 2 (shifted)")
            ax1.legend(loc="lower right", prop={'size': "small"})
            ax1.set_title("%s" % slices[0].id)
            ax1.set_xlabel("time [s]")
            ax1.set_ylabel("norm. amplitude")
            ax2 = fig.add_subplot(212)
            ax2.plot(cc_t, cc_convex, ls="", marker=".", color="k",
                     label="xcorr (convex)")
            ax2.plot(cc_t, cc_concave, ls="", marker=".", color="0.7",
                     label="xcorr (concave)")
            ax2.plot(cc_t[first_sample:last_sample + 1],
                     cc[first_sample:last_sample + 1], "b.",
                     label="used for fitting")
            tmp_t = np.linspace(cc_t[first_sample], cc_t[last_sample],
                                num_samples * 10)
            ax2.plot(tmp_t, scipy.polyval(coeffs, tmp_t), "b", label="fit")
            ax2.axvline(-dt, color="g", label="vertex")
            ax2.axhline(coeff, color="g")
            ax2.set_xlabel("%.2f at %.3f seconds correction" % (coeff, -dt))
            ax2.set_ylabel("correlation coefficient")
            ax2.set_ylim(-1, 1)
            ax2.set_xlim(cc_t[0], cc_t[-1])
            ax2.legend(loc="lower right", prop={'size': "x-small"})
            # plt.legend(loc="lower left")
            if filename:
                fig.savefig(filename)
            else:
                plt.show()

    return (pick2_corr, coeff)
Пример #47
0
class args(object):
    def __init__(self):
        self.source_model = os.path.join('test', 'testdata_v1',
                                         'testsource_v1')
        self.step = 0
        self.steplengthrun = False,
        self.ignore_network = True


args = args()
all_config = config_params(args, comm, size, rank)
m_a_options = {'g_speed': g_speed, 'window_params': window_params}
m_func = rm.get_measure_func(mtype)
all_ns = get_ns(all_config)
ntime, n, n_corr, Fs = all_ns
taper = cosine_taper(ntime, p=0.01)
taper[0:ntime // 2] = 1.0

with NoiseSource(source_file) as n:
    surf_area = n.surf_area

# sum the dimension that relates to filters
grad = grad.sum(axis=1)

# apply surface elements for integration
for j in range(grad.shape[0]):
    grad[j, :, 0] *= surf_area

# measurement
obs = read(obsfile)[0]
syn = read(synfile)[0]
Пример #48
0
def sleeman(stream):
    """
    Sleeman method calculating the noise of each trace of input stream.
    :type stream: Stream object from module obspy.core.stream
    :param stream: Stream containing 3 traces with the same signal recorded.
    """

    #Copy original stream
    m = stream.copy()

    #Verify stream
    if m[0].stats.sampling_rate != m[1].stats.sampling_rate \
    or m[0].stats.sampling_rate != m[2].stats.sampling_rate \
    or m[1].stats.sampling_rate != m[2].stats.sampling_rate:
        print("[pyColocSensors.sleeman]: Sampling rates are not identical \
        between traces")

    if m[0].stats.npts != m[1].stats.npts \
    or m[0].stats.npts != m[2].stats.npts \
    or m[1].stats.npts != m[2].stats.npts:
        print("[pyColocSensors.sleeman]: Traces does not have the same length")

    if m[0].stats.starttime-m[1].stats.starttime  >= m[0].stats.sampling_rate/2\
    or m[1].stats.starttime-m[2].stats.starttime  >= m[1].stats.sampling_rate/2\
    or m[0].stats.starttime-m[2].stats.starttime  >= m[0].stats.sampling_rate/2:\
        print("[pyColocSensors.sleeman]: Traces does not have the same start time")

    #Set psd and csd parameters. Set as McNamara recommands in his paper, \
    #except for windows length, staticaly fixed to 1024, to improve resolution
    #(doi: 10.1785/012003001)
    n_fft = 1024
    n_overlap = int(n_fft*0.75)
    fs = m[0].stats.sampling_rate

    #Calculate psd and csd
    (P00,f) = mlab.psd(m[0].data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    (P11,f) = mlab.psd(m[1].data,Fs=fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    (P22,f) = mlab.psd(m[2].data,Fs =fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    (P01,f) = mlab.csd(m[0].data,m[1].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    (P02,f) = mlab.csd(m[0].data,m[2].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    P10 = np.conj(P01)

    (P12,f) = mlab.csd(m[1].data,m[2].data, Fs=fs,NFFT=n_fft,noverlap=n_overlap,\
    detrend=detrend_func,window=cosine_taper(n_fft,p=0.2),scale_by_freq=True)

    P20 = np.conj(P02)

    P21 = np.conj(P12)

    #Apply corrections as McNamara recommends
    for spectra in [P00,P11,P22,P01,P02,P10,P12,P20,P21]:
        spectra = spectra*1.142857

    #Calculate electronic noises acoording to Sleeman's method
    N0 = P00-P10*P02/P12
    N1 = P11-P21*P10/P20
    N2 = P22-P02*P21/P01

    #Remove first samples (3%) in order to avoid poor resolution problems.
    #Samples remaining should be enough to cover one decade in frequency.
    N0 = N0[int(n_fft*0.03):]
    N1 = N1[int(n_fft*0.03):]
    N2 = N2[int(n_fft*0.03):]
    f = f[int(n_fft*0.03):]

    return (N0,N1,N2,f)
Пример #49
0
def remove_response2(self, inventory=None, output="VEL", water_level=60,
                    pre_filt=None, zero_mean=True, taper=True,
                    taper_fraction=0.05, plot=False, fig=None, **kwargs):
    """
    EDIT OF OBSPY'S REMOVE_RESPONSE FUNCTION
    Including titles etc.
    
    Deconvolve instrument response.

    Uses the adequate :class:`obspy.core.inventory.response.Response`
    from the provided
    :class:`obspy.core.inventory.inventory.Inventory` data. Raises an
    exception if the response is not present.

    Note that there are two ways to prevent overamplification
    while convolving the inverted instrument spectrum: One possibility is
    to specify a water level which represents a clipping of the inverse
    spectrum and limits amplification to a certain maximum cut-off value
    (`water_level` in dB). The other possibility is to taper the waveform
    data in the frequency domain prior to multiplying with the inverse
    spectrum, i.e. perform a pre-filtering in the frequency domain
    (specifying the four corner frequencies of the frequency taper as a
    tuple in `pre_filt`).

    .. note::

        Any additional kwargs will be passed on to
        :meth:`obspy.core.inventory.response.Response.get_evalresp_response`,
        see documentation of that method for further customization (e.g.
        start/stop stage).

    .. note::

        Using :meth:`~Trace.remove_response` is equivalent to using
        :meth:`~Trace.simulate` with the identical response provided as
        a (dataless) SEED or RESP file and when using the same
        `water_level` and `pre_filt` (and options `sacsim=True` and
        `pitsasim=False` which influence very minor details in detrending
        and tapering).

    .. rubric:: Example

    >>> from obspy import read, read_inventory
    >>> st = read()
    >>> tr = st[0].copy()
    >>> inv = read_inventory()
    >>> tr.remove_response(inventory=inv)  # doctest: +ELLIPSIS
    <...Trace object at 0x...>
    >>> tr.plot()  # doctest: +SKIP

    .. plot::

        from obspy import read, read_inventory
        st = read()
        tr = st[0]
        inv = read_inventory()
        tr.remove_response(inventory=inv)
        tr.plot()

    Using the `plot` option it is possible to visualize the individual
    steps during response removal in the frequency domain to check the
    chosen `pre_filt` and `water_level` options to stabilize the
    deconvolution of the inverted instrument response spectrum:

    >>> from obspy import read, read_inventory
    >>> st = read("/path/to/IU_ULN_00_LH1_2015-07-18T02.mseed")
    >>> tr = st[0]
    >>> inv = read_inventory("/path/to/IU_ULN_00_LH1.xml")
    >>> pre_filt = [0.001, 0.005, 45, 50]
    >>> tr.remove_response(inventory=inv, pre_filt=pre_filt, output="DISP",
    ...                    water_level=60, plot=True)  # doctest: +SKIP
    <...Trace object at 0x...>

    .. plot::

        from obspy import read, read_inventory
        st = read("/path/to/IU_ULN_00_LH1_2015-07-18T02.mseed", "MSEED")
        tr = st[0]
        inv = read_inventory("/path/to/IU_ULN_00_LH1.xml", "STATIONXML")
        pre_filt = [0.001, 0.005, 45, 50]
        output = "DISP"
        tr.remove_response(inventory=inv, pre_filt=pre_filt, output=output,
                           water_level=60, plot=True)

    :type inventory: :class:`~obspy.core.inventory.inventory.Inventory`
        or None.
    :param inventory: Station metadata to use in search for adequate
        response. If inventory parameter is not supplied, the response
        has to be attached to the trace with :meth:`Trace.attach_response`
        beforehand.
    :type output: str
    :param output: Output units. One of:

        ``"DISP"``
            displacement, output unit is meters
        ``"VEL"``
            velocity, output unit is meters/second
        ``"ACC"``
            acceleration, output unit is meters/second**2

    :type water_level: float
    :param water_level: Water level for deconvolution.
    :type pre_filt: list or tuple of four float
    :param pre_filt: Apply a bandpass filter in frequency domain to the
        data before deconvolution. The list or tuple defines
        the four corner frequencies `(f1, f2, f3, f4)` of a cosine taper
        which is one between `f2` and `f3` and tapers to zero for
        `f1 < f < f2` and `f3 < f < f4`.
    :type zero_mean: bool
    :param zero_mean: If `True`, the mean of the waveform data is
        subtracted in time domain prior to deconvolution.
    :type taper: bool
    :param taper: If `True`, a cosine taper is applied to the waveform data
        in time domain prior to deconvolution.
    :type taper_fraction: float
    :param taper_fraction: Taper fraction of cosine taper to use.
    :type plot: bool or str
    :param plot: If `True`, brings up a plot that illustrates how the
        data are processed in the frequency domain in three steps. First by
        `pre_filt` frequency domain tapering, then by inverting the
        instrument response spectrum with or without `water_level` and
        finally showing data with inverted instrument response multiplied
        on it in frequency domain. It also shows the comparison of
        raw/corrected data in time domain. If a `str` is provided then the
        plot is saved to file (filename must have a valid image suffix
        recognizable by matplotlib e.g. '.png').
    """
   # limit_numpy_fft_cache()

    from obspy.core.inventory import PolynomialResponseStage
    from obspy.signal.invsim import (cosine_taper, cosine_sac_taper,
                                     invert_spectrum)
    if plot:
        import matplotlib.pyplot as plt

    if (isinstance(inventory, (str, native_str)) and
            inventory.upper() in ("DISP", "VEL", "ACC")):
        from obspy.core.util.deprecation_helpers import             ObsPyDeprecationWarning
        output = inventory
        inventory = None
        msg = ("The order of optional parameters in method "
               "remove_response has changed. 'output' is not accepted "
               "as first positional argument in the next release.")
        warnings.warn(msg, category=ObsPyDeprecationWarning, stacklevel=3)
    response = self._get_response(inventory)
    # polynomial response using blockette 62 stage 0
    if not response.response_stages and response.instrument_polynomial:
        coefficients = response.instrument_polynomial.coefficients
        self.data = np.poly1d(coefficients[::-1])(self.data)
        return self

    # polynomial response using blockette 62 stage 1 and no other stages
    if len(response.response_stages) == 1 and        isinstance(response.response_stages[0], PolynomialResponseStage):
        # check for gain
        if response.response_stages[0].stage_gain is None:
            msg = 'Stage gain not defined for %s - setting it to 1.0'
            warnings.warn(msg % self.id)
            gain = 1
        else:
            gain = response.response_stages[0].stage_gain
        coefficients = response.response_stages[0].coefficients[:]
        for i in range(len(coefficients)):
            coefficients[i] /= math.pow(gain, i)
        self.data = np.poly1d(coefficients[::-1])(self.data)
        return self

    # use evalresp
    data = self.data.astype(np.float64)
    npts = len(data)
    # time domain pre-processing
    if zero_mean:
        data -= data.mean()
    if taper:
        data *= cosine_taper(npts, taper_fraction,
                             sactaper=True, halfcosine=False)

    if plot:
        fontsz = 12
        color1 = "blue"
        color2 = "red"
        bbox = dict(boxstyle="round", fc="w", alpha=1, ec="w")
        bbox1 = dict(boxstyle="round", fc="blue", alpha=0.15)
        bbox2 = dict(boxstyle="round", fc="red", alpha=0.15)
        if fig is None:
            fig = plt.figure(figsize=(14, 10))
        fig.suptitle(str(self), fontsize=fontsz)
        ax1 = fig.add_subplot(321)
        ax1b = ax1.twinx()
        ax2 = fig.add_subplot(323, sharex=ax1)
        ax2b = ax2.twinx()
        ax3 = fig.add_subplot(325, sharex=ax1)
        ax3b = ax3.twinx()
        ax4 = fig.add_subplot(322)
        ax5 = fig.add_subplot(324, sharex=ax4)
        ax6 = fig.add_subplot(326, sharex=ax4)
        for ax_ in (ax1, ax2, ax3, ax4, ax5, ax6):
            ax_.grid(zorder=-10)
        if pre_filt is None:
            text = 'pre_filt: None'
        else:
            text = 'pre_filt: [{:.3g}, {:.3g}, {:.3g}, {:.3g}]'.format(
                *pre_filt)
        ax1.text(0.05, 0.1, text, ha="left", va="bottom",
                 transform=ax1.transAxes, fontsize=fontsz, bbox=bbox,
                 zorder=5)
        ax1.set_ylabel("Data spectrum, raw", bbox=bbox1, fontsize=fontsz)
        ax1b.set_ylabel("'pre_filt' taper fraction", bbox=bbox2, fontsize=fontsz)
        evalresp_info = "\n".join(
            ['output: %s' % output] +
            ['%s: %s' % (key, value) for key, value in kwargs.items()])
        ax2.text(0.05, 0.1, evalresp_info, ha="left",
                 va="bottom", transform=ax2.transAxes, zorder=5, bbox=bbox, fontsize=fontsz)
        ax2.set_ylabel("Data spectrum,\n"
                       "'pre_filt' applied", bbox=bbox1, fontsize=fontsz)
        ax2b.set_ylabel("Instrument response", bbox=bbox2, fontsize=fontsz)
        ax3.text(0.05, 0.1, 'water_level: %s' % water_level,
                 ha="left", va="bottom", transform=ax3.transAxes,
                 fontsize=fontsz, zorder=5, bbox=bbox)
        ax3.set_ylabel("Data spectrum,\nmultiplied with inverted\n"
                       "instrument response", bbox=bbox1, fontsize=fontsz)
        ax3b.set_ylabel("Inverted instrument response,\n"
                        "water level applied", bbox=bbox2, fontsize=fontsz)
        ax3.set_xlabel("Frequency [Hz]", fontsize=fontsz)
        
        times = self.times()
        ax4.plot(times, self.data, color="k")
        ax4.set_ylabel("Raw", fontsize=fontsz)
        ax4.yaxis.set_ticks_position("right")
        ax4.yaxis.set_label_position("right")
        ax5.plot(times, data, color="k")
        ax5.set_ylabel("Raw, after time\ndomain pre-processing", fontsize=fontsz)
        ax5.yaxis.set_ticks_position("right")
        ax5.yaxis.set_label_position("right")
        ax6.set_ylabel("Response removed", fontsize=fontsz)
        ax6.set_xlabel("Time [s]", fontsize=fontsz)
        ax6.yaxis.set_ticks_position("right")
        ax6.yaxis.set_label_position("right")
        ax1.tick_params(labelsize=fontsz)
        ax1b.tick_params(labelsize=fontsz)
        ax2.tick_params(labelsize=fontsz)
        ax2b.tick_params(labelsize=fontsz)
        ax3.tick_params(labelsize=fontsz)
        ax3b.tick_params(labelsize=fontsz)
        ax4.tick_params(labelsize=fontsz)
        ax5.tick_params(labelsize=fontsz)
        ax6.tick_params(labelsize=fontsz)

    # smart calculation of nfft dodging large primes
    from obspy.signal.util import _npts2nfft
    nfft = _npts2nfft(npts)
    # Transform data to Frequency domain
    data = np.fft.rfft(data, n=nfft)
    # calculate and apply frequency response,
    # optionally prefilter in frequency domain and/or apply water level
    freq_response, freqs =         response.get_evalresp_response(self.stats.delta, nfft,
                                       output=output, **kwargs)

    if plot:
        ax1.loglog(freqs, np.abs(data), color=color1, zorder=9, label= "Data")
        ax1.legend(loc = "upper left")

    # frequency domain pre-filtering of data spectrum
    # (apply cosine taper in frequency domain)
    if pre_filt:
        freq_domain_taper = cosine_sac_taper(freqs, flimit=pre_filt)
        data *= freq_domain_taper

    if plot:
        try:
            freq_domain_taper
        except NameError:
            freq_domain_taper = np.ones(len(freqs))
        ax1b.semilogx(freqs, freq_domain_taper, color=color2, zorder=10)
        ax1b.set_ylim(-0.05, 1.05)
        ax2.loglog(freqs, np.abs(data), color=color1, zorder=9, label = "Data")
        ax2b.loglog(freqs, np.abs(freq_response), color=color2, zorder=10, label = "Filter")
        ax2b.legend(loc = "upper left")

    if water_level is None:
        # No water level used, so just directly invert the response.
        # First entry is at zero frequency and value is zero, too.
        # Just do not invert the first value (and set to 0 to make sure).
        freq_response[0] = 0.0
        freq_response[1:] = 1.0 / freq_response[1:]
    else:
        # Invert spectrum with specified water level.
        invert_spectrum(freq_response, water_level)

    data *= freq_response
    data[-1] = abs(data[-1]) + 0.0j

    if plot:
        ax3.loglog(freqs, np.abs(data), color=color1, zorder=9, label = "Data")
        ax3b.loglog(freqs, np.abs(freq_response), color=color2, zorder=10, label = "Filter")

    # transform data back into the time domain
    data = np.fft.irfft(data)[0:npts]

    if plot:
        # Oftentimes raises NumPy warnings which we don't want to see.
        with np.errstate(all="ignore"):
            ax6.plot(times, data, color="k")
            plt.subplots_adjust(wspace=0.4)
            
            if plot is True and fig is None:
                plt.show()
            elif plot is True and fig is not None:
                pass
            else:
                plt.savefig(plot)
                plt.close(fig)

    # assign processed data and store processing information
    self.data = data
    return self, np.abs(freq_response)