示例#1
0
def KonnoSmoothSpec(tr, bandwidth, plot):
    """ Smooth spectrum of a given trace with the Konno_omachi method
    * inputs : 
        - tr: type: trace; seimic trace
        - bandwidth : type int; number of point over wich the spectrum is smoothed, after testing 110 seems good
        - plot : type Bool; if True smooth, and un smooth spectrum are plotted
    * outputs : 
        - fr :  type array; frequencies of the spectrum
        - SmoothSpectre : type array; Smooth spectrum
    * exemple :
    """
    #  0. Spectre of the trace ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    t = np.arange(0, tr.stats.npts / tr.stats.sampling_rate, tr.stats.delta)
    trFreq= np.fft.fft(tr.data, n= 10000)
    fs = tr.stats.sampling_rate
    N = len(trFreq)
    #half spectre since fft is symmetric over is center 
    xF = trFreq[0:N/2] # 
    #frequencies
    fr = np.linspace(0,fs/2,N/2)
    
    #1. smoothing Spectrum ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #CAREFULL SMOTTHING GONNA CHANGE A LOT THE SPECTRUM BUT DOING THE SPECTRUML RATIO IS OK!
    SmoothSpectre = konno_ohmachi_smoothing(np.abs(xF), fr, bandwidth=bandwidth, count=1, enforce_no_matrix=False, normalize=False)
    
    if plot== True : 
        plt.figure()
        plt.plot(fr,np.abs(xF), 'r',label = 'non Smooth')
        plt.plot(fr,SmoothSpectre , 'k', label='Smooth')
        plt.ylabel("Amplitude")
        plt.xlabel("Frequency Hz")
        plt.legend()
    return fr, SmoothSpectre    
示例#2
0
 def test_konno_ohmachi_smoothing(self):
     """
     Tests the actual smoothing matrix.
     """
     # Create some random spectra.
     np.random.seed(1111)
     spectra = np.random.ranf((5, 200)) * 50
     frequencies = np.logspace(-3.0, 2.0, 200)
     spectra = np.require(spectra, dtype=np.float32)
     frequencies = np.require(frequencies, dtype=np.float64)
     # Wrong dtype raises.
     self.assertRaises(ValueError, konno_ohmachi_smoothing, spectra,
                       np.arange(200))
     # Differing float dtypes raise a warning.
     with warnings.catch_warnings(record=True):
         warnings.simplefilter('error', UserWarning)
         self.assertRaises(UserWarning, konno_ohmachi_smoothing, spectra,
                           frequencies)
     # Correct the dtype.
     frequencies = np.require(frequencies, dtype=np.float32)
     # The first one uses the matrix method, the second one the non matrix
     # method.
     smoothed_1 = konno_ohmachi_smoothing(spectra, frequencies, count=3)
     smoothed_2 = konno_ohmachi_smoothing(spectra,
                                          frequencies,
                                          count=3,
                                          max_memory_usage=0)
     # XXX: Why are the numerical inaccuracies quite large?
     np.testing.assert_almost_equal(smoothed_1, smoothed_2, 3)
     # Test using a pre-computed smoothing matrix
     smoothing_matrix = calculate_smoothing_matrix(frequencies)
     smoothed_3 = apply_smoothing_matrix(spectra, smoothing_matrix, count=3)
     np.testing.assert_almost_equal(smoothed_1, smoothed_3, 3)
     # Test the non-matrix mode for single spectra.
     smoothed_4 = konno_ohmachi_smoothing(
         np.require(spectra[0], dtype=np.float64),
         np.require(frequencies, dtype=np.float64))
     smoothed_5 = konno_ohmachi_smoothing(np.require(spectra[0],
                                                     dtype=np.float64),
                                          np.require(frequencies,
                                                     dtype=np.float64),
                                          normalize=True)
     # The normalized and not normalized should not be the same. That the
     # normalizing works has been tested before.
     self.assertFalse(np.all(smoothed_4 == smoothed_5))
     # Input dtype should be output dtype.
     self.assertEqual(smoothed_4.dtype, np.float64)
