Пример #1
0
def correct_response(st, removeResp=False, removePAZ=False, simPAZ=False, pre_filt=None, cornFreq=0.0083):
    """
    Correct the seismometer response.
    
    Seismometer response is given in either a dictionary ``removeResp''
    or a dictionary ``removePAZ''. ``removeResp has precedence. The
    dictionaries have the following structure

    removeResp: dictionary with Response information to be removed
        has the following keys:
        respfile: (str) filename of evalresp response file.
        units: (str) Units to return response in. Can be either DIS, VEL or ACC
        start_stage: (int) integer stage numbers of start stage (<0 causes
            default evalresp bahaviour).
        stop_stage: (int) integer stage numbers of stop stage
    removePAZ: dictionary with poles and zeros to be removed has the following
        keys:
            poles: (list of complex numbers) location of poles
            zeros: (list of complex numbers) location of zeros
            gain: (float) gain
            sensitivity: (float) sensitivity
        It can easily be retrieved with obspy.arclink.client.Client.getPAZ

    if ``removeResp'' is given the response of each trace must be present in
    the respfile. If ``removePAZ'' is used the response is assumed to be the
    same for all traces in the stream.
    A filter specified in pre_filt can be applied in to avoid amplification of
    noise.
    The instrument to be simulated is either described in the dictionary simPAZ
    or if simPAZ is False by the corner frequency ``cornFreq''. Response
    correction is done in place and original data is overwritten.
    
    The input stream ``st'' should be demeaned and tapered.
    
    :type st: obspy.core.stream.Stream
    :param st: data stream to be corrected
    :type removeResp: dict
    :param removeResp: Response information to be removed
    :type removePAZ: dict
    :param removePAZ: Response information to be removed
    :type simPAZ: dict
    :param simPAZ: Response information to be simulated
    :type cornFreq: float
    :param cornFreq: corner frequency of instrument to be simulated
    :type pre_filt: list
    :param pre_filt: 4 corners of the filter
    """
    
    for tr in st:
        starttime = tr.stats['starttime']
        endtime = tr.stats['endtime']
        network = tr.stats['network']
        station = tr.stats['station']
        channel = tr.stats['channel']
        location = tr.stats['location']
        length = tr.stats['npts']
        sampling_rate = tr.stats['sampling_rate']
        np2l = nextpow2(2.*length)
        
        if not simPAZ:
            simPAZ = cornFreq2Paz(cornFreq, damp=0.70716)
        simresp, freqs = np.conj(pazToFreqResp(simPAZ['poles'], simPAZ['zeros'],
                          scale_fac=simPAZ['gain']*simPAZ['sensitivity'],
                          t_samp=1./sampling_rate,
                          nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj()
        
        if removeResp:
            freqresp, freqs = evalresp(1./sampling_rate,np2l,removeResp['respfile'],
                                starttime, network=network, station=station,
                                channel=channel, locid=location,
                                start_stage=removeResp['start_stage'],
                                stop_stage=removeResp['stop_stage'],
                                units=removeResp['units'], freq=True)
        else:
            freqresp, freqs = np.conj(pazToFreqResp(removePAZ['poles'], removePAZ['zeros'],
                          scale_fac=removePAZ['gain']*removePAZ['sensitivity'],
                          t_samp=1./sampling_rate,
                          nfft=np2l, freq=True)) #see Doc of pazToFreqResp for reason of conj()
        
        ftr = np.fft.rfft(tr.data,n=np2l)
        ftr /= freqresp
        ftr[0] = 0.j  # correct the NaN in the DC component
        ftr *= simresp
        
        if pre_filt:
            ftr *= c_sac_taper(freqs, flimit=pre_filt)

        tr.data = np.fft.irfft(ftr)
        tr.trim(starttime,endtime)
    
    return   
Пример #2
0
def time_shift_apply(corr_data, shift):
    """ Apply time shift to traces.

    Apply time shifts to traces e.g. to align them to a common time base.
    Such shifts can occur in corrlation traces in case of a drifting clock.
    This function ``applies`` the shifts. To correct for shift estimated with
    :class:`~miic.core.stretch_mod.time_shift_estimate` you need to apply
    negative shifts.
    Shifting is done in frequency domain with 5% tapering.

    :type corr_data: :py:class:`~numpy.ndarray`
    :param corr_data: 2d ndarray containing the correlation functions that are
        to be shifted.
        One for each row.
    :type shift: :py:class:`~numpy.ndarray`
    :param shift: ndarray with shift.shape[0] = corr_data.shape[0] containing
        the shifts in units of the sampling interval by which the trace are to
        be shifted

    :rtype: :py:class:`~numpy.ndarray`
    :return: **shifted_mat**: shifted version of the input matrix
    """
    mat = corr_data
    # check input
    # shift is just a 1d array
    if len(shift.shape) == 1:
        t_shift = np.zeros([shift.shape[0], 1])
        t_shift[:, 0] = shift
        shift = t_shift
    # shift has the wrong length
    elif shift.shape[0] != mat.shape[0]:
        print 'InputError: shift.shape[0] must be equal corr_data.shape[0]'
        return 0
    # shift has multiple columns (multiple measurements for the same time)
    if shift.shape[1] > 1:
        shift = np.delete(shift, np.arange(1, shift.shape[1]), axis=1)

    # taper the reference matrix to avoid interpolation
    taper = cosTaper(mat.shape[1], 0.05)
    mat *= np.tile(taper, [mat.shape[0], 1])

    # find a suitable length for the FFT
    N = nextpow2(2 * mat.shape[1])
    w = np.zeros([1, N / 2 + 1])

    # original and shifted phase
    w[0, :] = np.linspace(0, np.pi, N / 2 + 1)
    pha = np.exp(-1j * (shift) * w)

    # Fourier Transform
    F = np.fft.rfft(mat, N, 1)

    # apply the phase shift
    sF = F * pha

    # transform to time domain
    smat = np.fft.irfft(sF)

    # cut to original size
    shifted_mat = smat[:, 0:mat.shape[1]]
    return shifted_mat
Пример #3
0
def correct_response(st,
                     removeResp=False,
                     removePAZ=False,
                     simPAZ=False,
                     pre_filt=None,
                     cornFreq=0.0083):
    """
    Correct the seismometer response.
    
    Seismometer response is given in either a dictionary ``removeResp''
    or a dictionary ``removePAZ''. ``removeResp has precedence. The
    dictionaries have the following structure

    removeResp: dictionary with Response information to be removed
        has the following keys:
        respfile: (str) filename of evalresp response file.
        units: (str) Units to return response in. Can be either DIS, VEL or ACC
        start_stage: (int) integer stage numbers of start stage (<0 causes
            default evalresp bahaviour).
        stop_stage: (int) integer stage numbers of stop stage
    removePAZ: dictionary with poles and zeros to be removed has the following
        keys:
            poles: (list of complex numbers) location of poles
            zeros: (list of complex numbers) location of zeros
            gain: (float) gain
            sensitivity: (float) sensitivity
        It can easily be retrieved with obspy.arclink.client.Client.getPAZ

    if ``removeResp'' is given the response of each trace must be present in
    the respfile. If ``removePAZ'' is used the response is assumed to be the
    same for all traces in the stream.
    A filter specified in pre_filt can be applied in to avoid amplification of
    noise.
    The instrument to be simulated is either described in the dictionary simPAZ
    or if simPAZ is False by the corner frequency ``cornFreq''. Response
    correction is done in place and original data is overwritten.
    
    The input stream ``st'' should be demeaned and tapered.
    
    :type st: obspy.core.stream.Stream
    :param st: data stream to be corrected
    :type removeResp: dict
    :param removeResp: Response information to be removed
    :type removePAZ: dict
    :param removePAZ: Response information to be removed
    :type simPAZ: dict
    :param simPAZ: Response information to be simulated
    :type cornFreq: float
    :param cornFreq: corner frequency of instrument to be simulated
    :type pre_filt: list
    :param pre_filt: 4 corners of the filter
    """

    for tr in st:
        starttime = tr.stats['starttime']
        endtime = tr.stats['endtime']
        network = tr.stats['network']
        station = tr.stats['station']
        channel = tr.stats['channel']
        location = tr.stats['location']
        length = tr.stats['npts']
        sampling_rate = tr.stats['sampling_rate']
        np2l = nextpow2(2. * length)

        if not simPAZ:
            simPAZ = cornFreq2Paz(cornFreq, damp=0.70716)
        simresp, freqs = np.conj(
            pazToFreqResp(
                simPAZ['poles'],
                simPAZ['zeros'],
                scale_fac=simPAZ['gain'] * simPAZ['sensitivity'],
                t_samp=1. / sampling_rate,
                nfft=np2l,
                freq=True))  #see Doc of pazToFreqResp for reason of conj()

        if removeResp:
            freqresp, freqs = evalresp(1. / sampling_rate,
                                       np2l,
                                       removeResp['respfile'],
                                       starttime,
                                       network=network,
                                       station=station,
                                       channel=channel,
                                       locid=location,
                                       start_stage=removeResp['start_stage'],
                                       stop_stage=removeResp['stop_stage'],
                                       units=removeResp['units'],
                                       freq=True)
        else:
            freqresp, freqs = np.conj(
                pazToFreqResp(
                    removePAZ['poles'],
                    removePAZ['zeros'],
                    scale_fac=removePAZ['gain'] * removePAZ['sensitivity'],
                    t_samp=1. / sampling_rate,
                    nfft=np2l,
                    freq=True))  #see Doc of pazToFreqResp for reason of conj()

        ftr = np.fft.rfft(tr.data, n=np2l)
        ftr /= freqresp
        ftr[0] = 0.j  # correct the NaN in the DC component
        ftr *= simresp

        if pre_filt:
            ftr *= c_sac_taper(freqs, flimit=pre_filt)

        tr.data = np.fft.irfft(ftr)
        tr.trim(starttime, endtime)

    return
Пример #4
0
def time_shift_apply(corr_data, shift):
    """ Apply time shift to traces.

    Apply time shifts to traces e.g. to align them to a common time base.
    Such shifts can occur in corrlation traces in case of a drifting clock.
    This function ``applies`` the shifts. To correct for shift estimated with
    :class:`~miic.core.stretch_mod.time_shift_estimate` you need to apply
    negative shifts.
    Shifting is done in frequency domain with 5% tapering.

    :type corr_data: :py:class:`~numpy.ndarray`
    :param corr_data: 2d ndarray containing the correlation functions that are
        to be shifted.
        One for each row.
    :type shift: :py:class:`~numpy.ndarray`
    :param shift: ndarray with shift.shape[0] = corr_data.shape[0] containing
        the shifts in units of the sampling interval by which the trace are to
        be shifted

    :rtype: :py:class:`~numpy.ndarray`
    :return: **shifted_mat**: shifted version of the input matrix
    """
    mat = corr_data
    # check input
    # shift is just a 1d array
    if len(shift.shape) == 1:
        t_shift = np.zeros([shift.shape[0], 1])
        t_shift[:, 0] = shift
        shift = t_shift
    # shift has the wrong length
    elif shift.shape[0] != mat.shape[0]:
        print "InputError: shift.shape[0] must be equal corr_data.shape[0]"
        return 0
    # shift has multiple columns (multiple measurements for the same time)
    if shift.shape[1] > 1:
        shift = np.delete(shift, np.arange(1, shift.shape[1]), axis=1)

    # taper the reference matrix to avoid interpolation
    taper = cosTaper(mat.shape[1], 0.05)
    mat *= np.tile(taper, [mat.shape[0], 1])

    # find a suitable length for the FFT
    N = nextpow2(2 * mat.shape[1])
    w = np.zeros([1, N / 2 + 1])

    # original and shifted phase
    w[0, :] = np.linspace(0, np.pi, N / 2 + 1)
    pha = np.exp(-1j * (shift) * w)

    # Fourier Transform
    F = np.fft.rfft(mat, N, 1)

    # apply the phase shift
    sF = F * pha

    # transform to time domain
    smat = np.fft.irfft(sF)

    # cut to original size
    shifted_mat = smat[:, 0 : mat.shape[1]]
    return shifted_mat