Esempio n. 1
0
    def _setNFFT(self, NFFT):  #if NFFT is changed, we need to redo the padding
        if self.__NFFT == NFFT and self.__NFFT is not None:
            #print 'NFFT is the same, nothing to do'
            return
        new_nfft = None
        if NFFT == 'nextpow2':
            #print 'NFFT is based on nextpow2:',
            n = nextpow2(self.data.size)
            new_nfft = int(pow(2, n))
        elif NFFT is None:
            #print 'NFFT set to data length',
            new_nfft = self.N
        elif isinstance(NFFT, int):
            #print 'NNFT set  manually to',
            assert NFFT > 0, 'NFFT must be a positive integer'
            new_nfft = NFFT
        else:
            raise ValueError(
                "NFFT must be either None, positive integer or 'nextpow2'")

        #print new_nfft
        if self.__NFFT != new_nfft:
            self.__NFFT = new_nfft
            # Now that the NFFT has changed, we need to update the range
            self._range.N = self.__NFFT
            self.__sides = self._default_sides()
            self.modified = True
Esempio n. 2
0
    def _setNFFT(self, NFFT):#if NFFT is changed, we need to redo the padding
        if self.__NFFT == NFFT and self.__NFFT is not None:
            #print 'NFFT is the same, nothing to do'
            return
        new_nfft = None
        if NFFT == 'nextpow2':
            #print 'NFFT is based on nextpow2:',
            n = nextpow2(self.data.size)
            new_nfft = int(pow(2,n))
        elif NFFT is None:
            #print 'NFFT set to data length',
            new_nfft = self.N
        elif isinstance(NFFT, int):
            #print 'NNFT set  manually to',
            assert NFFT > 0, 'NFFT must be a positive integer'
            new_nfft = NFFT
        else:
            raise ValueError("NFFT must be either None, positive integer or 'nextpow2'")

        #print new_nfft
        if self.__NFFT != new_nfft:
            self.__NFFT = new_nfft
            # Now that the NFFT has changed, we need to update the range
            self._range.N = self.__NFFT
            self.__sides = self._default_sides()
            self.modified = True
Esempio n. 3
0
def compute_spectrum_multitaper(x, dt, max_freq=300, NFFT=None):
    fs = 1. / (dt / 1000.)
    fmax = fs / 2.
    len_x = len(x)
    if NFFT is None:
        NFFT = 2**nextpow2(len_x)  # fft more efficient if power of 2
    freq_vec = np.linspace(0, fmax, NFFT / 2)
    a = pmtm(x, NFFT=NFFT, NW=2.5, method='eigen', show=False)
    power_pyr = np.mean(abs(a[0])**2 * a[1], axis=0)[:int(NFFT / 2)] / len_x

    if max_freq is not None:
        freq_vec = freq_vec[np.where(freq_vec <= max_freq)]
        power_pyr = power_pyr[np.where(freq_vec <= max_freq)]
    return freq_vec, power_pyr
Esempio n. 4
0
def compute_spectrogram_multitaper(x,
                                   dt,
                                   step_size=1,
                                   window_size=2**13,
                                   NW=2.5,
                                   freq_max=None,
                                   freq_min=None):
    fs = 1. / (dt / 1000.)
    fmax = fs / 2.
    len_x = len(x)
    NFFT = 2**nextpow2(len_x)  # fft more efficient if power of 2

    if NFFT is None:
        NFFT = window_size * 2

    assert len_x > window_size
    n_segs = int(np.floor(len_x / float(step_size))) + 1
    freq_vec = np.linspace(0, fmax, NFFT / 2)
    time_vec = np.arange(
        n_segs) * dt * step_size  # midpoint of respective window
    window_size_half = int(np.floor(window_size / 2.))
    x = np.pad(x, window_size_half, mode='reflect')

    spectrogram = np.zeros((len(freq_vec), n_segs))
    for i in range(n_segs):
        x_window = x[i * step_size:i * step_size + window_size]  # symmetric
        x_window -= np.mean(x_window)
        a = pmtm(x_window, NFFT=NFFT, NW=NW, method='eigen', show=False)
        power_window = np.mean(abs(a[0])**2 * a[1],
                               axis=0)[:int(NFFT / 2)] / window_size
        spectrogram[:, i] = power_window

    if freq_max is not None:
        spectrogram = spectrogram[np.where(freq_vec <= freq_max)[0], :]
        freq_vec = freq_vec[np.where(freq_vec <= freq_max)]

    if freq_min is not None:
        spectrogram = spectrogram[np.where(freq_vec > freq_min)[0], :]
        freq_vec = freq_vec[np.where(freq_vec > freq_min)]

    return spectrogram, freq_vec, time_vec