示例#3
0
 def test_konno_ohmachi_smoothing(self):
     """
     Tests the actual smoothing matrix.
     """
     # Create some random spectra.
     np.random.seed(1111)
     spectra = np.random.ranf((5, 200)) * 50
     frequencies = np.logspace(-3.0, 2.0, 200)
     spectra = np.require(spectra, dtype=np.float32)
     frequencies = np.require(frequencies, dtype=np.float64)
     # Wrong dtype raises.
     self.assertRaises(ValueError, konno_ohmachi_smoothing, spectra,
                       np.arange(200))
     # Differing float dtypes raise a warning.
     with warnings.catch_warnings(record=True):
         warnings.simplefilter('error', UserWarning)
         self.assertRaises(UserWarning, konno_ohmachi_smoothing, spectra,
                           frequencies)
     # Correct the dtype.
     frequencies = np.require(frequencies, dtype=np.float32)
     # The first one uses the matrix method, the second one the non matrix
     # method.
     smoothed_1 = konno_ohmachi_smoothing(spectra, frequencies, count=3)
     smoothed_2 = konno_ohmachi_smoothing(spectra, frequencies, count=3,
                                          max_memory_usage=0)
     # XXX: Why are the numerical inaccuracies quite large?
     np.testing.assert_almost_equal(smoothed_1, smoothed_2, 3)
     # Test using a pre-computed smoothing matrix
     smoothing_matrix = calculate_smoothing_matrix(frequencies)
     smoothed_3 = apply_smoothing_matrix(spectra, smoothing_matrix, count=3)
     np.testing.assert_almost_equal(smoothed_1, smoothed_3, 3)
     # Test the non-matrix mode for single spectra.
     smoothed_4 = konno_ohmachi_smoothing(
         np.require(spectra[0], dtype=np.float64),
         np.require(frequencies, dtype=np.float64))
     smoothed_5 = konno_ohmachi_smoothing(
         np.require(spectra[0], dtype=np.float64),
         np.require(frequencies, dtype=np.float64),
         normalize=True)
     # The normalized and not normalized should not be the same. That the
     # normalizing works has been tested before.
     self.assertFalse(np.all(smoothed_4 == smoothed_5))
     # Input dtype should be output dtype.
     self.assertEqual(smoothed_4.dtype, np.float64)
示例#4
0
def fft_smooth(trace, nfft):
    """
    Pads a trace to the nearest upper power of 2, takes the FFT, and
    smooths the amplitude spectra following the algorithm of
    Konno and Ohmachi.

    Args:
        trace (obspy.core.trace.Trace): Trace of strong motion data.
        nfft (int): Number of data points for the fourier transform.

    Returns:
        numpy.ndarray: Smoothed amplitude data and frequencies.
    """

    # Compute the FFT, normalizing by the number of data points
    spec = abs(np.fft.rfft(trace.data, n=nfft)) / nfft

    # Get the frequencies associated with the FFT
    freqs = np.fft.rfftfreq(nfft, 1 / trace.stats.sampling_rate)

    # Konno Omachi Smoothing using 20 for bandwidth parameter
    spec_smooth = konno_ohmachi_smoothing(spec.astype(float), freqs, 20)
    return spec_smooth, freqs
示例#5
0
def interp_smooth(path, singlecomp=False, ext=None, maxF=25, dt=1 / 100):
    """
        
    """
    if not singlecomp:  # take geometric mean of everything
        exts = [".EW2.gz", ".NS2.gz", ".EW1.gz", ".NS1.gz"]
        wfms = [readKiknet(path + f) for f in exts]
        [calcFAS(wf) for wf in wfms]
        s_b = (wfms[0]['FAS'] * wfms[1]['FAS'])**0.5 / (wfms[2]['FAS'] *
                                                        wfms[3]['FAS'])**0.5
    else:  #calc for only the specified component
        exts = [ext + "2.gz", ext + "1.gz"]
        wfms = [readKiknet(path + f) for f in exts]
        [calcFAS(wf) for wf in wfms]
        s_b = wfms[0]['FAS'] / wfms[1]['FAS']

    freqs = np.linspace(0 + dt, maxF + dt,
                        maxF / dt)[9:]  #start counting from 0.1Hz

    s_b = np.interp(freqs, wfms[0]['FASfreqs'], s_b)

    s_b = konno_ohmachi_smoothing(s_b, freqs, normalize=True)

    return (s_b, freqs)
示例#6
0
def rel_calib_stack(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 rel_calib_stack.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 = next_pow_2(ndat)

    # read calib file and calculate response function
    gg, _freq = _calc_resp(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 = \
            konno_ohmachi_smoothing(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=native_str('%.10f'))
        temp[:, 1] = ra
        temp[:, 2] = rpha
        np.savetxt(trans_ref, temp, fmt=native_str('%.10f'))

    return freq, amp, phase
示例#7
0
def rel_calib_stack(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 rel_calib_stack.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 = next_pow_2(ndat)

    # read calib file and calculate response function
    gg, _freq = _calc_resp(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 = konno_ohmachi_smoothing(
            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=native_str("%.10f"))
        temp[:, 1] = ra
        temp[:, 2] = rpha
        np.savetxt(trans_ref, temp, fmt=native_str("%.10f"))

    return freq, amp, phase