示例#1
0
def cfrequency(data, fs, smoothie, fk):

    nfft = nextpow2(data.shape[0])
    freq = np.arange(0, float(fs) - 1. / (nextpow2(data.shape[0]) / float(fs)),
                                 1. / (nextpow2(data.shape[0]) / float(fs)))
    freqaxis = freq[0:len(freq) / 2 + 1]
    cfreq = np.zeros(data.shape[0])
    if (np.size(data.shape) > 1):
        i = 0
        for row in data:
            Px_wm = welch(row, hamming(len(row)), nextpow2(len(row)))
            Px = Px_wm[0:len(Px_wm) / 2]
            cfreq[i] = np.sqrt(sum(pow(freqaxis, 2) * Px) / (sum(Px)))
            i = i + 1
        cfreq = smooth(cfreq, smoothie)
        cfreq_add = append(append([cfreq[0]] * (size(fk) // 2), cfreq),
                              [cfreq[size(cfreq) - 1]] * (size(fk) // 2))
        dcfreq = signal.lfilter(fk, 1, cfreq_add)
        dcfreq = dcfreq[size(fk) // 2:(size(dcfreq) - size(fk) // 2)]
        return cfreq, dcfreq
    else:
        Px_wm = welch(data, np.hamming(len(data)), nextpow2(len(data)))
        Px = Px_wm[0:len(Px_wm) / 2]
        cfreq = np.sqrt(np.sum(pow(freqaxis, 2) * Px) / (sum(Px)))

    return cfreq
示例#2
0
def decovit(UIN,WIN,DT,NT,TSHIFT,F0,ITMAX,MINDERR):	
	print('Iterative Decon (Ligorria & Ammon):\n')  	
	
	RMS = np.zeros([ITMAX,1]) 
	nfft = nextpow2(NT) 
	P0 = np.zeros(nfft) 

	U0 = np.zeros(nfft)
	W0 = np.zeros(nfft)
	
	U0[0:NT]=UIN
	W0[0:NT]=WIN
	
	gaussF = gaussFilter( DT, nfft, F0 )
	
	U = gfilter( U0, nfft, gaussF , DT)
	W = gfilter( W0, nfft, gaussF , DT)
	
	Wf = np.fft.fft( W0, nfft )
	R = U
	
	powerU = np.sum(U**2)
	
	it = 0
	sumsq_i = 1
	d_error = 100*powerU + MINDERR
	maxlag = 0.5*nfft
	print('\tMax Spike Display is '+str((maxlag)*DT))
	
	while np.abs(d_error) > MINDERR  and it < ITMAX:
		
		
		RW= correl(R, W, nfft)
		RW = RW/np.sum(W**2)
		
		i1=np.argmax( np.abs( RW[0:int(maxlag)-1] ) )
		amp = RW[i1]/DT
		
		P0[i1] = P0[i1] + amp
		P = gfilter(P0, nfft, gaussF, DT)
		P = gfilter(P, nfft, Wf, DT)
		
		R = U - P
		sumsq = np.sum( R**2 )/powerU
		RMS[it] = sumsq
		d_error = 100*(sumsq_i - sumsq)
		
		sumsq_i = sumsq
		
		it = it+1
		
	P = gfilter( P0, nfft, gaussF, DT )
	P = phaseshift(P,nfft,DT,TSHIFT)
	RFI=P[0:NT]
	RMS = RMS[0:it-1]
	
	print('\t# iterations: ',it,'\n')
	print('\tFinal RMS: ',float(RMS[it-2]),'\n')
	
	return RFI, RMS, it
示例#3
0
def xcorrf(trace1, trace2, shift=None):
    """
    Cross-correlation of numpy arrays data1 and data2 in frequency domain.
    """
    data1 = trace1.data
    data2 = trace2.data

    complex_result = data1.dtype == complex or data2.dtype == complex
    N1 = len(data1)
    N2 = len(data2)

    data1 = data1.astype("float64")
    data2 = data2.astype("float64")

    # Always use 2**n-sized FFT, perform xcorr
    size = max(2 * shift + 1, (N1 + N2) // 2 + shift)
    nfft = nextpow2(size)
    IN1 = fft(data1, nfft)
    IN1 *= conjugate(fft(data2, nfft))
    ret = ifft(IN1)
    del IN1

    if not complex_result:
        ret = ret.real
    # shift data for time lag 0 to index 'shift'

    ret = roll(ret, -(N1 - N2) // 2 + shift)[: 2 * shift + 1]

    return copy(ret)
示例#4
0
    def _find_and_open_files(self):
        """
        Helper function walking the file tree below self.db_path and
        attempts to find the correct netCDF files.
        """
        found_files = []
        for root, dirs, filenames in os.walk(self.db_path, followlinks=True):
            # Limit depth of filetree traversal
            nested_levels = os.path.relpath(root, self.db_path).split(
                os.path.sep)
            if len(nested_levels) >= 4:
                del dirs[:]
            if "ordered_output.nc4" not in filenames:
                continue
            found_files.append(os.path.join(root, "ordered_output.nc4"))

        if len(found_files) == 0:
            raise InstaseisNotFoundError(
                "No suitable netCDF files found under '%s'" % self.db_path)
        elif len(found_files) not in [1, 2, 4]:
            raise InstaseisError(
                "1, 2 or 4 netCDF must be present in the folder structure. "
                "Found %i: \t%s" % (len(found_files),
                                    "\n\t".join(found_files)))

        # Parse to find the correct components.
        netcdf_files = collections.defaultdict(list)
        patterns = ["PX", "PZ", "MZZ", "MXX_P_MYY", "MXZ_MYZ", "MXY_MXX_M_MYY"]
        for filename in found_files:
            s = os.path.relpath(filename, self.db_path).split(os.path.sep)
            for p in patterns:
                if p in s:
                    netcdf_files[p].append(filename)

        # Assert at most one file per type.
        for key, files in netcdf_files.items():
            if len(files) != 1:
                raise InstaseisError(
                    "Found %i files for component %s:\n\t%s" % (
                        len(files), key, "\n\t".join(files)))
            netcdf_files[key] = files[0]

        # Two valid cases.
        if "PX" in netcdf_files or "PZ" in netcdf_files:
            self._parse_fs_meshes(netcdf_files)
        elif "MZZ" in netcdf_files or "MXX_P_MYY" in netcdf_files or \
                "MXZ_MYZ" in netcdf_files or "MXY_MXX_M_MYY" or netcdf_files:
            if sorted(netcdf_files.keys()) != sorted([
                    "MZZ", "MXX_P_MYY", "MXZ_MYZ", "MXY_MXX_M_MYY"]):
                raise InstaseisError(
                    "Expecting all four elemental moment tensor subfolders "
                    "to be present.")
            self._parse_mt_meshes(netcdf_files)
        else:
            raise InstaseisError("Could not find any suitable netCDF files.")

        # Set some common variables.
        self.nfft = nextpow2(self.ndumps) * 2
        self.planet_radius = self.parsed_mesh.planet_radius
        self.dump_type = self.parsed_mesh.dump_type
示例#5
0
文件: xcorr.py 项目: iceseismic/sito
def spectralWhitening(data, sr=None, smoothi=None, freq_domain=False, apply_filter=None):
    """
    Apply spectral whitening to data.
    
    sr: sampling rate (only needed for smoothing)
    smoothi: None or int
    Data is divided by its smoothed (Default: None) amplitude spectrum.
    """
    if freq_domain:
        mask = False
        spec = data
    else:
        mask = np.ma.getmask(data)
        N = len(data)
        nfft = nextpow2(N)
        spec = fft(data, nfft)
    #df = sr/N
    spec_ampl = np.sqrt(np.abs(np.multiply(spec, np.conjugate(spec))))
    if isinstance(smoothi, basestring) and isnumber(smoothi) and smoothi > 0:
        smoothi = int(smoothi * N / sr)
        spec /= ifftshift(smooth(fftshift(spec_ampl), smoothi))
    else:
        spec /= spec_ampl
    if apply_filter is not None:
        spec *= filterResp(*apply_filter, sr=sr, N=len(spec), whole=True)[1]
    if freq_domain:
        return spec
    else:
        ret = np.real(ifft(spec, nfft)[:N])
        if USE_FFTW3:
            ret = ret.copy()
        return fillArray(ret, mask=mask, fill_value=0.)
示例#6
0
文件: psd.py 项目: iceseismic/sito
def test():
    from sito import read
    from obspy.signal.freqattributes import mper  # , welch

    # from mtspec import mtspec

    ms = read("/home/richter/Data/Parkfield/raw/PKD_1996_296.mseed")
    # ms.plotTrace()

    print ms[0].stats
    # -*- snip -*-
    data = ms[0].data
    data = data - np.mean(data)
    # data -= np.linspace(0,1,len(data))*(data[-1]-data[0])+data[0]

    N = len(data)
    df = 1.0 / (ms[0].stats.endtime - ms[0].stats.starttime)
    print N // 2 * df

    spec1 = mper(data, cosTaper(N, 0.05), nextpow2(N))[: N // 2]
    # spec2 =  welch(data, cosTaper(N, 0.05), nextpow2(N), len(data)/10, 0.2)[:N//2]
    spec1_d = oct_downsample(spec1, df, fac=1.3)
    freq1 = get_octfreqs(len(spec1_d), df, fac=1.3)

    ax = plot_psd(spec1, log=True)
    ax = plot_psd(spec1_d, freq1, log=True, ax=ax)
    plt.show()
示例#7
0
    def whiten(self, smooth=None, apply_filter=None):
        """
        Apply spectral whitening to data.
        """
        logging.info("Whitening {:} traces...", len(self.traces)) 
        for tr in self.traces:

            mask = np.ma.getmask(tr.data)
            N = len(tr.data)
            nfft = nextpow2(N)
            spec = fft(tr.data, nfft)

            df = tr.stats['sampling_rate']
            spec_ampl = np.sqrt(np.abs(np.multiply(spec, np.conjugate(spec))))

            if isinstance(smooth, basestring) and isnumber(smooth) and\
                    (smooth > 0):
                smooth = int(smooth * N / df)
                spec /= ifftshift(smooth_func(fftshift(spec_ampl), smooth))
            else:
                spec /= spec_ampl
            if apply_filter is not None:
                spec *= bandpass_response(*apply_filter, sr=df, N=len(spec),
                        whole=True)[1]
            ret = np.real(ifft(spec, nfft)[:N])
            tr.data = fill_array(ret, mask=mask, fill_value=0.)
示例#8
0
    def _get_info(self):
        """
        Returns a dictionary with information about the currently loaded
        database.
        """
        # Get the size of all netCDF files.
        filesize = 0
        for m in self.meshes:
            if m:
                filesize += os.path.getsize(m.filename)

        if self._is_reciprocal:
            if self.meshes.pz is not None and self.meshes.px is not None:
                components = 'vertical and horizontal'
            elif self.meshes.pz is None and self.meshes.px is not None:
                components = 'horizontal only'
            elif self.meshes.pz is not None and self.meshes.px is None:
                components = 'vertical only'
        else:
            components = '4 elemental moment tensors'

        return dict(
            is_reciprocal=self._is_reciprocal,
            components=components,
            source_depth=float(self.parsed_mesh.source_depth)
            if self._is_reciprocal is False else None,
            velocity_model=self.parsed_mesh.background_model,
            external_model_name=self.parsed_mesh.external_model_name,
            attenuation=self.parsed_mesh.attenuation,
            period=float(self.parsed_mesh.dominant_period),
            dump_type=self.parsed_mesh.dump_type,
            excitation_type=self.parsed_mesh.excitation_type,
            dt=float(self.parsed_mesh.dt),
            sampling_rate=float(1.0 / self.parsed_mesh.dt),
            npts=int(self.parsed_mesh.ndumps),
            nfft=int(nextpow2(self.parsed_mesh.ndumps) * 2),
            length=float(self.parsed_mesh.dt * (self.parsed_mesh.ndumps - 1)),
            stf=self.parsed_mesh.stf_kind,
            src_shift=float(self.parsed_mesh.source_shift),
            src_shift_samples=int(self.parsed_mesh.source_shift_samp),
            slip=self.parsed_mesh.stf_norm,
            sliprate=self.parsed_mesh.stf_d_norm,
            spatial_order=int(self.parsed_mesh.npol),
            min_radius=float(self.parsed_mesh.kwf_rmin) * 1e3,
            max_radius=float(self.parsed_mesh.kwf_rmax) * 1e3,
            planet_radius=float(self.parsed_mesh.planet_radius),
            min_d=float(self.parsed_mesh.kwf_colatmin),
            max_d=float(self.parsed_mesh.kwf_colatmax),
            time_scheme=self.parsed_mesh.time_scheme,
            directory=os.path.relpath(self.db_path),
            filesize=filesize,
            compiler=self.parsed_mesh.axisem_compiler,
            user=self.parsed_mesh.axisem_user,
            format_version=int(self.parsed_mesh.file_version),
            axisem_version=self.parsed_mesh.axisem_version,
            datetime=self.parsed_mesh.creation_time
        )
示例#9
0
文件: deconvolve.py 项目: preinh/RF
def deconvf(rsp_list, src, sampling_rate, water=0.05, gauss=2., tshift=10.,
            pad=0, length=None, normalize=True, normalize_to_src=False,
            returnall=False):
    """
    Frequency-domain deconvolution using waterlevel method.

    rsp, src    data containing the response and
                source functions, respectively
    water       waterlevel to stabilize the deconvolution
    gauss       Gauss parameter of Low-pass filter
    tshift      shift the resulting function by that amount
    pad         multiply number of samples used for fft by 2**pad
    """
    if length == None:
        length = len(src)
    N = length
    nfft = nextpow2(N) * 2 ** pad
    freq = np.fft.fftfreq(nfft, d=1. / sampling_rate)
    gauss = np.exp(np.maximum(-(0.5 * 2 * pi * freq / gauss) ** 2, -700.) -
                   1j * tshift * 2 * pi * freq)

    spec_src = fft(src, nfft)
    spec_src_conj = np.conjugate(spec_src)
    spec_src_water = np.abs(spec_src * spec_src_conj)
    spec_src_water = np.maximum(spec_src_water, max(spec_src_water) * water)

    if normalize_to_src:
        spec_src = gauss * spec_src * spec_src_conj / spec_src_water
        rf_src = ifft(spec_src, nfft)[:N]
        #i1 = int((tshift-1)*sampling_rate)
        #i2 = int((tshift+1)*sampling_rate)
        norm = 1 / max(rf_src)
        rf_src = norm * rf_src

    flag = False
    if not isinstance(rsp_list, (list, tuple)):
        flag = True
        rsp_list = [rsp_list]
    rf_list = [ifft(gauss * fft(rsp, nfft) * spec_src_conj / spec_src_water,
                    nfft)[:N] for rsp in rsp_list]
    if normalize:
        if not normalize_to_src:
            norm = 1. / max(rf_list[0])
        for rf in rf_list:
            rf *= norm
    if returnall:
        if not normalize_to_src:
            spec_src = gauss * spec_src * spec_src_conj / spec_src_water
            rf_src = ifft(spec_src, nfft)[:N]
            norm = 1 / max(rf_src)
            rf_src = norm * rf_src
        return rf_list, rf_src, spec_src_conj, spec_src_water, freq, gauss, norm, N, nfft
    elif flag:
        return rf
    else:
        return rf_list
示例#10
0
def bwith(data, fs, smoothie, fk):
    """
    Bandwidth of a signal.

    Computes the bandwidth of the given data which can be windowed or not.
    The bandwidth corresponds to the level where the power of the spectrum is
    half its maximum value. It is determined as the level of 1/sqrt(2) times
    the maximum Fourier amplitude.

    If data are windowed the bandwidth of each window is returned.

    :type data: :class:`~numpy.ndarray`
    :param data: Data to make envelope of.
    :param fs: Sampling frequency in Hz.
    :param smoothie: Factor for smoothing the result.
    :param fk: Coefficients for calculating time derivatives
        (calculated via central difference).
    :return: **bwith[, dbwithd]** - Bandwidth, Time derivative of predominant
        period (windowed only).
    """
    new_dtype = np.float32 if data.dtype.itemsize == 4 else np.float64
    data = np.require(data, dtype=new_dtype)

    nfft = util.nextpow2(data.shape[1])
    freqaxis = np.linspace(0, fs, nfft + 1)
    bwith = np.zeros(data.shape[0])
    f = fftpack.fft(data, nfft)
    f_sm = util.smooth(abs(f[:, 0:nfft // 2]), 10)
    if np.size(data.shape) > 1:
        i = 0
        for row in f_sm:
            minfc = abs(row - max(abs(row * (1 / np.sqrt(2)))))
            [mdist_ind, _mindist] = min(enumerate(minfc), key=itemgetter(1))
            bwith[i] = freqaxis[mdist_ind]
            i = i + 1
        # bwith_add = \
        #        np.append(np.append([bwith[0]] * (np.size(fk) // 2), bwith),
        #        [bwith[np.size(bwith) - 1]] * (np.size(fk) // 2))
        # faster alternative
        bwith_add = np.hstack(
            ([bwith[0]] * (np.size(fk) // 2), bwith,
             [bwith[np.size(bwith) - 1]] * (np.size(fk) // 2)))
        dbwith = signal.lfilter(fk, 1, bwith_add)
        # dbwith = dbwith[np.size(fk) // 2:(np.size(dbwith) -
        #         np.size(fk) // 2)]
        # correct start and end values of time derivative
        dbwith = dbwith[np.size(fk) - 1:]
        bwith = util.smooth(bwith, smoothie)
        dbwith = util.smooth(dbwith, smoothie)
        return bwith, dbwith
    else:
        minfc = abs(data - max(abs(data * (1 / np.sqrt(2)))))
        [mdist_ind, _mindist] = min(enumerate(minfc), key=itemgetter(1))
        bwith = freqaxis[mdist_ind]
        return bwith
示例#11
0
文件: trace.py 项目: iceseismic/sito
 def fft(self, nfft=None):
     if self.stats.is_fft:
         raise ValueError('Trace already ffted.')
     self.stats.npts_data = self.stats.npts
     if nfft is None:
         nfft = nextpow2(self.stats.npts_data)
     self.stats.nfft = nfft
     self.stats.stdev = (np.sum(self.data ** 2)) ** 0.5
     self.data = fft(self.data, nfft, overwrite_x=False)
     self.stats.is_fft = True
     self.stats.filter += 'FFT'
示例#12
0
    def test_util_filterResponse(self):
        sr = self.stream[0].stats.sampling_rate

        # test filterResponse vs filter2
        st = self.stream.copy()
        data = st[0].data.copy()
        N = len(data)
        nfft = nextpow2(len(data))
        values = util.main.filterResp(1, 5, corners=2, sr=20, N=nfft, whole=True)[1]
        st.filter2(1, 5, corners=2)
        data2 = ifft(fft(data, nfft) * values, nfft)
        np.testing.assert_array_almost_equal(st[0].data, data2[:N])

        # test stream interface
        st = self.stream.copy()
        st.fft()
        st.filter2(1, 5, corners=2)
        st.ifft()
        np.testing.assert_array_almost_equal(st[0].data, data2[:N])

        # filtering with filterResponse and zerophase=Trueproduces a peak at
        # the end of data. With nfft=N there is no peak anymore, but still the values are not the same
        st = self.stream.copy()
        freqs, values = util.main.filterResp(1, 5, sr=20, N=nfft, corners=2, whole=True, zerophase=True)
        st.filter2(1, 5, corners=2, zerophase=True)
        data2 = ifft(fft(data, nfft) * values, nfft)
        np.testing.assert_array_almost_equal(st[0].data[:-10 * sr], data2[:N - 10 * sr])

        return

        from numpy.fft.helper import ifftshift, fftfreq
        import matplotlib.pyplot as plt

        real_freqs = (ifftshift(freqs) - np.pi) * 0.5 * sr / np.pi
        freqs2 = fftfreq(nfft, 1 / 20.)
        print real_freqs
        print freqs2

        plt.subplot(411)
        plt.plot(real_freqs, np.abs(values))
        ax = plt.subplot(412)
        plt.plot(data, label='data')
        plt.legend()
        plt.subplot(413, sharex=ax)
        plt.plot(st[0].data, alpha=0.5, label='stream.filter2')
        plt.plot(data2[:N], alpha=0.5, label='filterResponse')
        plt.legend()
        plt.show()
def shifttrace_freq(stream, t_shift):
    if isinstance(stream, Stream):
        for i, tr in enumerate(stream):
            ndat = tr.stats.npts
            samp = tr.stats.sampling_rate
            nfft = nextpow2(ndat)
            nfft *= 2
            tr1 = np.fft.rfft(tr.data, nfft)
            for k in xrange(0, nfft / 2):
                tr1[k] *= np.complex(
                    np.cos((t_shift[i] * samp) * (k / float(nfft)) * 2.0 * np.pi),
                    -np.sin((t_shift[i] * samp) * (k / float(nfft)) * 2.0 * np.pi),
                )

            tr1 = np.fft.irfft(tr1, nfft)
            tr.data = tr1[0:ndat]
示例#14
0
def convSTF(st, sigma=30.):

    gauss = lambda (t, s): 1. / (2. * np.pi * s**2.)**.5 \
                           * np.exp(-1*(t**2)/(2*(s**2)))

    df = st[0].stats.sampling_rate
    dt = 1./df

    t = np.linspace(0., sigma * 20., sigma * 20 * df + 1)
    stf = gauss((t-sigma*10, sigma))
    nstf = len(stf)

    for tr in st:
        tr.data *= cosTaper(len(tr.data), p=0.05)
        nfft = util.nextpow2(max(nstf, tr.stats.npts)) * 2
        stff = np.fft.rfft(stf, n=nfft) * dt
        trf = np.fft.rfft(tr, n=nfft) * dt
        tr.data = np.fft.irfft(stff * trf)[sigma*10*df:sigma*10*df+len(tr.data)] * df

    return 1
示例#15
0
def spectrum_calc(tr):
    """
    Simple code to calculate the spectrum of a trace
    :param tr: obspy Trace
    :return:
    freqs, spec_tr
    which are frequencies and spectrum of the trace

    To plot the spectrum:

    import matplotlib.pyplot as plt
    plt.loglog(freqs, spec_tr)
    """

    nfft = nextpow2(tr.stats.npts)
    freqs = np.fft.rfftfreq(nfft) / tr.stats.delta

    spec_tr = np.abs(np.fft.rfft(tr.data, n=nfft))

    return freqs, spec_tr
示例#16
0
def logcep(data, fs, nc, p, n, w):  # @UnusedVariable: n is never used!!!
    """
    Cepstrum of a signal.

    Computes the cepstral coefficient on a logarithmic scale of the given data
    which can be windowed or not.

    If data are windowed the analytic signal and the envelope of each window is
    returned.

    :type data: :class:`~numpy.ndarray`
    :param data: Data to make envelope of.
    :param fs: Sampling frequency in Hz.
    :param nc: number of cepstral coefficients.
    :param p: Number of filters in filterbank.
    :param n: Number of data windows.
    :return: Cepstral coefficients.
    """
    new_dtype = np.float32 if data.dtype.itemsize == 4 else np.float64
    data = np.require(data, dtype=new_dtype)

    dataT = np.transpose(data)
    nfft = util.nextpow2(dataT.shape[0])
    fc = fftpack.fft(dataT, nfft, 0)
    f = fc[1:len(fc) // 2 + 1, :]
    m, a, b = logbankm(p, nfft, fs, w)
    pw = np.real(np.multiply(f[a:b, :], np.conj(f[a:b, :])))
    pth = np.max(pw) * 1E-20
    ath = np.sqrt(pth)
    # h1 = np.transpose(np.array([[ath] * int(b + 1 - a)]))
    # h2 = m * abs(f[a - 1:b, :])
    y = np.log(np.maximum(m * abs(f[a - 1:b, :]), ath))
    z = util.rdct(y)
    z = z[1:, :]
    # nc = nc + 1
    nf = np.size(z, 1)
    if (p > nc):
        z = z[:nc, :]
    elif (p < nc):
        z = np.vstack([z, np.zeros(nf, nc - p)])
    return z
示例#17
0
def spectralwhitening(st):
    """
    Apply spectral whitening to data.
    Data is divided by its smoothed (Default: None) amplitude spectrum.
    """
    
    for trace in arange(len(st)):
        data = st[trace].data
        
        n = len(data)
        nfft = nextpow2(n)
        
        spec = fft(data, nfft)
        spec_ampl = sqrt(abs(multiply(spec, conjugate(spec))))
        
        spec /= spec_ampl  #Do we need to do some smoothing here?
        ret = real(ifft(spec, nfft)[:n])
        
        st[trace].data = ret
        
    return st
示例#18
0
文件: rf.py 项目: iceseismic/sito
def gauss(data, sampling_rate, gauss, pad=0, hp=None, return_gauss=False):
    """
    Gauss filter

    gauss       Gauss parameter of Low-pass filter
    pad         multiply number of samples used for fft by 2**pad
    """
    N = len(data)
    nfft = nextpow2(N) * 2 ** pad
    freq = np.fft.fftfreq(nfft, d=1. / sampling_rate)
    gauss = np.exp(maximum(-(0.5 * 2 * pi * freq / gauss) ** 2, -700.))
    if hp:
        hp = filterResp(hp[0], hp[1], corners=hp[2], zerophase=True,
                        sr=sampling_rate, N=nfft, whole=True)[1]
        gauss = hp * gauss
    if return_gauss:
        return gauss
#    import pylab
#    pylab.plot(freq, gauss)
#    pylab.show()
    resp = ifft(gauss * fft(data, nfft), nfft)[:N]
    return resp
示例#19
0
def cfrequency_unwindowed(data, fs):
    """
    Central frequency of a signal.

    Computes the central frequency of the given data (a single waveform).
    The central frequency is a measure of the frequency where the
    power is concentrated. It corresponds to the second moment of the power
    spectral density function.

    The central frequency is returned in Hz.

    :type data: :class:`~numpy.ndarray`
    :param data: Data to estimate central frequency from.
    :param fs: Sampling frequency in Hz.
    :return: **cfreq** - Central frequency in Hz
    """
    nfft = util.nextpow2(len(data))
    freq = np.linspace(0, fs, nfft + 1)
    freqaxis = freq[0 : nfft // 2]
    Px_wm = welch(data, np.hamming(len(data)), nfft)
    Px = Px_wm[0 : len(Px_wm) // 2]
    cfreq = np.sqrt(np.sum(freqaxis ** 2 * Px) / (sum(Px)))
    return cfreq
示例#20
0
文件: xcorr.py 项目: wangwu1991/sito
def spectralWhitening(data,
                      sr=None,
                      smoothi=None,
                      freq_domain=False,
                      apply_filter=None):
    """
    Apply spectral whitening to data.
    
    sr: sampling rate (only needed for smoothing)
    smoothi: None or int
    Data is divided by its smoothed (Default: None) amplitude spectrum.
    """
    if freq_domain:
        mask = False
        spec = data
    else:
        mask = np.ma.getmask(data)
        N = len(data)
        nfft = nextpow2(N)
        spec = fft(data, nfft)
    #df = sr/N
    spec_ampl = np.sqrt(np.abs(np.multiply(spec, np.conjugate(spec))))
    if isinstance(smoothi, basestring) and isnumber(smoothi) and smoothi > 0:
        smoothi = int(smoothi * N / sr)
        spec /= ifftshift(smooth(fftshift(spec_ampl), smoothi))
    else:
        spec /= spec_ampl
    if apply_filter is not None:
        spec *= filterResp(*apply_filter, sr=sr, N=len(spec), whole=True)[1]
    if freq_domain:
        return spec
    else:
        ret = np.real(ifft(spec, nfft)[:N])
        if USE_FFTW3:
            ret = ret.copy()
        return fillArray(ret, mask=mask, fill_value=0.)
示例#21
0
def spectralwhitening_smooth(stream, N):
    """
    Apply spectral whitening to data.
    Data is divided by its smoothed (Default: None) amplitude spectrum.
    """
    stream2 = copy.deepcopy(stream)

    for trace in arange(len(stream2)):
        data = stream2[trace].data

        n = len(data)
        nfft = nextpow2(n)

        spec = fft(data, nfft)
        spec_ampl = sqrt(abs(multiply(spec, conjugate(spec))))

        spec_ampl = smooth(spec_ampl, N)

        spec /= spec_ampl  #Do we need to do some smoothing here?
        ret = real(ifft(spec, nfft)[:n])

        stream2[trace].data = ret

    return stream2
示例#22
0
文件: trace.py 项目: iceseismic/sito
 def acorr(self, shift=None, normalize=True, oneside=False):
     if shift is None:
         shift = len(self.data)
     else:
         shift = int(shift * self.stats.sampling_rate)
     size = max(2 * shift + 1, len(self.data) + shift)
     nfft = nextpow2(size)
     IN1 = fft(self.data, nfft)
     IN1 *= np.conjugate(IN1)
     ret = ifft(IN1).real
     # shift data for time lag 0 to index 'shift'
     ret = np.roll(ret, shift)[:2 * shift + 1]
     # normalize xcorr
     if normalize:
         stdev = (np.sum(self.data ** 2)) ** 0.5
         if stdev == 0:
             log.warning('Data is zero!!')
             ret[:] = 0.
         else:
             ret /= stdev ** 2
     if oneside:
         ret = ret[shift:]
     self.data = ret
     self.stats.npts = len(ret)
示例#23
0
文件: trace.py 项目: wangwu1991/sito
 def acorr(self, shift=None, normalize=True, oneside=False):
     if shift is None:
         shift = len(self.data)
     else:
         shift = int(shift * self.stats.sampling_rate)
     size = max(2 * shift + 1, len(self.data) + shift)
     nfft = nextpow2(size)
     IN1 = fft(self.data, nfft)
     IN1 *= np.conjugate(IN1)
     ret = ifft(IN1).real
     # shift data for time lag 0 to index 'shift'
     ret = np.roll(ret, shift)[:2 * shift + 1]
     # normalize xcorr
     if normalize:
         stdev = (np.sum(self.data**2))**0.5
         if stdev == 0:
             log.warning('Data is zero!!')
             ret[:] = 0.
         else:
             ret /= stdev**2
     if oneside:
         ret = ret[shift:]
     self.data = ret
     self.stats.npts = len(ret)
示例#24
0
def xcorrf(trace1, trace2, shift=None):
    """
    Cross-correlation of numpy arrays data1 and data2 in frequency domain.
    """
    data1 = trace1.data
    data2 = trace2.data

    complex_result = (data1.dtype == complex or data2.dtype == complex)
    N1 = len(data1)
    N2 = len(data2)

    data1 = data1.astype('float64')
    data2 = data2.astype('float64')

    # Always use 2**n-sized FFT, perform xcorr
    size = max(2 * shift + 1, (N1 + N2) // 2 + shift)
    nfft = nextpow2(size)
    print size
    #Calculate fft of data1 and data2

    IN1 = fft(data1, nfft)
    IN2 = fft(data2, nfft)

    IN1 *= conjugate(IN2)

    ret = ifft(IN1)

    del IN1, IN2

    if not complex_result:
        ret = ret.real
    # shift data for time lag 0 to index 'shift'

    ret = roll(ret, -(N1 - N2) // 2 + shift)[:2 * shift + 1]

    return copy(ret)
示例#25
0
文件: invsim.py 项目: gthompson/obspy
def seisSim(data, samp_rate, paz_remove=None, paz_simulate=None,
            remove_sensitivity=True, simulate_sensitivity=True,
            water_level=600.0, zero_mean=True, taper=True,
            taper_fraction=0.05, pre_filt=None, seedresp=None,
            nfft_pow2=False, pitsasim=True, sacsim=False, shsim=False,
            **_kwargs):
    """
    Simulate/Correct seismometer.

    :type data: NumPy ndarray
    :param data: Seismogram, detrend before hand (e.g. zero mean)
    :type samp_rate: Float
    :param samp_rate: Sample Rate of Seismogram
    :type paz_remove: Dictionary, None
    :param paz_remove: Dictionary containing keys 'poles', 'zeros', 'gain'
        (A0 normalization factor). poles and zeros must be a list of complex
        floating point numbers, gain must be of type float. Poles and Zeros are
        assumed to correct to m/s, SEED convention. Use None for no inverse
        filtering.
    :type paz_simulate: Dictionary, None
    :param paz_simulate: Dictionary containing keys 'poles', 'zeros', 'gain'.
        Poles and zeros must be a list of complex floating point numbers, gain
        must be of type float. Or None for no simulation.
    :type remove_sensitivity: Boolean
    :param remove_sensitivity: Determines if data is divided by
        `paz_remove['sensitivity']` to correct for overall sensitivity of
        recording instrument (seismometer/digitizer) during instrument
        correction.
    :type simulate_sensitivity: Boolean
    :param simulate_sensitivity: Determines if data is multiplied with
        `paz_simulate['sensitivity']` to simulate overall sensitivity of
        new instrument (seismometer/digitizer) during instrument simulation.
    :type water_level: Float
    :param water_level: Water_Level for spectrum to simulate
    :type zero_mean: Boolean
    :param zero_mean: If true the mean of the data is subtracted
    :type taper: Boolean
    :param taper: If true a cosine taper is applied.
    :type taper_fraction: Float
    :param taper_fraction: Taper fraction of cosine taper to use
    :type pre_filt: List or tuple of floats
    :param pre_filt: Apply a bandpass filter to the data trace 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 seedresp: Dictionary, None
    :param seedresp: Dictionary contains keys 'filename', 'date', 'units'.
        'filename' is the path to a RESP-file generated from a dataless SEED
        volume (or a file like object with RESP information);
        'date' is a `~obspy.core.utcdatetime.UTCDateTime` object for the date
        that the response function should be extracted for (can be omitted when
        calling simulate() on Trace/Stream. the Trace's starttime will then be
        used);
        'units' defines the units of the response function.
        Can be either 'DIS', 'VEL' or 'ACC'.
    :type nfft_pow2: Boolean
    :param nfft_pow2: Number of frequency points to use for FFT. If True,
        the exact power of two is taken (default in PITSA). If False the
        data are not zeropadded to the next power of two which makes a
        slower FFT but is then much faster for e.g. evalresp which scales
        with the FFT points.
    :type pitsasim: Boolean
    :param pitsasim: Choose parameters to match
        instrument correction as done by PITSA.
    :type sacsim: Boolean
    :param sacsim: Choose parameters to match
        instrument correction as done by SAC.
    :type shsim: Boolean
    :param shsim: Choose parameters to match
        instrument correction as done by Seismic Handler.
    :return: The corrected data are returned as numpy.ndarray float64
        array. float64 is chosen to avoid numerical instabilities.

    This function works in the frequency domain, where nfft is the next power
    of len(data) to avoid wrap around effects during convolution. The inverse
    of the frequency response of the seismometer (``paz_remove``) is
    convolved with the spectrum of the data and with the frequency response
    of the seismometer to simulate (``paz_simulate``). A 5% cosine taper is
    taken before simulation. The data must be detrended (e.g.) zero mean
    beforehand. If paz_simulate=None only the instrument correction is done.
    In the latter case, a broadband filter can be applied to the data trace
    using pre_filt. This restricts the signal to the valid frequency band and
    thereby avoids artefacts due to amplification of frequencies outside of the
    instrument's passband (for a detailed discussion see
    *Of Poles and Zeros*, F. Scherbaum, Kluwer Academic Publishers).

    .. versionchanged:: 0.5.1
        The default for `remove_sensitivity` and `simulate_sensitivity` has
        been changed to ``True``. Old deprecated keyword arguments `paz`,
        `inst_sim`, `no_inverse_filtering` have been removed.
    """
    # Checking the types
    if not paz_remove and not paz_simulate and not seedresp:
        msg = "Neither inverse nor forward instrument simulation specified."
        raise TypeError(msg)

    for d in [paz_remove, paz_simulate]:
        if d is None:
            continue
        for key in ['poles', 'zeros', 'gain']:
            if key not in d:
                raise KeyError("Missing key: %s" % key)
    # Translated from PITSA: spr_resg.c
    delta = 1.0 / samp_rate
    #
    ndat = len(data)
    data = data.astype("float64")
    if zero_mean:
        data -= data.mean()
    if taper:
        if sacsim:
            data *= cosTaper(ndat, taper_fraction,
                             sactaper=sacsim, halfcosine=False)
        else:
            data *= cosTaper(ndat, taper_fraction)
    # The number of points for the FFT has to be at least 2 * ndat (in
    # order to prohibit wrap around effects during convolution) cf.
    # Numerical Recipes p. 429 calculate next power of 2.
    if nfft_pow2:
        nfft = util.nextpow2(2 * ndat)
    # evalresp scales directly with nfft, therefore taking the next power of
    # two has a greater negative performance impact than the slow down of a
    # not power of two in the FFT
    else:
        nfft = _npts2nfft(ndat)
    # Transform data in Fourier domain
    data = np.fft.rfft(data, n=nfft)
    # Inverse filtering = Instrument correction
    if paz_remove:
        freq_response, freqs = pazToFreqResp(paz_remove['poles'],
                                             paz_remove['zeros'],
                                             paz_remove['gain'], delta, nfft,
                                             freq=True)
    if seedresp:
        freq_response, freqs = evalresp(delta, nfft, seedresp['filename'],
                                        seedresp['date'],
                                        units=seedresp['units'], freq=True,
                                        network=seedresp['network'],
                                        station=seedresp['station'],
                                        locid=seedresp['location'],
                                        channel=seedresp['channel'])
        if not remove_sensitivity:
            msg = "remove_sensitivity is set to False, but since seedresp " + \
                  "is selected the overall sensitivity will be corrected " + \
                  " for anyway!"
            warnings.warn(msg)
    if paz_remove or seedresp:
        if pre_filt:
            # make cosine taper
            fl1, fl2, fl3, fl4 = pre_filt
            if sacsim:
                cos_win = c_sac_taper(freqs, flimit=(fl1, fl2, fl3, fl4))
            else:
                cos_win = cosTaper(freqs.size, freqs=freqs,
                                   flimit=(fl1, fl2, fl3, fl4))
            data *= cos_win
        specInv(freq_response, water_level)
        data *= freq_response
        del freq_response
    # Forward filtering = Instrument simulation
    if paz_simulate:
        data *= pazToFreqResp(paz_simulate['poles'], paz_simulate['zeros'],
                              paz_simulate['gain'], delta, nfft)

    data[-1] = abs(data[-1]) + 0.0j
    # transform data back into the time domain
    data = np.fft.irfft(data)[0:ndat]
    if pitsasim:
        # linear detrend
        data = simpleDetrend(data)
    if shsim:
        # detrend using least squares
        data = scipy.signal.detrend(data, type="linear")
    # correct for involved overall sensitivities
    if paz_remove and remove_sensitivity and not seedresp:
        data /= paz_remove['sensitivity']
    if paz_simulate and simulate_sensitivity:
        data *= paz_simulate['sensitivity']
    return data
示例#26
0
def mtinv_gs(st_tr, gl, fmin, fmax, fmax_hardcut_factor=4, S0=None, nsv=1,
          single_force=False, stat_subset=[], weighting_type=2, weights=[],
          cache_path='', force_recalc=False, cache=False, w_level=50,
          method='full_pca', constrained_sources=None):
    '''
    Frequency domain moment tensor inversion.

    Features:
     - grid search for best source location
     - direct inversion for different error measures (see weighting type)
     - constrain to limited number of source mechanisms/time dependencies using
       principal component analysis
     - deconvolution of source time function used for Green's function
       simulations
     - caching the Green's matrix in Frequency space for speed up of repeated
       evaluation

    Theory see Diplomathesis 'The Effect of Tilt on Moment Tensor Inversion in
    the Nearfield of Active Volcanoes' section 2.2

    :type st_tr: :class:`~obspy.core.stream.Stream`
    :param st_tr: Stream containing the seismograms, station names are numbers
        starting with 0001, channels are ['u', 'v', 'w']
    :type gl: list of :class:`~obspy.core.stream.Stream` objects or list
    :param gl: list of Streams containing the green's functions, station names
        are numbers starting with 0001, channels are of format '%02d%1d' where
        the first number is the component of the receiver ([0,1,2]) and the
        second the source ([0,1,...,5] or [0,1,...,8] including single forces).
        Should have the same sample rate as st_tr. If no grid search is needed,
        just put a single stream in the list.
        In case of a high number of stations (>250), gl can be a list of 
        strings containing the path to and names of the greens functions files
    :type fmin: float
    :param fmin: high pass frequency
    :type fmax: float
    :param fmax: low pass frequency
    :type fmax_hardcut_factor: int
    :param fmax_hardcut_factor: multiple of fmax where the inversion is stopped
    :type S0: :class:`numpy.ndarray`
    :param S0: source time function used for computation of the Green's
        function to deconvolve. Is assumed to have same sample rate as st_tr.
        If S0 is None, no deconvolution is performed.
    :type nsv: int
    :param nsv: number of mechanisms corresponding to the largest singular
        values in the constrained inversion
    :type single_force: Bool
    :param single_force: include single force in the inversion (then green's
        functions for single forces are needed in channels ([6,7,8]))
    :type stat_subset: List
    :param stat_subset: List of stations to use in the inversion
    :type weighting: int
    :param weighting_type: should be one of [0,1,2], 0: no weighting, 1: use l2
        norm weighting for each trace, 2: use l2 norm weighting for each
        station (weight is sum of the weights of the traces)
    :type weights: listtype
    :param weights: a priori relative weighting of stations, should have length
        nstat or same length as stat_subset
    :type cache_path: string
    :param cache_path: path to a folder to cache Green's matrix
    :type force_recalc: Bool
    :param force_recalc: force reevalution of fourier transform of
        Green's functions (if cached in 'cache_path' to speed up inversion).
    :type cache: Bool
    :param cache: cache in a file or not
    :type w_level: int
    :param w_level: value of waterlevel in dB under max amplitude in spectrum
        of deconvolved Green's function

    returns a tuple containing:
        M_t     - time dependent Momenttensor solution (if nsv > 1 than summed
                  up mechanisms)
        m       - time independent Momenttensor (nsv arrays)
        x       - time dependence of principal component solutions in m
        s       - singular values of principal components
        st_syn  - synthetic seismograms generated with the inverted source
        st_tr   - input seismograms filtered the same way as the synthetics
                  (for comparison to synthetic seismograms)
        misfit  - misfit of synthetics, definition depends on weighting
                  (is only mathematically strict minimized for nsv=6  (9 in
                  case of single force), otherwise approximately)
        argmin  - index of Green's function in list that minimizes the misfit
    '''
    st_tr = st_tr.copy()
    st_tr.filter('lowpass', freq=fmax, corners=4)
    st_tr.filter('highpass', freq=fmin, corners=4)

    # test if gl is a list or a stream
    if type(gl[0]) == str:
        st_g = read('%s'%(gl[0]))
    else:
        st_g = gl[0]

    ng = st_g[0].data.size

    df = st_tr[0].stats.sampling_rate
    dt = 1./df

    nstat = st_tr.select(channel='u').count()
    ndat = st_tr[0].data.size
    nfft = util.nextpow2(max(ndat, ng) * 2)

    # use freuquncies below corner frequency * fmax_hardcut_factor (tremendous
    # speed up in inversion)
    nfinv = int(fmax_hardcut_factor * fmax / (df / 2.) * nfft)
    nfinv = min(nfft/2+1, nfinv)

    # going to frequency domain

    # correction for stf used in green's forward simulation
    if S0 is None:
        S0w = 1.
    else:
        S0w = np.fft.rfft(S0, n=nfft)[:nfinv] * dt

        # introduce waterlevel to prevent instabilities in deconvolution of
        # greens functions, see obspy.signal.invsim specInv

        # Calculated waterlevel in the scale of spec
        swamp = waterlevel(S0w, w_level)
        # Find length in real fft frequency domain, spec is complex
        sqrt_len = np.abs(S0w)
        # Set/scale length to swamp, but leave phase untouched
        # 0 sqrt_len will transform in np.nans when dividing by it
        idx = np.where((sqrt_len < swamp) & (sqrt_len > 0.0))
        S0w[idx] *= swamp / sqrt_len[idx]


    # setup seismogram matrix in fourier space
    utr = np.zeros((nstat * 3, ndat))
    utrw = np.zeros((nstat * 3, nfft/2+1)) * 0j
    weights_l2 = np.zeros(nstat * 3)

    for k in np.arange(nstat):
        for i, chan in enumerate(['u', 'v', 'w']):
            utr[k*3 + i,:] = st_tr.select(station='%04d' % (k+1), channel=chan)[0].data
            utrw[k*3 + i,:] = np.fft.rfft(utr[k*3 + i,:], n=nfft) * dt
            # calculate l2 norm for weighting
            weights_l2[k*3 + i] = cumtrapz(utr[k*3 + i,:]**2, dx=dt)[-1]
    
    M_tl = []
    ml = []
    xl = []
    sl = []
    st_synl = []
    misfitl = []

    st_tr.filter('lowpass', freq=fmax, corners=4)

    if method == 'full_pca':
        for i, stg in enumerate(gl):
            if type(stg) == str:
                st_g = read('%s'%(stg))
            else:
                st_g = stg
            print i

            if round(st_tr[0].stats.sampling_rate, 5) != round(st_g[0].stats.sampling_rate, 5):
                msg = 'sampling rates of Seismograms and Green\'s function are not the'
                msg = msg + ' same: %f != %f' % (st_tr[0].stats.sampling_rate,
                                                 st_g[0].stats.sampling_rate)
                raise ValueError(msg)

            M_t, m, x, s, st_syn, misfit = mtinv((utrw, weights_l2.copy(), S0w, df,
                dt, nstat, ndat, ng, nfft, nfinv), st_tr, st_g, fmin, fmax,
                nsv=nsv, single_force=single_force, stat_subset=stat_subset,
                force_recalc=force_recalc, weighting_type=weighting_type,
                weights=weights, cache_path=cache_path + ('%06d_' % i), cache=cache)

            M_tl.append(M_t)
            ml.append(m)
            xl.append(x)
            sl.append(s)
            st_synl.append(st_syn)
            misfitl.append(misfit)

        misfit = np.array(misfitl)
        argmin = misfit.argmin()
        

        return M_tl[argmin], ml[argmin], xl[argmin], sl[argmin], st_synl[argmin], st_tr, misfit, argmin
    
    elif method == 'constrained':
    
        for i, stg in enumerate(gl):
            if type(stg) == str:
                st_g = read('%s'%(stg))
            else:
                st_g = stg
            print i

            if round(st_tr[0].stats.sampling_rate, 5) != round(st_g[0].stats.sampling_rate, 5):
                msg = 'sampling rates of Seismograms and Green\'s function are not the'
                msg = msg + ' same: %f != %f' % (st_tr[0].stats.sampling_rate,
                                                 st_g[0].stats.sampling_rate)
                raise ValueError(msg)

            M, stf, misfit, st_syn = mtinv_constrained((utrw, weights_l2.copy(), S0w, df,
                dt, nstat, ndat, ng, nfft, nfinv), st_tr, st_g, fmin, fmax,
                nsv=nsv, single_force=single_force, stat_subset=stat_subset,
                force_recalc=force_recalc, weighting_type=weighting_type,
                weights=weights, cache_path=cache_path + ('%06d_' % i),
                cache=cache, constrained_sources=constrained_sources)

            M_tl.append(M)
            sl.append(stf)
            st_synl.append(st_syn)
            misfitl.append(misfit)

        misfit = np.array(misfitl)
        argmin = misfit.argmin()
        

        return M_tl[argmin], sl[argmin], st_synl[argmin], st_tr, misfit, argmin
示例#27
0
def relcalstack(st1,
                st2,
                calib_file,
                window_len,
                overlap_frac=0.5,
                smooth=0,
                save_data=True):
    """
    Method for relative calibration of sensors using a sensor with known
    transfer function

    :param st1: Stream or Trace object, (known)
    :param st2: Stream or Trace object, (unknown)
    :type calib_file: str
    :param calib_file: file name of calibration file containing the PAZ of the
        known instrument in GSE2 standard.
    :type window_len: float
    :param window_len: length of sliding window in seconds
    :type overlap_frac: float
    :param overlap_frac: fraction of overlap, defaults to fifty percent (0.5)
    :type smooth: float
    :param smooth: variable that defines if the Konno-Ohmachi taper is used or
        not. default = 0 -> no taper generally used in geopsy: smooth = 40
    :type save_data: bool
    :param save_data: Whether or not to save the result to a file. If True, two
        output files will be created:
        * The new response in station_name.window_length.resp
        * The ref response in station_name.refResp
        Defaults to True
    :returns: frequency, amplitude and phase spectrum

    implemented after relcalstack.c by M.Ohrnberger and J.Wassermann.
    """
    # transform given trace objects to streams
    if isinstance(st1, Trace):
        st1 = Stream([st1])
    if isinstance(st2, Trace):
        st2 = Stream([st2])
    # check if sampling rate and trace length is the same
    if st1[0].stats.npts != st2[0].stats.npts:
        msg = "Traces don't have the same length!"
        raise ValueError(msg)
    elif st1[0].stats.sampling_rate != st2[0].stats.sampling_rate:
        msg = "Traces don't have the same sampling rate!"
        raise ValueError(msg)
    else:
        ndat1 = st1[0].stats.npts
        sampfreq = st1[0].stats.sampling_rate

    # read waveforms
    tr1 = st1[0].data.astype(np.float64)
    tr2 = st2[0].data.astype(np.float64)

    # get window length, nfft and frequency step
    ndat = int(window_len * sampfreq)
    nfft = nextpow2(ndat)

    # read calib file and calculate response function
    gg, _freq = _calcresp(calib_file, nfft, sampfreq)

    # calculate number of windows and overlap
    nwin = int(np.floor((ndat1 - nfft) / (nfft / 2)) + 1)
    noverlap = nfft * overlap_frac

    auto, _freq, _t = \
        spectral_helper(tr1, tr1, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)
    cross, freq, _t = \
        spectral_helper(tr2, tr1, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)

    res = (cross / auto).sum(axis=1) * gg

    # The first item might be zero. Problems with phase calculations.
    res = res[1:]
    freq = freq[1:]
    gg = gg[1:]

    res /= nwin
    # apply Konno-Ohmachi smoothing taper if chosen
    if smooth > 0:
        # Write in one matrix for performance reasons.
        spectra = np.empty((2, len(res.real)))
        spectra[0] = res.real
        spectra[1] = res.imag
        new_spectra = \
            konnoOhmachiSmoothing(spectra, freq, bandwidth=smooth, count=1,
                                  max_memory_usage=1024, normalize=True)
        res.real = new_spectra[0]
        res.imag = new_spectra[1]

    amp = np.abs(res)
    # include phase unwrapping
    phase = np.unwrap(np.angle(res))  # + 2.0 * np.pi
    ra = np.abs(gg)
    rpha = np.unwrap(np.angle(gg))

    if save_data:
        trans_new = (st2[0].stats.station + "." + st2[0].stats.channel + "." +
                     str(window_len) + ".resp")
        trans_ref = st1[0].stats.station + ".refResp"
        # Create empty array for easy saving
        temp = np.empty((len(freq), 3))
        temp[:, 0] = freq
        temp[:, 1] = amp
        temp[:, 2] = phase
        np.savetxt(trans_new, temp, fmt="%.10f")
        temp[:, 1] = ra
        temp[:, 2] = rpha
        np.savetxt(trans_ref, temp, fmt="%.10f")

    return freq, amp, phase
示例#28
0
def deconvf(rsp_list,
            src,
            sampling_rate,
            water=0.05,
            gauss=2.,
            tshift=10.,
            pad=0,
            length=None,
            normalize=True,
            normalize_to_src=False,
            returnall=False):
    """
    Frequency-domain deconvolution using waterlevel method.

    rsp, src    data containing the response and
                source functions, respectively
    water       waterlevel to stabilize the deconvolution
    gauss       Gauss parameter of Low-pass filter
    tshift      shift the resulting function by that amount
    pad         multiply number of samples used for fft by 2**pad
    """
    if length == None:
        length = len(src)
    N = length
    nfft = nextpow2(N) * 2**pad
    freq = np.fft.fftfreq(nfft, d=1. / sampling_rate)
    gauss = np.exp(
        maximum(-(0.5 * 2 * pi * freq / gauss)**2, -700.) -
        1j * tshift * 2 * pi * freq)

    spec_src = fft(src, nfft)
    spec_src_conj = np.conjugate(spec_src)
    spec_src_water = np.abs(spec_src * spec_src_conj)
    spec_src_water = np.maximum(spec_src_water, max(spec_src_water) * water)

    if normalize_to_src:
        spec_src = gauss * spec_src * spec_src_conj / spec_src_water
        rf_src = ifft(spec_src, nfft)[:N]
        #i1 = int((tshift-1)*sampling_rate)
        #i2 = int((tshift+1)*sampling_rate)
        norm = 1 / max(rf_src)
        rf_src = norm * rf_src

    flag = False
    if not isinstance(rsp_list, (list, tuple)):
        flag = True
        rsp_list = [rsp_list]
    rf_list = [
        ifft(gauss * fft(rsp, nfft) * spec_src_conj / spec_src_water, nfft)[:N]
        for rsp in rsp_list
    ]
    if normalize:
        if not normalize_to_src:
            norm = 1. / max(rf_list[0])
        for rf in rf_list:
            rf *= norm
    if returnall:
        if not normalize_to_src:
            spec_src = gauss * spec_src * spec_src_conj / spec_src_water
            rf_src = ifft(spec_src, nfft)[:N]
            norm = 1 / max(rf_src)
            rf_src = norm * rf_src
        return rf_list, rf_src, spec_src_conj, spec_src_water, freq, gauss, norm, N, nfft
    elif flag:
        return rf
    else:
        return rf_list
示例#29
0
文件: xcorr.py 项目: iceseismic/sito
def xcorrf(data1, data2, shift=None, shift_zero=0, oneside=False,
           demean=True, window=0, ndat1d=0, ndat2d=0, N1=None, N2=None,
           normalize=True,
           freq_domain=False, transform_back=True,
           stdev1=None, stdev2=None):
    """
    Cross-correlation of numpy arrays data1 and data2 in frequency domain.
    

    We define cross-corelation as:
    xcorr[i] = sum_j (tr1[i+j-shift_zero] * tr2[j])
    The data is demeaned before cross-correlation and the result normalized
    after cross-correlation.

    data1, data2: data
    shift:    maximum samples to shift
              (window for i in the above formula)
    shift_zero: shift tr1 before cross-correlation by this amount of samples to
              the right (this means correlation function is shifted to the
              right or better: the window of what you get of the function
              is shifted to the left)
    oneside:  if True only the right/positive side of the correlation function
              is returned. Overrides parameter shift_zero.
    demean:   if True demean data beforehand
    normalize: if True normalize correlation function
              (1 means perfect correlation)
    window:   Use only data in this window for demeaning and normalizing
              0: window = min(ndat1, ndat2)
              >0: window = this parameter
    ndat1d, ndat2d: If >0 use different values for the length of the arrays when
              calculating the mean (defaults to window parameter)
    return:   numpy array with correlation function of length 2*shift+1 for
              oneside=False and of length shift+1 for oneside=True
    """
    if freq_domain and not transform_back:
        return data1 * np.conjugate(data2)
    elif freq_domain:
        min_size = max(2 * shift + 1 + abs(shift_zero),
                       (N1 + N2) // 2 + shift + abs(shift_zero))
        if len(data1) < min_size:
            raise ValueError('NFFT was not large enough to cover the desired '
                          'xcorr!\nnfft: %d, required minimum: %d' %
                          (len(data1), min_size))
        ret = (ifft(data1 * np.conjugate(data2))).real
    else:
        complex_result = (data1.dtype == np.complex or
                          data2.dtype == np.complex)
        N1 = len(data1)
        N2 = len(data2)
        #if isinstance(data1[0], np.integer) or isinstance(data2[0], np.integer):
        data1 = data1.astype('float64')
        data2 = data2.astype('float64')
        #if (N1-N2)%2==1:
        #    raise ValueError('(N1-N2)%2 has to be 0')
        if window == 0:
            window = min(N1, N2)
        if ndat1d == 0:
            ndat1d = window
        if ndat2d == 0:
            ndat2d = window
        # determine indices for demeaning and normalization
        ind1 = max(0, (N1 - window) // 2)
        ind2 = min(N1, (N1 + window) // 2)
        ind3 = max(0, (N2 - window) // 2)
        ind4 = min(N2, (N2 + window) // 2)

        # demean and normalize data
        if demean:
            data1 -= np.sum(data1[ind1:ind2]) / ndat1d
            data2 -= np.sum(data2[ind3:ind4]) / ndat2d
        if normalize:
            data1 /= np.max(data1[ind1:ind2])
            data2 /= np.max(data2[ind3:ind4])

        # Always use 2**n-sized FFT, perform xcorr
        size = max(2 * shift + 1 + abs(shift_zero),
                   (N1 + N2) // 2 + shift + abs(shift_zero))
        nfft = nextpow2(size)
        IN1 = fft(data1, nfft)
        if USE_FFTW3:
            IN1 = IN1.copy()
        IN1 *= np.conjugate(fft(data2, nfft))
        ret = ifft(IN1)
        if not USE_FFTW3:
            del IN1
        if not complex_result:
            ret = ret.real
    # shift data for time lag 0 to index 'shift'

    ret = np.roll(ret, -(N1 - N2) // 2 + shift + shift_zero)[:2 * shift + 1]
    # normalize xcorr
    if normalize:
        if not freq_domain:
            stdev1 = (np.sum(data1[ind1:ind2] ** 2)) ** 0.5
            stdev2 = (np.sum(data2[ind3:ind4] ** 2)) ** 0.5
#            stdev1 = (np.sum(data1 ** 2)) ** 0.5
#            stdev2 = (np.sum(data2 ** 2)) ** 0.5
        if stdev1 == 0 or stdev2 == 0:
            log.warning('Data is zero!!')
            ret[:] = 0.
        else:
            ret /= stdev1 * stdev2
    if oneside:
        ret = ret[shift:]
    return np.copy(ret)
示例#30
0
文件: invsim.py 项目: shineusn/obspy
def seisSim(data,
            samp_rate,
            paz_remove=None,
            paz_simulate=None,
            remove_sensitivity=True,
            simulate_sensitivity=True,
            water_level=600.0,
            zero_mean=True,
            taper=True,
            taper_fraction=0.05,
            pre_filt=None,
            seedresp=None,
            nfft_pow2=False,
            pitsasim=True,
            sacsim=False,
            shsim=False,
            **_kwargs):
    """
    Simulate/Correct seismometer.

    :type data: NumPy ndarray
    :param data: Seismogram, detrend before hand (e.g. zero mean)
    :type samp_rate: Float
    :param samp_rate: Sample Rate of Seismogram
    :type paz_remove: Dictionary, None
    :param paz_remove: Dictionary containing keys 'poles', 'zeros', 'gain'
        (A0 normalization factor). poles and zeros must be a list of complex
        floating point numbers, gain must be of type float. Poles and Zeros are
        assumed to correct to m/s, SEED convention. Use None for no inverse
        filtering.
    :type paz_simulate: Dictionary, None
    :param paz_simulate: Dictionary containing keys 'poles', 'zeros', 'gain'.
        Poles and zeros must be a list of complex floating point numbers, gain
        must be of type float. Or None for no simulation.
    :type remove_sensitivity: Boolean
    :param remove_sensitivity: Determines if data is divided by
        `paz_remove['sensitivity']` to correct for overall sensitivity of
        recording instrument (seismometer/digitizer) during instrument
        correction.
    :type simulate_sensitivity: Boolean
    :param simulate_sensitivity: Determines if data is multiplied with
        `paz_simulate['sensitivity']` to simulate overall sensitivity of
        new instrument (seismometer/digitizer) during instrument simulation.
    :type water_level: Float
    :param water_level: Water_Level for spectrum to simulate
    :type zero_mean: Boolean
    :param zero_mean: If true the mean of the data is subtracted
    :type taper: Boolean
    :param taper: If true a cosine taper is applied.
    :type taper_fraction: Float
    :param taper_fraction: Taper fraction of cosine taper to use
    :type pre_filt: List or tuple of floats
    :param pre_filt: Apply a bandpass filter to the data trace 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 seedresp: Dictionary, None
    :param seedresp: Dictionary contains keys 'filename', 'date', 'units'.
        'filename' is the path to a RESP-file generated from a dataless SEED
        volume (or a file like object with RESP information);
        'date' is a `~obspy.core.utcdatetime.UTCDateTime` object for the date
        that the response function should be extracted for (can be omitted when
        calling simulate() on Trace/Stream. the Trace's starttime will then be
        used);
        'units' defines the units of the response function.
        Can be either 'DIS', 'VEL' or 'ACC'.
    :type nfft_pow2: Boolean
    :param nfft_pow2: Number of frequency points to use for FFT. If True,
        the exact power of two is taken (default in PITSA). If False the
        data are not zeropadded to the next power of two which makes a
        slower FFT but is then much faster for e.g. evalresp which scales
        with the FFT points.
    :type pitsasim: Boolean
    :param pitsasim: Choose parameters to match
        instrument correction as done by PITSA.
    :type sacsim: Boolean
    :param sacsim: Choose parameters to match
        instrument correction as done by SAC.
    :type shsim: Boolean
    :param shsim: Choose parameters to match
        instrument correction as done by Seismic Handler.
    :return: The corrected data are returned as numpy.ndarray float64
        array. float64 is chosen to avoid numerical instabilities.

    This function works in the frequency domain, where nfft is the next power
    of len(data) to avoid wrap around effects during convolution. The inverse
    of the frequency response of the seismometer (``paz_remove``) is
    convolved with the spectrum of the data and with the frequency response
    of the seismometer to simulate (``paz_simulate``). A 5% cosine taper is
    taken before simulation. The data must be detrended (e.g.) zero mean
    beforehand. If paz_simulate=None only the instrument correction is done.
    In the latter case, a broadband filter can be applied to the data trace
    using pre_filt. This restricts the signal to the valid frequency band and
    thereby avoids artefacts due to amplification of frequencies outside of the
    instrument's passband (for a detailed discussion see
    *Of Poles and Zeros*, F. Scherbaum, Kluwer Academic Publishers).

    .. versionchanged:: 0.5.1
        The default for `remove_sensitivity` and `simulate_sensitivity` has
        been changed to ``True``. Old deprecated keyword arguments `paz`,
        `inst_sim`, `no_inverse_filtering` have been removed.
    """
    # Checking the types
    if not paz_remove and not paz_simulate and not seedresp:
        msg = "Neither inverse nor forward instrument simulation specified."
        raise TypeError(msg)

    for d in [paz_remove, paz_simulate]:
        if d is None:
            continue
        for key in ['poles', 'zeros', 'gain']:
            if key not in d:
                raise KeyError("Missing key: %s" % key)
    # Translated from PITSA: spr_resg.c
    delta = 1.0 / samp_rate
    #
    ndat = len(data)
    data = data.astype("float64")
    if zero_mean:
        data -= data.mean()
    if taper:
        if sacsim:
            data *= cosTaper(ndat,
                             taper_fraction,
                             sactaper=sacsim,
                             halfcosine=False)
        else:
            data *= cosTaper(ndat, taper_fraction)
    # The number of points for the FFT has to be at least 2 * ndat (in
    # order to prohibit wrap around effects during convolution) cf.
    # Numerical Recipes p. 429 calculate next power of 2.
    if nfft_pow2:
        nfft = util.nextpow2(2 * ndat)
    # evalresp scales directly with nfft, therefore taking the next power of
    # two has a greater negative performance impact than the slow down of a
    # not power of two in the FFT
    else:
        nfft = _npts2nfft(ndat)
    # Transform data in Fourier domain
    data = np.fft.rfft(data, n=nfft)
    # Inverse filtering = Instrument correction
    if paz_remove:
        freq_response, freqs = pazToFreqResp(paz_remove['poles'],
                                             paz_remove['zeros'],
                                             paz_remove['gain'],
                                             delta,
                                             nfft,
                                             freq=True)
    if seedresp:
        freq_response, freqs = evalresp(delta,
                                        nfft,
                                        seedresp['filename'],
                                        seedresp['date'],
                                        units=seedresp['units'],
                                        freq=True,
                                        network=seedresp['network'],
                                        station=seedresp['station'],
                                        locid=seedresp['location'],
                                        channel=seedresp['channel'])
        if not remove_sensitivity:
            msg = "remove_sensitivity is set to False, but since seedresp " + \
                  "is selected the overall sensitivity will be corrected " + \
                  " for anyway!"
            warnings.warn(msg)
    if paz_remove or seedresp:
        if pre_filt:
            # make cosine taper
            fl1, fl2, fl3, fl4 = pre_filt
            if sacsim:
                cos_win = c_sac_taper(freqs, flimit=(fl1, fl2, fl3, fl4))
            else:
                cos_win = cosTaper(freqs.size,
                                   freqs=freqs,
                                   flimit=(fl1, fl2, fl3, fl4))
            data *= cos_win
        specInv(freq_response, water_level)
        data *= freq_response
        del freq_response
    # Forward filtering = Instrument simulation
    if paz_simulate:
        data *= pazToFreqResp(paz_simulate['poles'], paz_simulate['zeros'],
                              paz_simulate['gain'], delta, nfft)

    data[-1] = abs(data[-1]) + 0.0j
    # transform data back into the time domain
    data = np.fft.irfft(data)[0:ndat]
    if pitsasim:
        # linear detrend
        data = simpleDetrend(data)
    if shsim:
        # detrend using least squares
        data = scipy.signal.detrend(data, type="linear")
    # correct for involved overall sensitivities
    if paz_remove and remove_sensitivity and not seedresp:
        data /= paz_remove['sensitivity']
    if paz_simulate and simulate_sensitivity:
        data *= paz_simulate['sensitivity']
    return data
示例#31
0
def CalcResp(poles, zeros, scaleFac, MaxPer, sampfreq):
    ndat = MaxPer * sampfreq
    nfft = nextpow2(ndat)
    buffer = np.empty(nfft/2+1, dtype='complex128')
#    poles = []
#    zeros = []
#    file = open(str(pazFile), 'r')
#
#    # read file until calibration section is found
#    text = ' '
#    while text != 'CAL1':
#        textln = file.readline()
#        text = textln.split(' ')[0]
#    if not text == 'CAL1':
#        msg = 'could not find calibration section!'
#        raise NameError(msg)
#    else:
#        cal = textln[31:34]
#    if cal == 'PAZ':
#        # read poles
#        npoles = int(file.readline())
#        for i in xrange(npoles):
#            pole = file.readline()
#            pole_r = float(pole.split(" ")[0])
#            pole_i = float(pole.split(" ")[1])
#            pole_c = pole_r + pole_i * 1.j
#            poles.append(pole_c)
#        # read zeros
#        nzeros = int(file.readline())
#        for i in xrange(nzeros):
#            zero = file.readline()
#            zero_r = float(zero.split(" ")[0])
#            zero_i = float(zero.split(" ")[1])
#            zero_c = zero_r + zero_i * 1.j
#            zeros.append(zero_c)
#        # read scale factor
#        scale_fac = float(file.readline())
#        file.close
        
    scale_fac = scaleFac

    # calculate transfer function
    delta_f = sampfreq / nfft
    F = np.empty(nfft/2+1)
    for i in xrange(nfft/2 + 1):
        fr = i * delta_f
        F[i] = fr
        om = 2 * np.pi * fr
        num = 1. + 0.j
        
        for ii in xrange(len(zeros)):
            s = 0. + om * 1.j
            dif = s - zeros[ii]
            num = dif * num

        denom = 1. + 0.j
        for ii in xrange(len(poles)):
            s = 0. + om * 1.j
            dif = s - poles[ii]
            denom = dif * denom

        t_om = 1. + 0.j
        if denom.real != 0. or denom.imag != 0.:
            t_om = num / denom
        
        t_om *= scale_fac
       
        if i < nfft/2 and i > 0:
            buffer[i] = t_om

        if i == 0:
            buffer[i] = t_om + 0.j
    
        if i == nfft/2:
            buffer[i] = t_om + 0.j

# plot
    amp = abs(buffer)
    phase = np.arctan(buffer.imag / buffer.real) / np.pi * 180
    
    # Plot
    fig = plt.figure()
    ax1 = plt.subplot(211)
    ax1.loglog(F, amp)
    ax1.set_ylabel('Amplitude')
        
    ax2 = plt.subplot(212)
    ax2.semilogx(F, phase)
    ax2.set_xlabel('Frequenzy [Hz]')
    ax2.set_ylabel('Phase')
        
    plt.show()
示例#32
0
def relcalstack(st1, st2, calib_file, window_len, OverlapFrac=0.5, smooth=0):
    """
    Method for relative calibration of sensors using a sensor with known transfer function

    :param st1/st2: Stream object, (known/unknown) the trace.stats dict like class must contain \
                    the parameters "sampling_rate", "npts" and "station"
    :type calib_file: String
    :param calib_file: name of calib file containing the known PAZ of known instrument in GSE2 standard.
    :type window_len: Float
    :param window_len: length of sliding window in seconds
    :type OverlapFrac: float
    :param OverlapFrac: fraction of overlap, defaults to fifty percent (0.5)
    :type smooth: Float
    :param smooth: variable that defines if the Konno-Ohmachi taper is used or not. default = 0 -> no taper \
                    generally used in geopsy: smooth = 40
    """
    # check Konno-Ohmachi
    if smooth < 0:
        smooth = 0
                                                                   
    # check if sampling rate and trace length is the same
    if st1[0].stats.npts != st2[0].stats.npts:
        msg = 'Traces dont have the same length!'
        raise ValueError(msg)
    elif st1[0].stats.sampling_rate != st2[0].stats.sampling_rate:
        msg = 'Traces dont have the same sampling rate!'
        raise ValueError(msg)
    else:
        ndat1 = st1[0].stats.npts
        ndat2 = st2[0].stats.npts
        sampfreq = st1[0].stats.sampling_rate

    # read waveforms
    tr1 = st1[0].data.astype(np.float64)
    tr2 = st2[0].data.astype(np.float64)
                                                 
    # get window length, nfft and frequency step
    ndat = int(window_len*sampfreq)
    nfft = nextpow2(ndat)
    df = sampfreq / nfft

    # initialize array for response function
    res = np.zeros(nfft/2+1, dtype='complex128')

    # read calib file and calculate response function
    gg, freq = calcresp(calib_file, nfft, sampfreq)

    # calculate number of windows and overlap
    nwin = int(np.floor((ndat1 - nfft)/(nfft/2)) + 1)
    noverlap = nfft * OverlapFrac

    auto, freq, t = spectral_helper(tr1, tr1, NFFT=nfft, Fs=sampfreq, noverlap = noverlap)
    cross, freq, t = spectral_helper(tr1, tr2, NFFT=nfft, Fs=sampfreq, noverlap = noverlap)
    
    # 180 Grad Phasenverschiebung
    cross.imag = -cross.imag

    for i in range(nwin): 
        res += (cross[:,i] / auto[:,i]) * gg
    
    # apply Konno-Ohmachi smoothing taper if choosen
    if smooth > 0:
        res /= nwin                             

        res.real = smooth_spectra(res.real, freq, smooth, count=1, max_memory_in_mb=1024)
        res.imag = smooth_spectra(res.imag, freq, smooth, count=1, max_memory_in_mb=1024) 

    else:
        res /= nwin

    #print 'Writing output....'
                                                                                  
    f = open(st2[0].stats.station+"."+str(window_len)+".resp", "w")
    g = open(st1[0].stats.station+".refResp", "w")

    amp = []
    phase = []

    for i in range(nfft/2+1):

        a = np.sqrt(res.real[i]*res.real[i]+res.imag[i]*res.imag[i]) 
        pha = np.arctan2(res.imag[i],res.real[i])
        ra = np.sqrt(gg.real[i]*gg.real[i]+gg.imag[i]*gg.imag[i])
        rpha = np.arctan2(gg.imag[i],gg.real[i])
        amp.append(a)
        phase.append(pha)
        f.write("%f %f %f\n" %(freq[i], a, pha))
        g.write("%f %f %f\n" %(freq[i], ra, rpha))

    f.close()
    g.close()

    return freq, amp, phase
示例#33
0
def deconvf(rsp_list, src, sampling_rate, water=0.05, gauss=2., tshift=10.,
            pad=0, length=None, normalize=True, normalize_to_src=False,
            return_dict=False):
    """
    Frequency-domain deconvolution using waterlevel method.

    Deconvolve src from arrays in rsp_list.

    :param rsp_list: either a list of arrays containing the response functions
        or a single array
    :param src: array of source function
    :param sampling_rate: sampling rate of the data
    :param water: waterlevel to stabilize the deconvolution
    :param gauss: Gauss parameter of Low-pass filter
    :param tshift: delay time 0s will be at time tshift afterwards
    :param pad: multiply number of samples used for fft by 2**pad
    :param length: number of data points in results, optional
    :param normalize: if results are normalized
    :param normalize_to_src: True ->  normalized so that the maximum of a
        deconvolution of the source with itself is 1\n
        False -> normalized so that the maximum of the deconvolution of the
        first response array in rsp_list is 1
    :param return_dict: return additionally a lot of different parameters in a
        dict for debugging purposes

    :return: (list of) array(s) with deconvolution(s)
    """
    if length is None:
        length = len(src)
    N = length
    nfft = nextpow2(N) * 2 ** pad
    freq = np.fft.fftfreq(nfft, d=1. / sampling_rate)
    gauss = np.exp(np.maximum(-(0.5 * 2 * pi * freq / gauss) ** 2, -700.) -
                   1j * tshift * 2 * pi * freq)

    spec_src = fft(src, nfft)
    spec_src_conj = np.conjugate(spec_src)
    spec_src_water = np.abs(spec_src * spec_src_conj)
    spec_src_water = np.maximum(spec_src_water, max(spec_src_water) * water)

    if normalize_to_src:
        spec_src = gauss * spec_src * spec_src_conj / spec_src_water
        rf_src = ifft(spec_src, nfft)[:N]
        norm = 1 / max(rf_src)
        rf_src = norm * rf_src

    flag = False
    if not isinstance(rsp_list, (list, tuple)):
        flag = True
        rsp_list = [rsp_list]
    rf_list = [ifft(gauss * fft(rsp, nfft) * spec_src_conj / spec_src_water,
                    nfft)[:N] for rsp in rsp_list]
    if normalize:
        if not normalize_to_src:
            norm = 1. / max(rf_list[0])
        for rf in rf_list:
            rf *= norm
    if return_dict:
        if not normalize_to_src:
            spec_src = gauss * spec_src * spec_src_conj / spec_src_water
            rf_src = ifft(spec_src, nfft)[:N]
            norm = 1 / max(rf_src)
            rf_src = norm * rf_src
        ret_dict = {'rf_src': rf_src, 'rf_src_conj': spec_src_conj,
                    'spec_src_water': spec_src_water, 'freq': freq,
                    'gauss': gauss, 'norm': norm, 'N': N, 'nfft': nfft}
        return rf_list, ret_dict
    elif flag:
        return rf
    else:
        return rf_list
示例#34
0
文件: xcorr.py 项目: wangwu1991/sito
def xcorrf(data1,
           data2,
           shift=None,
           shift_zero=0,
           oneside=False,
           demean=True,
           window=0,
           ndat1d=0,
           ndat2d=0,
           N1=None,
           N2=None,
           normalize=True,
           freq_domain=False,
           transform_back=True,
           stdev1=None,
           stdev2=None):
    """
    Cross-correlation of numpy arrays data1 and data2 in frequency domain.
    

    We define cross-corelation as:
    xcorr[i] = sum_j (tr1[i+j-shift_zero] * tr2[j])
    The data is demeaned before cross-correlation and the result normalized
    after cross-correlation.

    data1, data2: data
    shift:    maximum samples to shift
              (window for i in the above formula)
    shift_zero: shift tr1 before cross-correlation by this amount of samples to
              the right (this means correlation function is shifted to the
              right or better: the window of what you get of the function
              is shifted to the left)
    oneside:  if True only the right/positive side of the correlation function
              is returned. Overrides parameter shift_zero.
    demean:   if True demean data beforehand
    normalize: if True normalize correlation function
              (1 means perfect correlation)
    window:   Use only data in this window for demeaning and normalizing
              0: window = min(ndat1, ndat2)
              >0: window = this parameter
    ndat1d, ndat2d: If >0 use different values for the length of the arrays when
              calculating the mean (defaults to window parameter)
    return:   numpy array with correlation function of length 2*shift+1 for
              oneside=False and of length shift+1 for oneside=True
    """
    if freq_domain and not transform_back:
        return data1 * np.conjugate(data2)
    elif freq_domain:
        min_size = max(2 * shift + 1 + abs(shift_zero),
                       (N1 + N2) // 2 + shift + abs(shift_zero))
        if len(data1) < min_size:
            raise ValueError('NFFT was not large enough to cover the desired '
                             'xcorr!\nnfft: %d, required minimum: %d' %
                             (len(data1), min_size))
        ret = (ifft(data1 * np.conjugate(data2))).real
    else:
        complex_result = (data1.dtype == np.complex
                          or data2.dtype == np.complex)
        N1 = len(data1)
        N2 = len(data2)
        #if isinstance(data1[0], np.integer) or isinstance(data2[0], np.integer):
        data1 = data1.astype('float64')
        data2 = data2.astype('float64')
        #if (N1-N2)%2==1:
        #    raise ValueError('(N1-N2)%2 has to be 0')
        if window == 0:
            window = min(N1, N2)
        if ndat1d == 0:
            ndat1d = window
        if ndat2d == 0:
            ndat2d = window
        # determine indices for demeaning and normalization
        ind1 = max(0, (N1 - window) // 2)
        ind2 = min(N1, (N1 + window) // 2)
        ind3 = max(0, (N2 - window) // 2)
        ind4 = min(N2, (N2 + window) // 2)

        # demean and normalize data
        if demean:
            data1 -= np.sum(data1[ind1:ind2]) / ndat1d
            data2 -= np.sum(data2[ind3:ind4]) / ndat2d
        if normalize:
            data1 /= np.max(data1[ind1:ind2])
            data2 /= np.max(data2[ind3:ind4])

        # Always use 2**n-sized FFT, perform xcorr
        size = max(2 * shift + 1 + abs(shift_zero),
                   (N1 + N2) // 2 + shift + abs(shift_zero))
        nfft = nextpow2(size)
        IN1 = fft(data1, nfft)
        if USE_FFTW3:
            IN1 = IN1.copy()
        IN1 *= np.conjugate(fft(data2, nfft))
        ret = ifft(IN1)
        if not USE_FFTW3:
            del IN1
        if not complex_result:
            ret = ret.real
    # shift data for time lag 0 to index 'shift'

    ret = np.roll(ret, -(N1 - N2) // 2 + shift + shift_zero)[:2 * shift + 1]
    # normalize xcorr
    if normalize:
        if not freq_domain:
            stdev1 = (np.sum(data1[ind1:ind2]**2))**0.5
            stdev2 = (np.sum(data2[ind3:ind4]**2))**0.5


#            stdev1 = (np.sum(data1 ** 2)) ** 0.5
#            stdev2 = (np.sum(data2 ** 2)) ** 0.5
        if stdev1 == 0 or stdev2 == 0:
            log.warning('Data is zero!!')
            ret[:] = 0.
        else:
            ret /= stdev1 * stdev2
    if oneside:
        ret = ret[shift:]
    return np.copy(ret)
示例#35
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 = nextpow2(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 spead up the routine a bit we estimate all steering vectors in advance
    steer = np.empty((nf, grdpts_x, grdpts_y, nstat), dtype='c16')
    clibsignal.calcSteer(nstat, grdpts_x, grdpts_y, nf, nlow,
                         deltaf, time_shift_table, steer)
    R = np.empty((nf, nstat, nstat), dtype='c16')
    ft = np.empty((nstat, nf), dtype='c16')
    newstart = stime
    tap = cosTaper(nsamp, p=0.22)  # 0.22 matches 0.2 of historical C bbfk.c
    offset = 0
    relpow_map = np.empty((grdpts_x, grdpts_y), dtype='f8')
    abspow_map = np.empty((grdpts_x, grdpts_y), dtype='f8')
    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.require(ft, 'c16', ['C_CONTIGUOUS'])
        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':
        # 719162 == hours between 1970 and 0001
        res[:, 0] = res[:, 0] / (24. * 3600) + 719162
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
示例#36
0
def mtinv_gs(st_tr,
             gl,
             fmin,
             fmax,
             fmax_hardcut_factor=4,
             S0=None,
             nsv=1,
             single_force=False,
             stat_subset=[],
             weighting_type=2,
             weights=[],
             cache_path='',
             force_recalc=False,
             cache=False,
             w_level=50):
    '''
    Frequency domain moment tensor inversion.

    Features:
     - grid search for best source location
     - direct inversion for different error measures (see weighting type)
     - constrain to limited number of source mechanisms/time dependencies using
       principal component analysis
     - deconvolution of source time function used for Green's function
       simulations
     - caching the Green's matrix in Frequency space for speed up of repeated
       evaluation

    Theory see Diplomathesis 'The Effect of Tilt on Moment Tensor Inversion in
    the Nearfield of Active Volcanoes' section 2.2

    :type st_tr: :class:`~obspy.core.stream.Stream`
    :param st_tr: Stream containing the seismograms, station names are numbers
        starting with 0001, channels are ['u', 'v', 'w']
    :type gl: list of :class:`~obspy.core.stream.Stream` objects or list
    :param gl: list of Streams containing the green's functions, station names
        are numbers starting with 0001, channels are of format '%02d%1d' where
        the first number is the component of the receiver ([0,1,2]) and the
        second the source ([0,1,...,5] or [0,1,...,8] including single forces).
        Should have the same sample rate as st_tr. If no grid search is needed,
        just put a single stream in the list.
        In case of a high number of stations (>250), gl can be a list of 
        strings containing the path to and names of the greens functions files
    :type fmin: float
    :param fmin: high pass frequency
    :type fmax: float
    :param fmax: low pass frequency
    :type fmax_hardcut_factor: int
    :param fmax_hardcut_factor: multiple of fmax where the inversion is stopped
    :type S0: :class:`numpy.ndarray`
    :param S0: source time function used for computation of the Green's
        function to deconvolve. Is assumed to have same sample rate as st_tr.
        If S0 is None, no deconvolution is performed.
    :type nsv: int
    :param nsv: number of mechanisms corresponding to the largest singular
        values in the constrained inversion
    :type single_force: Bool
    :param single_force: include single force in the inversion (then green's
        functions for single forces are needed in channels ([6,7,8]))
    :type stat_subset: List
    :param stat_subset: List of stations to use in the inversion
    :type weighting: int
    :param weighting_type: should be one of [0,1,2], 0: no weighting, 1: use l2
        norm weighting for each trace, 2: use l2 norm weighting for each
        station (weight is sum of the weights of the traces)
    :type weights: listtype
    :param weights: a priori relative weighting of stations, should have length
        nstat or same length as stat_subset
    :type cache_path: string
    :param cache_path: path to a folder to cache Green's matrix
    :type force_recalc: Bool
    :param force_recalc: force reevalution of fourier transform of
        Green's functions (if cached in 'cache_path' to speed up inversion).
    :type cache: Bool
    :param cache: cache in a file or not
    :type w_level: int
    :param w_level: value of waterlevel in dB under max amplitude in spectrum
        of deconvolved Green's function

    returns a tuple containing:
        M_t     - time dependent Momenttensor solution (if nsv > 1 than summed
                  up mechanisms)
        m       - time independent Momenttensor (nsv arrays)
        x       - time dependence of principal component solutions in m
        s       - singular values of principal components
        st_syn  - synthetic seismograms generated with the inverted source
        st_tr   - input seismograms filtered the same way as the synthetics
                  (for comparison to synthetic seismograms)
        misfit  - misfit of synthetics, definition depends on weighting
                  (is only mathematically strict minimized for nsv=6  (9 in
                  case of single force), otherwise approximately)
        argmin  - index of Green's function in list that minimizes the misfit
    '''
    st_tr = st_tr.copy()
    st_tr.filter('lowpass', freq=fmax, corners=4)
    st_tr.filter('highpass', freq=fmin, corners=4)

    # test if gl is a list or a stream
    if type(gl[0]) == str:
        st_g = read('%s' % (gl[0]))
    else:
        st_g = gl[0]

    ng = st_g[0].data.size

    df = st_tr[0].stats.sampling_rate
    dt = 1. / df

    nstat = st_tr.select(channel='u').count()
    ndat = st_tr[0].data.size
    nfft = nextpow2(max(ndat, ng) * 2)

    # use freuquncies below corner frequency * fmax_hardcut_factor (tremendous
    # speed up in inversion)
    nfinv = int(fmax_hardcut_factor * fmax / (df / 2.) * nfft)
    nfinv = min(nfft / 2 + 1, nfinv)

    # going to frequency domain

    # correction for stf used in green's forward simulation
    if S0 is None:
        S0w = 1.
    else:
        S0w = np.fft.rfft(S0, n=nfft)[:nfinv] * dt

        # introduce waterlevel to prevent instabilities in deconvolution of
        # greens functions, see obspy.signal.invsim specInv

        # Calculated waterlevel in the scale of spec
        swamp = waterlevel(S0w, w_level)
        # Find length in real fft frequency domain, spec is complex
        sqrt_len = np.abs(S0w)
        # Set/scale length to swamp, but leave phase untouched
        # 0 sqrt_len will transform in np.nans when dividing by it
        idx = np.where((sqrt_len < swamp) & (sqrt_len > 0.0))
        S0w[idx] *= swamp / sqrt_len[idx]

    # setup seismogram matrix in fourier space
    utr = np.zeros((nstat * 3, ndat))
    utrw = np.zeros((nstat * 3, nfft / 2 + 1)) * 0j
    weights_l2 = np.zeros(nstat * 3)

    for k in np.arange(nstat):
        for i, chan in enumerate(['u', 'v', 'w']):
            utr[k * 3 + i, :] = st_tr.select(station='%04d' % (k + 1),
                                             channel=chan)[0].data
            utrw[k * 3 + i, :] = np.fft.rfft(utr[k * 3 + i, :], n=nfft) * dt
            # calculate l2 norm for weighting
            weights_l2[k * 3 + i] = cumtrapz(utr[k * 3 + i, :]**2, dx=dt)[-1]

    M_tl = []
    ml = []
    xl = []
    sl = []
    st_synl = []
    #misfitl = []
    misfitarg = []
    min_misfit = 1e6

    st_tr.filter('lowpass', freq=fmax, corners=4)

    for i, stg in enumerate(gl):
        if type(stg) == str:
            st_g = read('%s' % (stg))
            print 'Working on %s ' % stg
        else:
            st_g = stg

        if round(st_tr[0].stats.sampling_rate, 5) != round(
                st_g[0].stats.sampling_rate, 5):
            msg = 'sampling rates of Seismograms and Green\'s function are not the'
            msg = msg + ' same: %f != %f' % (st_tr[0].stats.sampling_rate,
                                             st_g[0].stats.sampling_rate)
            raise ValueError(msg)

        M_t, m, x, s, st_syn, misfit = mtinv(
            (utrw, weights_l2.copy(), S0w, df, dt, nstat, ndat, ng, nfft,
             nfinv),
            st_tr,
            st_g,
            fmin,
            fmax,
            nsv=nsv,
            single_force=single_force,
            stat_subset=stat_subset,
            force_recalc=force_recalc,
            weighting_type=weighting_type,
            weights=weights,
            cache_path=cache_path + ('%06d_' % i),
            cache=cache)

        if misfit < min_misfit:
            min_misfit = misfit

            M_tl = M_t
            ml = m
            xl = x
            sl = s
            st_synl = st_syn
            misfitl = misfit
            argmin = i

        else:
            pass

            #M_tl.append(M_t)
            #ml.append(m)
            #xl.append(x)
            #sl.append(s)
            #st_synl.append(st_syn)
            #misfitl.append(misfit)

        #del st_g, st_syn, M_t, m, x, s, misfit

    #misfit = np.array(misfitl)
    #argmin = misfit.argmin()

    return M_tl, ml, xl, sl, st_synl, st_tr, misfitl, argmin
示例#37
0
def deconvf(rsp_list,
            src,
            sampling_rate,
            water=0.05,
            gauss=2.,
            tshift=10.,
            pad=0,
            length=None,
            normalize=True,
            normalize_to_src=False,
            return_dict=False):
    """
    Frequency-domain deconvolution using waterlevel method.

    Deconvolve src from arrays in rsp_list.

    :param rsp_list: either a list of arrays containing the response functions
        or a single array
    :param src: array of source function
    :param sampling_rate: sampling rate of the data
    :param water: waterlevel to stabilize the deconvolution
    :param gauss: Gauss parameter of Low-pass filter
    :param tshift: delay time 0s will be at time tshift afterwards
    :param pad: multiply number of samples used for fft by 2**pad
    :param length: number of data points in results, optional
    :param normalize: if results are normalized
    :param normalize_to_src: True ->  normalized so that the maximum of a
        deconvolution of the source with itself is 1\n
        False -> normalized so that the maximum of the deconvolution of the
        first response array in rsp_list is 1
    :param return_dict: return additionally a lot of different parameters in a
        dict for debugging purposes

    :return: (list of) array(s) with deconvolution(s)
    """
    if length is None:
        length = len(src)
    N = length
    nfft = nextpow2(N) * 2**pad
    freq = np.fft.fftfreq(nfft, d=1. / sampling_rate)
    gauss = np.exp(
        np.maximum(-(0.5 * 2 * pi * freq / gauss)**2, -700.) -
        1j * tshift * 2 * pi * freq)

    spec_src = fft(src, nfft)
    spec_src_conj = np.conjugate(spec_src)
    spec_src_water = np.abs(spec_src * spec_src_conj)
    spec_src_water = np.maximum(spec_src_water, max(spec_src_water) * water)

    if normalize_to_src:
        spec_src = gauss * spec_src * spec_src_conj / spec_src_water
        rf_src = ifft(spec_src, nfft)[:N]
        norm = 1 / max(rf_src)
        rf_src = norm * rf_src

    flag = False
    if not isinstance(rsp_list, (list, tuple)):
        flag = True
        rsp_list = [rsp_list]
    rf_list = [
        ifft(gauss * fft(rsp, nfft) * spec_src_conj / spec_src_water, nfft)[:N]
        for rsp in rsp_list
    ]
    if normalize:
        if not normalize_to_src:
            norm = 1. / max(rf_list[0])
        for rf in rf_list:
            rf *= norm
    if return_dict:
        if not normalize_to_src:
            spec_src = gauss * spec_src * spec_src_conj / spec_src_water
            rf_src = ifft(spec_src, nfft)[:N]
            norm = 1 / max(rf_src)
            rf_src = norm * rf_src
        ret_dict = {
            'rf_src': rf_src,
            'rf_src_conj': spec_src_conj,
            'spec_src_water': spec_src_water,
            'freq': freq,
            'gauss': gauss,
            'norm': norm,
            'N': N,
            'nfft': nfft
        }
        return rf_list, ret_dict
    elif flag:
        return rf
    else:
        return rf_list
示例#38
0
def relcalstack(st1, st2, calib_file, window_len, overlap_frac=0.5, smooth=0,
                save_data=True):
    """
    Method for relative calibration of sensors using a sensor with known
    transfer function

    :param st1: Stream or Trace object, (known)
    :param st2: Stream or Trace object, (unknown)
    :type calib_file: String
    :param calib_file: file name of calibration file containing the PAZ of the
        known instrument in GSE2 standard.
    :type window_len: Float
    :param window_len: length of sliding window in seconds
    :type overlap_frac: float
    :param overlap_frac: fraction of overlap, defaults to fifty percent (0.5)
    :type smooth: Float
    :param smooth: variable that defines if the Konno-Ohmachi taper is used or
        not. default = 0 -> no taper generally used in geopsy: smooth = 40
    :type save_data: Boolean
    :param save_data: Whether or not to save the result to a file. If True, two
        output files will be created:
        * The new response in station_name.window_length.resp
        * The ref response in station_name.refResp
        Defaults to True
    :returns: frequency, amplitude and phase spectrum

    implemented after relcalstack.c by M.Ohrnberger and J.Wassermann.
    """
    # transform given trace objects to streams
    if isinstance(st1, Trace):
        st1 = Stream([st1])
    if isinstance(st2, Trace):
        st2 = Stream([st2])
    # check if sampling rate and trace length is the same
    if st1[0].stats.npts != st2[0].stats.npts:
        msg = "Traces don't have the same length!"
        raise ValueError(msg)
    elif st1[0].stats.sampling_rate != st2[0].stats.sampling_rate:
        msg = "Traces don't have the same sampling rate!"
        raise ValueError(msg)
    else:
        ndat1 = st1[0].stats.npts
        sampfreq = st1[0].stats.sampling_rate

    # read waveforms
    tr1 = st1[0].data.astype(np.float64)
    tr2 = st2[0].data.astype(np.float64)

    # get window length, nfft and frequency step
    ndat = int(window_len * sampfreq)
    nfft = nextpow2(ndat)

    # read calib file and calculate response function
    gg, _freq = _calcresp(calib_file, nfft, sampfreq)

    # calculate number of windows and overlap
    nwin = int(np.floor((ndat1 - nfft) / (nfft / 2)) + 1)
    noverlap = nfft * overlap_frac

    auto, _freq, _t = \
        spectral_helper(tr1, tr1, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)
    cross, freq, _t = \
        spectral_helper(tr2, tr1, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)

    res = (cross / auto).sum(axis=1) * gg

    # The first item might be zero. Problems with phase calculations.
    res = res[1:]
    freq = freq[1:]
    gg = gg[1:]

    res /= nwin
    # apply Konno-Ohmachi smoothing taper if chosen
    if smooth > 0:
        # Write in one matrix for performance reasons.
        spectra = np.empty((2, len(res.real)))
        spectra[0] = res.real
        spectra[1] = res.imag
        new_spectra = \
            konnoOhmachiSmoothing(spectra, freq, bandwidth=smooth, count=1,
                                  max_memory_usage=1024, normalize=True)
        res.real = new_spectra[0]
        res.imag = new_spectra[1]

    amp = np.abs(res)
    # include phase unwrapping
    phase = np.unwrap(np.angle(res))  # + 2.0 * np.pi
    ra = np.abs(gg)
    rpha = np.unwrap(np.angle(gg))

    if save_data:
        trans_new = (st2[0].stats.station + "." + st2[0].stats.channel +
                     "." + str(window_len) + ".resp")
        trans_ref = st1[0].stats.station + ".refResp"
        # Create empty array for easy saving
        temp = np.empty((len(freq), 3))
        temp[:, 0] = freq
        temp[:, 1] = amp
        temp[:, 2] = phase
        np.savetxt(trans_new, temp, fmt="%.10f")
        temp[:, 1] = ra
        temp[:, 2] = rpha
        np.savetxt(trans_ref, temp, fmt="%.10f")

    return freq, amp, phase
示例#39
0
def corr_pairs(str1,str2,corrname,geoinf):
    """
    Step through the traces in the relevant streams and correlate whatever 
    overlaps enough.
    
    input:
    
    str1,str2, obspy stream objects: Streams holding traces for station 1 and 
    station 2
    winlen, int: window length in seconds
    overlap, int: overlap in seconds
    maxlag, int: maximum lag for correlation in seconds
    nu, int: pcc nu, exponent for phase cross correlation

    startday, UTCDateTime object: Time where stack should start (if data 
    available)
    endday, UTCDateTime object: Maximum time until where stacking should be 
    carried out
    Fs, float: Sampling rate of data in Hz
    fmin: Minimum frequency the signal was filtered to (or 0.001 Hz)
    fmax: Maximum frequency the signal was filtered to (or 0.5*sampling 
    frequency)
    onebit: Boolean, do one-bitting or not
    verbose, boolean: loud or quiet
    
    output:
    
    cccstack, numpy array: classical cross correlation in time domain
    pccstack, numpy array: phase cross correlation
    ccccnt, int: Number of windows stacked for cccstack
    pcccnt, int: Number of windows stacked for pccstack
    
    
    """
    
    print('Computing correlation stack for:',file=None)
    print('-------------',file=None)
    print(str1[0].id)
    print(str2[0].id)
    print('-------------',file=None)
    
   
    startday=UTCDateTime(inp.startdate)
    endday=UTCDateTime(inp.enddate)
    t1=startday
    Fs_new=inp.Fs
    tlen=int(inp.max_lag*Fs_new[-1])*2+1
    
    # Initialize arrays and variables
    pcccnt=0
    ccccnt=0
    n1=0
    n2=0
    cccstack=np.zeros(tlen)
    pccstack=np.zeros(tlen,dtype=np.float64)
    cstack_ccc=np.zeros(tlen,dtype=np.complex128)
    cstack_pcc=np.zeros(tlen,dtype=np.complex128)
    
    # Collect intermediate traces in a binary file.
    if inp.write_all:
        if inp.get_pws:
            msg = 'Saving intermediate windows of phase weighted stack\
is not implemented yet. Intermediate windows will be saved as linear stack.'
        
        # set the size of float
        
        # set size of character array for processing string
        
        # format of file:
        # header consisting of float, float, float, string of 256, string of 256
        # traces, traces, traces...
        # header values: Sampling rate Fs, number of samples in each trace,  Nr. of windows in intermediate stacks, Endianness, preprocessing string
        interm_fs = Fs_new[-1]
        interm_nsam = tlen
        interm_nwin = inp.interm_nstack
        
        if cccstack.dtype.byteorder == '=':
            interm_endian = sys.byteorder
        elif cccstack.dtype.byteorder == '<':
            interm_endian = 'little'
        elif cccstack.dtype.byteorder == '>':
            interm_endian = 'big'
            
        interm_preproc = get_prepstring()
        
        # open the file(s)
        if inp.corrtype in ['both','pcc','ccc']:
            
            outdir = os.path.join(cfg.datadir,'correlations',inp.corrname)
            interm_file=os.path.join(outdir,str1[0].id+'.'+str2[0].id+'.'+inp.corrtype+'.'+\
            inp.corrname+'.windows.bin')
            interm_file = open(interm_file,'wb')
            header_1 = np.array([interm_fs,interm_nsam,interm_nwin],dtype='f4')
            header_2 = np.array([interm_endian,interm_preproc],dtype='S256')
            header_1.tofile(interm_file)
            header_2.tofile(interm_file)
            
        else:
            print('Correlation type not recognized. Correlation types are:\
ccc, pcc or both.')
            MPI.COMM_WORLD.Abort(1)
            
            
         
    while n1<len(str1) and n2<len(str2):
    
        # Check if the end of one of the traces has been reached
        if str1[n1].stats.endtime-t1<inp.winlen-1:
            n1+=1
            print('No more windows in trace 1..',file=None)
            continue
        elif str2[n2].stats.endtime-t1<inp.winlen-1:
            n2+=1
            print('No more windows in trace 2..',file=None)
            continue
        
        # Check the starttime of the potentially new trace
        t1=max(t1,str1[n1].stats.starttime,str2[n2].stats.starttime)
        #print(t1,file=None)
        t2=t1+inp.winlen
        print(t1)
        # Check if the end of the desired stacking window is reached
        if t2>endday: 
            #print('At end of correlation time',file=None)
            break
        
        
        tr1=str1[n1].slice(starttime=t1,endtime=t2-1/Fs_new[-1])
        tr2=str2[n2].slice(starttime=t1,endtime=t2-1/Fs_new[-1])
        
        if tr1.stats.npts != tr2.stats.npts:
            t1 = t2 - inp.olap
            
            continue
       # tr1.plot()
        #tr2.plot()
        
        #- Downsampling ===============================================================
        if len(tr1.data)>40 and len(tr2.data)>40:
            k=0
            while k<len(Fs_new):
                if Fs_new[k]<tr1.stats.sampling_rate:
                    tr1=proc.trim_next_sec(tr1,False,None)
                    tr1=proc.downsample(tr1,Fs_new[k],False,None)
                if Fs_new[k]<tr2.stats.sampling_rate:
                    tr2=proc.trim_next_sec(tr2,False,None)
                    tr2=proc.downsample(tr2,Fs_new[k],False,None)
                k+=1
        else:
            t1 = t2 - inp.olap
            continue   
        #==============================================================================
        #- Checks     
        #============================================================================== 
        if tr1.data.any()==np.nan or tr2.data.any()==np.nan:
            t1 = t2 - inp.olap
            print('Encountered nan, skipping this trace pair...',file=None)
            continue
        if tr1.data.any()==np.inf or tr2.data.any()==np.inf:
            t1 = t2 - inp.olap
            print('Encountered inf, skipping this trace pair...',file=None)
            continue
            
        if len(tr1.data) == len(tr2.data):
            mlag = inp.max_lag / tr1.stats.delta
            mlag=int(mlag)
            
        # Check if the traces are both long enough
        if len(tr1.data)<=2*mlag or len(tr2.data)<=2*mlag:
            t1 = t2 - inp.olap
            print('One or both traces too short',file=None)
            continue
        # Check if too many zeros
        # I use epsilon for this check. That is convenient but not strictly right. It seems to do the job though. min doesn't work.
        
        if np.sum(np.abs(tr1.data)<sys.float_info.epsilon) > 0.1*tr1.stats.npts or \
        np.sum(np.abs(tr2.data)<sys.float_info.epsilon) > 0.1*tr2.stats.npts:
            t1 = t2 - inp.olap
            
            if inp.verbose: print('More than 10% of trace equals 0, skipping.',file=None)
            continue
        
         #==============================================================================
        #- Data treatment        
        #==============================================================================


        #- Glitch correction ==========================================================
        if inp.cap_glitches:
            std1 = np.std(tr1.data*1.e6)
            gllow = inp.glitch_thresh * -std1
            glupp = inp.glitch_thresh * std1
            tr1.data = np.clip(tr1.data*1.e6,gllow,glupp)/1.e6
            
            std2 = np.std(tr2.data*1.e6)
            gllow = inp.glitch_thresh * -std2
            glupp = inp.glitch_thresh * std2
            tr2.data = np.clip(tr2.data*1.e6,gllow,glupp)/1.e6
            
        
            
#        #- Whitening            ==================================================================
        
        if inp.apply_white:
            tr1 = whiten(tr1)
            tr2 = whiten(tr2)
            
        #- One-bitting ================================================================
        
        if inp.apply_onebit:
            tr1.data = np.sign(tr1.data)
            tr2.data = np.sign(tr2.data)
        
#- RAM normalization...who wants to do all this stuff!! ================================================================
        if inp.apply_ram:
            tr1 = ram_norm(tr1,inp.ram_window,prefilt=inp.ram_filter)
            tr2 = ram_norm(tr2,inp.ram_window,prefilt=inp.ram_filter)
        
       
        #==============================================================================
        #- Correlations proper 
        #==============================================================================        #- Taper
        if inp.taper_traces == True:
            tr1.taper(type='cosine',max_percentage=inp.perc_taper)
            tr2.taper(type='cosine',max_percentage=inp.perc_taper)
        
    #-   Classical correlation part =====================================
        if inp.corrtype == 'ccc' or inp.corrtype == 'both':
            #ccc=classic_xcorr(tr1, tr2, mlag)
            (ccc, params) = cross_covar(tr1.data, \
            tr2.data, mlag,inp.normalize_correlation)
            
            
            
            if ccc.any() == np.nan:
                msg='NaN encountered, omitting correlation from stack.'
                warn(msg)
                print(tr1)
                print(tr2)
                t1 = t2 - inp.olap
                continue
                
            # normalization by trace energy
            en1 = params[2]
            en2 = params[3]
            if inp.normalize_correlation:
                ccc/=(sqrt(en1)*sqrt(en2))
            
            cccstack+=ccc
            ccccnt+=1
           
            print('Finished a correlation window',file=None)
            # Make this faster by zero padding
            
            
            if inp.get_pws == True:
                coh_ccc = np.zeros(nextpow2(len(ccc)))
                startindex = int(0.5*(len(coh_ccc) - len(ccc)))
                coh_ccc[startindex:startindex+len(ccc)] += ccc*np.hanning(len(ccc))
                coh_ccc = hilbert(coh_ccc)
                tol = np.max(coh_ccc)/10000.
                #if tol < 1e-9:
                #    tol = 1e-9
                coh_ccc = coh_ccc/(np.absolute(coh_ccc)+tol)
                coh_ccc = coh_ccc[startindex:startindex+len(ccc)]
                cstack_ccc+=coh_ccc
                
            else: 
                coh_ccc = None
                cstack_ccc = None
                
            if inp.write_all==True and ccccnt % inp.interm_nstack == 0:
                trcname = t2.strftime("end%Y.%j.%H.%M.%S")
                trcname = np.array([trcname],dtype='S24')
                trcname.tofile(interm_file)
                ccc = np.array(ccc,dtype='f4')
                ccc.tofile(interm_file)
                
                #id1=str1[n1].id.split('.')[0]+'.'+str1[n1].id.split('.')[1]
                #id2=str2[n2].id.split('.')[0]+'.'+str2[n2].id.split('.')[1]
                #win_dir = cfg.datadir+'/correlations/interm/'+id1+\
                #    '_'+id2+'/'
                
                #if os.path.exists(win_dir)==False:
                #    os.mkdir(win_dir)
                
                #timestring = tr1.stats.starttime.strftime('.%Y.%j.%H.%M.%S')
                #savecorrs(ccc,coh_ccc,1,tr1.id,tr2.id,geoinf,\
                #corrname,'ccc',win_dir,params,timestring,startday=t1,endday=t2)
                        
                
                #- Phase correlation part =========================================
                # To be implemented: Getting trace energy
        
        elif inp.corrtype == 'pcc' or inp.corrtype == 'both':
            pcc=phase_xcorr(tr1.data, tr2.data, mlag, inp.pcc_nu)
            pccstack+=pcc
            pcccnt+=1
            
            
            
            if inp.get_pws == True:
                coh_pcc = np.zeros(nextpow2(len(pcc)))
                startindex = int(0.5*(len(coh_pcc) - len(pcc)))
                coh_pcc[startindex:startindex+len(pcc)] += pcc*np.hanning(len(pcc))  # Tapering and zero padding to make hilbert trafo faster
                coh_pcc = hilbert(coh_pcc)
                tol = np.max(coh_pcc)/10000.
                #if tol < 1e-9:
                #    tol = 1e-9
                coh_pcc = coh_pcc/(np.absolute(coh_pcc)+tol)
                coh_pcc = coh_pcc[startindex:startindex+len(pcc)]
                cstack_pcc+=coh_pcc
            else: 
                coh_pcc = None
                cstack_pcc = None
            if inp.write_all==True:
                trcname = t2.strftime("end%Y.%j.%H.%M.%S")
                trcname = np.array([trcname],dtype='S24')
                trcname.tofile(interm_file)
                pcc = np.array(pcc,dtype='f4')
                pcc.tofile(interm_file)
                #id1=str1[n1].id.split('.')[0]+'.'+str1[n1].id.split('.')[1]
                #id2=str2[n2].id.split('.')[0]+'.'+str2[n2].id.split('.')[1]
                #win_dir = cfg.datadir+'/correlations/interm/'+id1+\
                #    '_'+id2+'/'
                #
                #if os.path.exists(win_dir)==False:
                #    os.mkdir(win_dir)
                #timestring = tr1.stats.starttime.strftime('.%Y.%j.%H.%M.%S')  
                #savecorrs(pcc,coh_pcc,1,tr1.id,tr2.id,geoinf,\
                #corrname,'pcc',win_dir,None,timestring,startday=t1,endday=t2)
                   
           
        #Update starttime
        t1 = t2 - inp.olap
    if 'interm_file' in locals():  
        interm_file.close()
    return(cccstack,pccstack,cstack_ccc,cstack_pcc,ccccnt,pcccnt)
示例#40
0
def relcalstack(st1, st2, calib_file, window_len, OverlapFrac=0.5, smooth=0):
    """
    Method for relative calibration of sensors using a sensor with known transfer function

    :param st1/st2: Stream object, (known/unknown) the trace.stats dict like class must contain \
                    the parameters "sampling_rate", "npts" and "station"
    :type calib_file: String
    :param calib_file: name of calib file containing the known PAZ of known instrument in GSE2 standard.
    :type window_len: Float
    :param window_len: length of sliding window in seconds
    :type OverlapFrac: float
    :param OverlapFrac: fraction of overlap, defaults to fifty percent (0.5)
    :type smooth: Float
    :param smooth: variable that defines if the Konno-Ohmachi taper is used or not. default = 0 -> no taper \
                    generally used in geopsy: smooth = 40
    """
    # check Konno-Ohmachi
    if smooth < 0:
        smooth = 0

    # check if sampling rate and trace length is the same
    if st1[0].stats.npts != st2[0].stats.npts:
        msg = "Traces dont have the same length!"
        raise ValueError(msg)
    elif st1[0].stats.sampling_rate != st2[0].stats.sampling_rate:
        msg = "Traces dont have the same sampling rate!"
        raise ValueError(msg)
    else:
        ndat1 = st1[0].stats.npts
        ndat2 = st2[0].stats.npts
        sampfreq = st1[0].stats.sampling_rate

    # read waveforms
    tr1 = st1[0].data.astype(np.float64)
    tr2 = st2[0].data.astype(np.float64)

    # get window length, nfft and frequency step
    ndat = int(window_len * sampfreq)
    nfft = nextpow2(ndat)
    df = sampfreq / nfft

    # initialize array for response function
    res = np.zeros(nfft / 2 + 1, dtype="complex128")

    # read calib file and calculate response function
    gg, freq = calcresp(calib_file, nfft, sampfreq)

    # calculate number of windows and overlap
    nwin = int(np.floor((ndat1 - nfft) / (nfft / 2)) + 1)
    noverlap = nfft * OverlapFrac

    auto, freq, t = spectral_helper(tr1, tr1, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)
    cross, freq, t = spectral_helper(tr1, tr2, NFFT=nfft, Fs=sampfreq, noverlap=noverlap)

    # 180 Grad Phasenverschiebung
    cross.imag = -cross.imag

    for i in range(nwin):
        res += (cross[:, i] / auto[:, i]) * gg

    # apply Konno-Ohmachi smoothing taper if choosen
    if smooth > 0:
        res /= nwin

        res.real = smooth_spectra(res.real, freq, smooth, count=1, max_memory_in_mb=1024)
        res.imag = smooth_spectra(res.imag, freq, smooth, count=1, max_memory_in_mb=1024)

    else:
        res /= nwin

    # print 'Writing output....'

    f = open(st2[0].stats.station + "." + str(window_len) + ".resp", "w")
    g = open(st1[0].stats.station + ".refResp", "w")

    amp = []
    phase = []

    for i in range(nfft / 2 + 1):

        a = np.sqrt(res.real[i] * res.real[i] + res.imag[i] * res.imag[i])
        pha = np.arctan2(res.imag[i], res.real[i])
        ra = np.sqrt(gg.real[i] * gg.real[i] + gg.imag[i] * gg.imag[i])
        rpha = np.arctan2(gg.imag[i], gg.real[i])
        amp.append(a)
        phase.append(pha)
        f.write("%f %f %f\n" % (freq[i], a, pha))
        g.write("%f %f %f\n" % (freq[i], ra, rpha))

    f.close()
    g.close()

    return freq, amp, phase
示例#41
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 = nextpow2(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
    tap = cosTaper(nsamp, p=0.22)  # 0.22 matches 0.2 of historical C bbfk.c
    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':
        # 719162 == hours between 1970 and 0001
        res[:, 0] = res[:, 0] / (24. * 3600) + 719162
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
示例#42
0
def sonic(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 for Seismic-Array-Beamforming/FK-Analysis

    :param stream: Stream object, the trace.stats dict like class must
        contain a obspy.core.util.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
    :type frqhigh: Float
    :param frqhigh: higher frequency for fk
    :type stime: UTCDateTime
    :param stime: Starttime of interest
    :type etime: UTCDateTime
    :param etime: Endtime 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: string
    :param timestamp: valid values: 'julsec' and 'mlabday'; 'julsec' returns
        the timestamp in secons 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)
    :return: numpy.ndarray of timestamp, relative power, absolute power,
        backazimut, slowness
    """
    res = []
    eotr = True
    #XXX move all the the ctypes related stuff to bbfk (Moritz's job)

    # check that sampling rates do not vary
    df = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=df)):
        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_numpy = get_timeshift(geometry, sll_x, sll_y, sl_s,
                                           grdpts_x, grdpts_y)
    time_shift_table = ndarray2ptr3D(time_shift_table_numpy)
    # fillup the double trace pointer
    nstat = len(stream)
    trace = (C.c_void_p * nstat)()
    ntrace = np.empty(nstat, dtype="int32", order="C")
    for i, tr in enumerate(stream):
        # assure data are of correct type
        tr.data = np.require(tr.data, 'float64', ['C_CONTIGUOUS'])
        trace[i] = tr.data.ctypes.data_as(C.c_void_p)
        ntrace[i] = len(tr.data)

    # offset of arrays
    spoint, _epoint = get_spoint(stream, stime, etime)
    #
    # loop with a sliding window over the data trace array and apply bbfk
    #
    df = stream[0].stats.sampling_rate
    nsamp = int(win_len * df)
    nstep = int(nsamp * win_frac)

    # generate plan for rfftr
    nfft = nextpow2(nsamp)
    newstart = stime
    offset = 0
    while eotr:
        try:
            buf = bbfk(spoint, offset, trace, ntrace, time_shift_table, frqlow,
                       frqhigh, df, nsamp, nstat, prewhiten, grdpts_x,
                       grdpts_y, nfft)
            abspow, power, ix, iy = buf
        except IndexError:
            break

        # 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 - np.sign(azimut) * 180
        if power > semb_thres and 1. / slow > vel_thres:
            res.append(np.array([newstart.timestamp, power, abspow, baz,
                                 slow]))
            if verbose:
                print(newstart, (newstart + (nsamp / df)), res[-1][1:])
        if (newstart + (nsamp + nstep) / df) > etime:
            eotr = False
        offset += nstep

        newstart += nstep / df
    res = np.array(res)
    if timestamp == 'julsec':
        pass
    elif timestamp == 'mlabday':
        # 719162 == hours between 1970 and 0001
        res[:, 0] = res[:, 0] / (24. * 3600) + 719162
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
示例#43
0
def sonic(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 for Seismic-Array-Beamforming/FK-Analysis

    :param stream: Stream object, the trace.stats dict like class must
        contain a obspy.core.util.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
    :type frqhigh: Float
    :param frqhigh: higher frequency for fk
    :type stime: UTCDateTime
    :param stime: Starttime of interest
    :type etime: UTCDateTime
    :param etime: Endtime 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: string
    :param timestamp: valid values: 'julsec' and 'mlabday'; 'julsec' returns
        the timestamp in secons 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)
    :return: numpy.ndarray of timestamp, relative power, absolute power,
        backazimut, slowness
    """
    res = []
    eotr = True
    #XXX move all the the ctypes related stuff to bbfk (Moritz's job)

    # check that sampling rates do not vary
    df = stream[0].stats.sampling_rate
    if len(stream) != len(stream.select(sampling_rate=df)):
        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_numpy = get_timeshift(geometry, sll_x, sll_y,
                                                    sl_s, grdpts_x, grdpts_y)
    time_shift_table = ndarray2ptr3D(time_shift_table_numpy)
    # fillup the double trace pointer
    nstat = len(stream)
    trace = (C.c_void_p * nstat)()
    ntrace = np.empty(nstat, dtype="int32", order="C")
    for i, tr in enumerate(stream):
        # assure data are of correct type
        tr.data = np.require(tr.data, 'float64', ['C_CONTIGUOUS'])
        trace[i] = tr.data.ctypes.data_as(C.c_void_p)
        ntrace[i] = len(tr.data)

    # offset of arrays
    spoint, _epoint = get_spoint(stream, stime, etime)
    #
    # loop with a sliding window over the data trace array and apply bbfk
    #
    df = stream[0].stats.sampling_rate
    nsamp = int(win_len * df)
    nstep = int(nsamp * win_frac)

    # generate plan for rfftr
    nfft = nextpow2(nsamp)
    newstart = stime
    offset = 0
    while eotr:
        try:
            buf = bbfk(spoint, offset, trace, ntrace, time_shift_table, frqlow,
                       frqhigh, df, nsamp, nstat, prewhiten, grdpts_x,
                       grdpts_y, nfft)
            abspow, power, ix, iy = buf
        except IndexError:
            break

        # 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 - np.sign(azimut) * 180
        if power > semb_thres and 1. / slow > vel_thres:
            res.append(np.array([newstart.timestamp, power, abspow, baz,
                                 slow]))
            if verbose:
                print(newstart, (newstart + (nsamp / df)), res[-1][1:])
        if (newstart + (nsamp + nstep) / df) > etime:
            eotr = False
        offset += nstep

        newstart += nstep / df
    res = np.array(res)
    if timestamp == 'julsec':
        pass
    elif timestamp == 'mlabday':
        # 719162 == hours between 1970 and 0001
        res[:, 0] = res[:, 0] / (24. * 3600) + 719162
    else:
        msg = "Option timestamp must be one of 'julsec', or 'mlabday'"
        raise ValueError(msg)
    return np.array(res)
示例#44
0
def CalcResp(poles, zeros, scaleFac, MaxPer, sampfreq):
    ndat = MaxPer * sampfreq
    nfft = nextpow2(ndat)
    buffer = np.empty(nfft / 2 + 1, dtype='complex128')
    #    poles = []
    #    zeros = []
    #    file = open(str(pazFile), 'r')
    #
    #    # read file until calibration section is found
    #    text = ' '
    #    while text != 'CAL1':
    #        textln = file.readline()
    #        text = textln.split(' ')[0]
    #    if not text == 'CAL1':
    #        msg = 'could not find calibration section!'
    #        raise NameError(msg)
    #    else:
    #        cal = textln[31:34]
    #    if cal == 'PAZ':
    #        # read poles
    #        npoles = int(file.readline())
    #        for i in xrange(npoles):
    #            pole = file.readline()
    #            pole_r = float(pole.split(" ")[0])
    #            pole_i = float(pole.split(" ")[1])
    #            pole_c = pole_r + pole_i * 1.j
    #            poles.append(pole_c)
    #        # read zeros
    #        nzeros = int(file.readline())
    #        for i in xrange(nzeros):
    #            zero = file.readline()
    #            zero_r = float(zero.split(" ")[0])
    #            zero_i = float(zero.split(" ")[1])
    #            zero_c = zero_r + zero_i * 1.j
    #            zeros.append(zero_c)
    #        # read scale factor
    #        scale_fac = float(file.readline())
    #        file.close

    scale_fac = scaleFac

    # calculate transfer function
    delta_f = sampfreq / nfft
    F = np.empty(nfft / 2 + 1)
    for i in xrange(nfft / 2 + 1):
        fr = i * delta_f
        F[i] = fr
        om = 2 * np.pi * fr
        num = 1. + 0.j

        for ii in xrange(len(zeros)):
            s = 0. + om * 1.j
            dif = s - zeros[ii]
            num = dif * num

        denom = 1. + 0.j
        for ii in xrange(len(poles)):
            s = 0. + om * 1.j
            dif = s - poles[ii]
            denom = dif * denom

        t_om = 1. + 0.j
        if denom.real != 0. or denom.imag != 0.:
            t_om = num / denom

        t_om *= scale_fac

        if i < nfft / 2 and i > 0:
            buffer[i] = t_om

        if i == 0:
            buffer[i] = t_om + 0.j

        if i == nfft / 2:
            buffer[i] = t_om + 0.j

# plot
    amp = abs(buffer)
    phase = np.arctan(buffer.imag / buffer.real) / np.pi * 180

    # Plot
    fig = plt.figure()
    ax1 = plt.subplot(211)
    ax1.loglog(F, amp)
    ax1.set_ylabel('Amplitude')

    ax2 = plt.subplot(212)
    ax2.semilogx(F, phase)
    ax2.set_xlabel('Frequenzy [Hz]')
    ax2.set_ylabel('Phase')

    plt.show()