Esempio n. 5
0
def pmtm(x, NW=None, k=None, NFFT=None, e=None, v=None, method='adapt', show=True):
    """Multitapering spectral estimation

    :param array x: the data
    :param float NW: The time half bandwidth parameter (typical values are 2.5,3,3.5,4). Must be provided otherwise the tapering windows and eigen values (outputs of dpss) must be provided  
    :param int k: uses the first k Slepian sequences. If *k* is not provided, *k* is set to *NW*2*.
    :param NW
    :param e: the matrix containing the tapering windows
    :param v: the window concentrations (eigenvalues)
    :param str method: set how the eigenvalues are used. Must be in ['unity', 'adapt', 'eigen']
    :param bool show: plot results


    Usually in spectral estimation the mean to reduce bias is to use tapering window. 
    In order to reduce variance we need to average different spectrum. The problem 
    is that we have only one set of data. Thus we need to decompose a set into several 
    segments. Such method are well-known: simple daniell's periodogram, Welch's method
    and so on. The drawback of such methods is a loss of resolution since the segments 
    used to compute the spectrum are smaller than the data set. 
    The interest of multitapering method is to keep a good resolution while reducing 
    bias and variance. 

    How does it work? First we compute different simple periodogram with the whole data 
    set (to keep good resolution) but each periodgram is computed with a different 
    tapering windows. Then, we average all these spectrum. To avoid redundancy and bias
    due to the tapers mtm use special tapers.

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import *

        data = data_cosine(N=2048, A=0.1, sampling=1024, freq=200)
        # If you already have the DPSS windows
        [tapers, eigen] = dpss(2048, 2.5, 4)
        res = pmtm(data, e=tapers, v=eigen, show=False)
        # You do not need to compute the DPSS before end
        res = pmtm(data, NW=2.5, show=False)
        res = pmtm(data, NW=2.5, k=4, show=True)

    """
    assert method in ['adapt','eigen','unity']

    N = len(x)

    # if dpss not provided, compute them
    if e is None and v is None:
        if NW != None:
            [tapers, eigenvalues] = dpss(N, NW, k=k)
        else:
            raise ValueError("NW must be provided (e.g. 2.5, 3, 3.5, 4")
    elif e != None and v != None:
        eigenvalues = v[:]
        tapers = e[:]
    else:
        raise ValueError("if e provided, v must be provided as well and viceversa.")
    nwin = len(eigenvalues) # length of the eigen values vector to be used later

    # set the NFFT
    if NFFT==None:
        NFFT = max(256, 2**nextpow2(N))
    # si nfft smaller thqn N, cut otherwise add wero.
    # compute 
    if method in ['eigen', 'unity']:
        if method == 'unity':
            weights = np.ones((nwin, 1))
        elif method == 'eigen':
            # The S_k spectrum can be weighted by the eigenvalues, as in Park et al. 
            weights = np.array([_x/float(i+1) for i,_x in enumerate(eigenvalues)])
            weights = weights.reshape(nwin,1)

        Sk = abs(np.fft.fft(np.multiply(tapers.transpose(), x), NFFT))**2
        Sk = np.mean(Sk * weights, axis=0)


    elif method == 'adapt':
        # This version uses the equations from [2] (P&W pp 368-370).

        # Wrap the data modulo nfft if N > nfft
        sig2 = np.dot(x, x) / float(N)
        Sk = abs(np.fft.fft(np.multiply(tapers.transpose(), x), NFFT))**2
        Sk = Sk.transpose()
        S = (Sk[:,0] + Sk[:,1]) / 2    # Initial spectrum estimate
        S = S.reshape(NFFT, 1)
        Stemp = np.zeros((NFFT,1))
        S1 = np.zeros((NFFT,1))
        # Set tolerance for acceptance of spectral estimate:
        tol = 0.0005 * sig2 / float(NFFT)
        i = 0
        a = sig2 * (1 - eigenvalues)

        # converges very quickly but for safety; set i<100
        while sum(np.abs(S-S1))/NFFT > tol and i<100:
            i = i + 1
            # calculate weights
            b1 = np.multiply(S, np.ones((1,nwin))) 
            b2 = np.multiply(S,eigenvalues.transpose()) + np.ones((NFFT,1))*eigenvalues.transpose()
            b = b1/b2
            
            # calculate new spectral estimate
            wk=(b**2)*(np.ones((NFFT,1))*eigenvalues.transpose())
            S1 = sum(wk.transpose()*Sk.transpose())/ sum(wk.transpose())
            S1 = S1.reshape(NFFT, 1)
            Stemp = S1
            S1 = S
            S = Stemp   # swap S and S1
        Sk = S
    #clf(); p.plot(); plot(arange(0,0.5,1./512),20*log10(res[0:256]))
    if show==True:
        semilogy(Sk)
    return Sk
Esempio n. 6
0
def pmtm(x, NW=None, k=None, NFFT=None, e=None, v=None, method="adapt", show=True):
    """Multitapering spectral estimation

    :param array x: the data
    :param float NW: The time half bandwidth parameter (typical values are 2.5,3,3.5,4). Must be provided otherwise the tapering windows and eigen values (outputs of dpss) must be provided  
    :param int k: uses the first k Slepian sequences. If *k* is not provided, *k* is set to *NW*2*.
    :param NW
    :param e: the matrix containing the tapering windows
    :param v: the window concentrations (eigenvalues)
    :param str method: set how the eigenvalues are used. Must be in ['unity', 'adapt', 'eigen']
    :param bool show: plot results


    Usually in spectral estimation the mean to reduce bias is to use tapering window. 
    In order to reduce variance we need to average different spectrum. The problem 
    is that we have only one set of data. Thus we need to decompose a set into several 
    segments. Such method are well-known: simple daniell's periodogram, Welch's method
    and so on. The drawback of such methods is a loss of resolution since the segments 
    used to compute the spectrum are smaller than the data set. 
    The interest of multitapering method is to keep a good resolution while reducing 
    bias and variance. 

    How does it work? First we compute different simple periodogram with the whole data 
    set (to keep good resolution) but each periodgram is computed with a different 
    tapering windows. Then, we average all these spectrum. To avoid redundancy and bias
    due to the tapers mtm use special tapers.

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import *

        data = data_cosine(N=2048, A=0.1, sampling=1024, freq=200)
        # If you already have the DPSS windows
        [tapers, eigen] = dpss(2048, 2.5, 4)
        res = pmtm(data, e=tapers, v=eigen, show=False)
        # You do not need to compute the DPSS before end
        res = pmtm(data, NW=2.5, show=False)
        res = pmtm(data, NW=2.5, k=4, show=True)

    """
    assert method in ["adapt", "eigen", "unity"]

    N = len(x)

    # if dpss not provided, compute them
    if e is None and v is None:
        if NW != None:
            [tapers, eigenvalues] = dpss(N, NW, k=k)
        else:
            raise ValueError("NW must be provided (e.g. 2.5, 3, 3.5, 4")
    elif e != None and v != None:
        eigenvalues = v[:]
        tapers = e[:]
    else:
        raise ValueError("if e provided, v must be provided as well and viceversa.")
    nwin = len(eigenvalues)  # length of the eigen values vector to be used later

    # set the NFFT
    if NFFT == None:
        NFFT = max(256, 2 ** nextpow2(N))
    # si nfft smaller thqn N, cut otherwise add wero.
    # compute
    if method in ["eigen", "unity"]:
        if method == "unity":
            weights = np.ones((nwin, 1))
        elif method == "eigen":
            # The S_k spectrum can be weighted by the eigenvalues, as in Park et al.
            weights = np.array([_x / float(i + 1) for i, _x in enumerate(eigenvalues)])
            weights = weights.reshape(nwin, 1)

        Sk = abs(np.fft.fft(np.multiply(tapers.transpose(), x), NFFT)) ** 2
        Sk = np.mean(Sk * weights, axis=0)

    elif method == "adapt":
        # This version uses the equations from [2] (P&W pp 368-370).

        # Wrap the data modulo nfft if N > nfft
        sig2 = np.dot(x, x) / float(N)
        Sk = abs(np.fft.fft(np.multiply(tapers.transpose(), x), NFFT)) ** 2
        Sk = Sk.transpose()
        S = (Sk[:, 0] + Sk[:, 1]) / 2  # Initial spectrum estimate
        S = S.reshape(NFFT, 1)
        Stemp = np.zeros((NFFT, 1))
        S1 = np.zeros((NFFT, 1))
        # Set tolerance for acceptance of spectral estimate:
        tol = 0.0005 * sig2 / float(NFFT)
        i = 0
        a = sig2 * (1 - eigenvalues)

        # converges very quickly but for safety; set i<100
        while sum(np.abs(S - S1)) / NFFT > tol and i < 100:
            i = i + 1
            # calculate weights
            b1 = np.multiply(S, np.ones((1, nwin)))
            b2 = np.multiply(S, eigenvalues.transpose()) + np.ones((NFFT, 1)) * eigenvalues.transpose()
            b = b1 / b2

            # calculate new spectral estimate
            wk = (b ** 2) * (np.ones((NFFT, 1)) * eigenvalues.transpose())
            S1 = sum(wk.transpose() * Sk.transpose()) / sum(wk.transpose())
            S1 = S1.reshape(NFFT, 1)
            Stemp = S1
            S1 = S
            S = Stemp  # swap S and S1
        Sk = S
    # clf(); p.plot(); plot(arange(0,0.5,1./512),20*log10(res[0:256]))
    if show == True:
        semilogy(Sk)
    return Sk
Esempio n. 7
0
#   method = 'linear'
#   idx_u = np.isnan(km.u)
#   km.u[idx_u] = interp1d(t[~idx_u], km.u[~idx_u], kind=method, fill_value='extrapolate')
#plt.figure()
#plt.plot(t,km.u)
#plt.show(block=False)

# Post-processing of the data
km.ref_u = u[8,8,:] # referebce point, hub centre u component
km.ref_v = v[8,8,:] # reference point, v omp
km.ref_w = w[8,8,:] # ref point, w comp

# Measure the spectral densities, coherence and decay factor
km.win = 2**7
km.noverlap = km.win*3/4
km.Nfft = 2**nextpow2(km.ref_u.size)
km.dt = np.nanmean(np.diff(t))
km.Fs = 1/km.dt
km.T = t[-1]
km.t = np.arange(km.dt,km.T,km.dt)
km.N = u.size
km.k = np.fix((km.N-km.noverlap)/(km.win-km.noverlap))
km.df = 1/km.T
km.f = (np.arange(km.t.size)/2)*km.df
km.kw = 2*math.pi*km.f/np.nanmean(u)
km.Spectrum = 'twosided'
km.W = np.fft.fft(np.hamming(km.win))
km.WW = km.W*km.W.conj()
km.KMU = sum(km.WW)*km.k*(1/km.win)*km.Fs

# Statistics of the turbulent field
Esempio n. 8
0
def pmtm(x,
         NW=None,
         k=None,
         NFFT=None,
         e=None,
         v=None,
         method='adapt',
         show=False):
    """Multitapering spectral estimation

    :param array x: the data
    :param float NW: The time half bandwidth parameter (typical values are
        2.5,3,3.5,4). Must be provided otherwise the tapering windows and
        eigen values (outputs of dpss) must be provided
    :param int k: uses the first k Slepian sequences. If *k* is not provided,
        *k* is set to *NW*2*.
    :param NW:
    :param e: the window concentrations (eigenvalues)
    :param v: the matrix containing the tapering windows
    :param str method: set how the eigenvalues are used when weighting the
        results. Must be in ['unity', 'adapt', 'eigen']. see below for details.
    :param bool show: plot results
    :return: Sk (complex), weights, eigenvalues

    Usually in spectral estimation the mean to reduce bias is to use tapering
    window. In order to reduce variance we need to average different spectrum.
    The problem is that we have only one set of data. Thus we need to
    decompose a set into several segments. Such method are well-known: simple
    daniell's periodogram, Welch's method and so on. The drawback of such
    methods is a loss of resolution since the segments used to compute the
    spectrum are smaller than the data set.
    The interest of multitapering method is to keep a good resolution while
    reducing bias and variance.

    How does it work? First we compute different simple periodogram with the
    whole data set (to keep good resolution) but each periodgram is computed
    with a different tapering windows. Then, we average all these spectrum.
    To avoid redundancy and bias due to the tapers mtm use special tapers.

    Method can be eigen, unity or adapt. If *unity*, weights are set to 1. If
    *eigen* are proportional to the eigen-values. If *adapt*, equations from 
    [2] (P&W pp 368-370) are used.

    The output is made of 2 matrices called *Sk* and *weights*. The third item
    stored the eigenvalues. The two matrices have dimensions equal to the number
    of windows used multiplied by the number of input points. The first matrix
    stored the spectral results while the second stores the weights.

    Would you wish to plot the spectrum, you will have to take the means of the
    different windows and weight down the results before mean(Sk *  weigths). Please see the
    code for details.

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import data_cosine, dpss, pmtm

        data = data_cosine(N=2048, A=0.1, sampling=1024, freq=200)
        # If you already have the DPSS windows
        [tapers, eigen] = dpss(2048, 2.5, 4)
        res = pmtm(data, e=eigen, v=tapers, show=False)
        # You do not need to compute the DPSS before end
        res = pmtm(data, NW=2.5, show=False)
        res = pmtm(data, NW=2.5, k=4, show=True)


    .. versionchanged:: 0.6.2

        APN modified method to return each Sk as complex values, the eigenvalues
        and the weights

    """
    assert method in ['adapt', 'eigen', 'unity']

    N = len(x)

    # if dpss not provided, compute them
    if e is None and v is None:
        if NW is not None:
            [tapers, eigenvalues] = dpss(N, NW, k=k)
        else:
            raise ValueError("NW must be provided (e.g. 2.5, 3, 3.5, 4")
    elif e is not None and v is not None:
        eigenvalues = e[:]
        tapers = v[:]
    else:
        raise ValueError(
            "if e provided, v must be provided as well and viceversa.")
    nwin = len(
        eigenvalues)  # length of the eigen values vector to be used later

    # set the NFFT
    if NFFT == None:
        NFFT = max(256, 2**nextpow2(N))

    Sk_complex = np.fft.fft(np.multiply(tapers.transpose(), x), NFFT)
    Sk = abs(Sk_complex)**2

    # si nfft smaller thqn N, cut otherwise add wero.
    # compute
    if method in ['eigen', 'unity']:
        if method == 'unity':
            weights = np.ones((nwin, 1))
        elif method == 'eigen':
            # The S_k spectrum can be weighted by the eigenvalues, as in Park et al.
            weights = np.array(
                [_x / float(i + 1) for i, _x in enumerate(eigenvalues)])
            weights = weights.reshape(nwin, 1)

    elif method == 'adapt':
        # This version uses the equations from [2] (P&W pp 368-370).

        # Wrap the data modulo nfft if N > nfft
        sig2 = np.dot(x, x) / float(N)
        Sk = abs(np.fft.fft(np.multiply(tapers.transpose(), x), NFFT))**2
        Sk = Sk.transpose()
        S = (Sk[:, 0] + Sk[:, 1]) / 2  # Initial spectrum estimate
        S = S.reshape(NFFT, 1)
        Stemp = np.zeros((NFFT, 1))
        S1 = np.zeros((NFFT, 1))
        # Set tolerance for acceptance of spectral estimate:
        tol = 0.0005 * sig2 / float(NFFT)
        i = 0
        a = sig2 * (1 - eigenvalues)
        wk = np.ones((NFFT, 1)) * eigenvalues.transpose()

        # converges very quickly but for safety; set i<100
        while sum(np.abs(S - S1)) / NFFT > tol and i < 100:
            i = i + 1
            # calculate weights
            b1 = np.multiply(S, np.ones((1, nwin)))
            b2 = np.multiply(S, eigenvalues.transpose()) + np.ones(
                (NFFT, 1)) * a.transpose()
            b = b1 / b2

            # calculate new spectral estimate
            wk = (b**2) * (np.ones((NFFT, 1)) * eigenvalues.transpose())
            S1 = sum(wk.transpose() * Sk.transpose()) / sum(wk.transpose())
            S1 = S1.reshape(NFFT, 1)
            S, S1 = S1, S  # swap S and S1
        weights = wk

    if show is True:
        print("""To plot the spectrum please use Multitapering class instead of
pmtm. Same syntax but more correct plot. This plotting functionality is kept for
book-keeping but lacks sampling option, and amplitude is not correct.""")
        from pylab import semilogy
        if method == "adapt":
            Sk = np.mean(Sk * weights, axis=1)
        else:
            Sk = np.mean(Sk * weights, axis=0)
        semilogy(Sk)

    return Sk_complex, weights, eigenvalues