コード例 #1
0
ファイル: test_algorithms.py プロジェクト: TomDLT/nitime
def test_dpss_windows():
    "Are the eigenvalues representing spectral concentration near unity"
    # these values from Percival and Walden 1993
    _, l = tsa.dpss_windows(31, 6, 4)
    unos = np.ones(4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 7, 4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 8, 4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 8, 4.2)
    npt.assert_array_almost_equal(l, unos)
コード例 #2
0
ファイル: test_algorithms.py プロジェクト: zyq11223/nitime
def test_dpss_windows():
    "Are the eigenvalues representing spectral concentration near unity"
    # these values from Percival and Walden 1993
    _, l = tsa.dpss_windows(31, 6, 4)
    unos = np.ones(4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 7, 4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 8, 4)
    npt.assert_array_almost_equal(l, unos)
    _, l = tsa.dpss_windows(31, 8, 4.2)
    npt.assert_array_almost_equal(l, unos)
コード例 #3
0
def taper_segments(X, NW=3):
    """Apply taper functions to signal over all chunks

    Parameters
    ==========
    X: np.ndarray
        shape (N_CHUNKS, N_CHANNELS, N_SAMPLES)
        dtype float
        - Chunked input signal
    NW: int
        default 3
        - Time bandwith parameter (copied from matlab function),
        the higher the bandwidth, the more tapers used.

    Returns
    =======
    output: np.ndarray
        shape (N_CHUNKS, N_CHANNELS, N_TAPERS, N_SAMPLES)
        dtype float
        - Signal transformed by applying tapers. Uses N_TAPERS = 2 * NW - 1
    """
    _, _, window_size = X.shape
    n_tapers = 2 * NW - 1

    # Get the taper functions as a matrix
    tapers, _ = ntalg.dpss_windows(window_size, NW, n_tapers)

    # Apply the dpss functions elementwise to the input signal
    return X[:, :, np.newaxis, :] * tapers
コード例 #4
0
ファイル: test_spectral.py プロジェクト: arokem/nitime
def test_dpss_windows():
    """ Test a couple of funky corner cases of DPSS_windows """

    N = 1024
    NW = 0  # Setting NW to 0 triggers the weird corner case in which some of
            # the symmetric tapers have a negative average
    Kmax = 7

    # But that's corrected by the algorithm:
    d, w = tsa.dpss_windows(1024, 0, 7)
    for this_d in d[0::2]:
        npt.assert_equal(this_d.sum(axis=-1) < 0, False)

    # Make sure we interpolate to the proper number of points
    d, w = tsa.dpss_windows(245411, 4, 8, 1000)
    npt.assert_equal(d.shape[-1], 245411)
コード例 #5
0
ファイル: test_spectral.py プロジェクト: zyq11223/nitime
def test_dpss_windows():
    """ Test a couple of funky corner cases of DPSS_windows """

    N = 1024
    NW = 0  # Setting NW to 0 triggers the weird corner case in which some of
    # the symmetric tapers have a negative average
    Kmax = 7

    # But that's corrected by the algorithm:
    d, w = tsa.dpss_windows(1024, 0, 7)
    for this_d in d[0::2]:
        npt.assert_equal(this_d.sum(axis=-1) < 0, False)

    # Make sure we interpolate to the proper number of points
    d, w = tsa.dpss_windows(245411, 4, 8, 1000)
    npt.assert_equal(d.shape[-1], 245411)
コード例 #6
0
ファイル: test_spectral.py プロジェクト: arokem/nitime
def test_dpss_properties():
    """ Test conventions of Slepian eigenvectors """

    N = 2000
    NW = 200
    d, lam = tsa.dpss_windows(N, NW, 2*NW-2)
    # 2NW-2 lamdas should be all > 0.9
    npt.assert_(
        (lam > 0.9).all(), 'Eigenvectors show poor spectral concentration'
        )
    # test orthonomality
    err = np.linalg.norm(d.dot(d.T) - np.eye(2*NW-2), ord='fro')
    npt.assert_(err**2 < 1e-16, 'Eigenvectors not numerically orthonormal')
    # test positivity of even functions
    npt.assert_(
        (d[::2].sum(axis=1) > 0).all(),
        'Even Slepian sequences should have positive DC'
        )
    # test positive initial slope of odd functions
    # (this tests the sign of a linear slope)
    pk = np.argmax(np.abs(d[1::2, :N//2]), axis=1)
    t = True
    for p, f in zip(pk, d[1::2]):
        t = t and np.sum( np.arange(1,p+1) * f[:p] ) >= 0
    npt.assert_(t, 'Odd Slepians should begin positive-going')
コード例 #7
0
    def estimate(self, signal, sample_rate, start_time, end_time, debug=False):

        slen = len(signal)

        #compute DPSS tapers for signals
        NW = max(1, int((slen / sample_rate) * self.bandwidth))
        K = 2 * NW - 1

        tapers, eigs = ntalg.dpss_windows(slen, NW, K)
        ntapers = len(tapers)
        if debug:
            print(
                '[MultiTaperSpectrumEstimator.estimate] slen=%d, NW=%d, K=%d, bandwidth=%0.1f, ntapers: %d'
                % (slen, NW, K, self.bandwidth, ntapers))

        #compute a set of tapered signals
        s_tap = tapers * signal

        #compute the FFT of each tapered signal
        s_fft = fft(s_tap, axis=1)

        #throw away negative frequencies of the spectrum
        cspec_freq = fftfreq(slen, d=1.0 / sample_rate)
        nz = cspec_freq >= 0.0
        s_fft = s_fft[:, nz]
        flen = nz.sum()
        cspec_freq = cspec_freq[nz]
        #print '(1)cspec_freq.shape=',cspec_freq.shape
        #print '(1)s_fft.shape=',s_fft.shape

        #determine the weights used to combine the tapered signals
        if self.adaptive and ntapers > 1:
            #compute the adaptive weights
            weights, weights_dof = ntutils.adaptive_weights(
                s_fft, eigs, sides='twosided', max_iter=self.max_adaptive_iter)
        else:
            weights = np.ones([ntapers, flen]) / float(ntapers)

        #print '(1)weights.shape=',weights.shape

        def make_spectrum(signal, signal_weights):
            denom = (signal_weights**2).sum(axis=0)
            return (np.abs(signal * signal_weights)**2).sum(axis=0) / denom

        if self.jackknife:
            #do leave-one-out cross validation to estimate the complex mean and standard deviation of the spectrum
            cspec_mean = np.zeros([flen], dtype='complex')
            for k in range(ntapers):
                index = range(ntapers)
                del index[k]
                #compute an estimate of the spectrum using all but the kth weight
                cspec_est = make_spectrum(s_fft[index, :], weights[index, :])
                cspec_diff = cspec_est - cspec_mean
                #do an online update of the mean spectrum
                cspec_mean += cspec_diff / (k + 1)
        else:
            #compute the average complex spectrum weighted across tapers
            cspec_mean = make_spectrum(s_fft, weights)

        return cspec_freq, cspec_mean.squeeze()
コード例 #8
0
ファイル: timefreq.py プロジェクト: mschachter/LaSP
    def estimate(self, signal, sample_rate, start_time, end_time, debug=False):

        slen = len(signal)

        #compute DPSS tapers for signals
        NW = max(1, int((slen / sample_rate)*self.bandwidth))
        K = 2*NW - 1

        tapers, eigs = ntalg.dpss_windows(slen, NW, K)
        ntapers = len(tapers)
        if debug:
            print '[MultiTaperSpectrumEstimator.estimate] slen=%d, NW=%d, K=%d, bandwidth=%0.1f, ntapers: %d' % (slen, NW, K, self.bandwidth, ntapers)

        #compute a set of tapered signals
        s_tap = tapers * signal

        #compute the FFT of each tapered signal
        s_fft = fft(s_tap, axis=1)

        #throw away negative frequencies of the spectrum
        cspec_freq = fftfreq(slen, d=1.0/sample_rate)
        nz = cspec_freq >= 0.0
        s_fft = s_fft[:, nz]
        flen = nz.sum()
        cspec_freq = cspec_freq[nz]
        #print '(1)cspec_freq.shape=',cspec_freq.shape
        #print '(1)s_fft.shape=',s_fft.shape

        #determine the weights used to combine the tapered signals
        if self.adaptive and ntapers > 1:
            #compute the adaptive weights
            weights,weights_dof = ntutils.adaptive_weights(s_fft, eigs, sides='twosided', max_iter=self.max_adaptive_iter)
        else:
            weights = np.ones([ntapers, flen]) / float(ntapers)

        #print '(1)weights.shape=',weights.shape

        def make_spectrum(signal, signal_weights):
            denom = (signal_weights**2).sum(axis=0)
            return (np.abs(signal * signal_weights)**2).sum(axis=0) / denom

        if self.jackknife:
            #do leave-one-out cross validation to estimate the complex mean and standard deviation of the spectrum
            cspec_mean = np.zeros([flen], dtype='complex')
            for k in range(ntapers):
                index = range(ntapers)
                del index[k]
                #compute an estimate of the spectrum using all but the kth weight
                cspec_est = make_spectrum(s_fft[index, :], weights[index, :])
                cspec_diff = cspec_est - cspec_mean
                #do an online update of the mean spectrum
                cspec_mean += cspec_diff / (k+1)
        else:
            #compute the average complex spectrum weighted across tapers
            cspec_mean = make_spectrum(s_fft, weights)

        return cspec_freq,cspec_mean.squeeze()
コード例 #9
0
ファイル: test_algorithms.py プロジェクト: TomDLT/nitime
def test_long_dpss_win():
    """ Test that very long dpss windows can be generated (using interpolation)"""

    # This one is generated using interpolation:
    a1,e = tsa.dpss_windows(166800, 4, 8, interp_from=4096)

    # This one is calculated:
    a2,e = tsa.dpss_windows(166800, 4, 8)

    # They should be very similar:
    npt.assert_almost_equal(a1, a2, decimal=5)

    # They should both be very similar to the same one calculated in matlab
    # (using 'a = dpss(166800, 4, 8)').
    test_dir_path = os.path.join(nitime.__path__[0], 'tests')
    matlab_long_dpss = np.load(os.path.join(test_dir_path, 'long_dpss_matlab.npy'))
    # We only have the first window to compare against:
    # Both for the interpolated case:
    npt.assert_almost_equal(a1[0], matlab_long_dpss, decimal=5)
    # As well as the calculated case:
    npt.assert_almost_equal(a1[0], matlab_long_dpss, decimal=5)
コード例 #10
0
ファイル: test_spectral.py プロジェクト: ilustreous/nitime
def test_dpss_windows():
    """ Test a funky corner case of DPSS_windows """  

    N = 1024
    NW = 0 # Setting NW to 0 triggers the weird corner case in which some of
           # the symmetric tapers have a negative average
    Kmax = 7

    # But that's corrected by the algorithm:
    d,w=tsa.dpss_windows(1024, 0, 7)
    for this_d in d[0::2]:
        npt.assert_equal(this_d.sum(axis=-1)< 0, False)
コード例 #11
0
def test_dpss_windows():
    """ Test a funky corner case of DPSS_windows """

    N = 1024
    NW = 0  # Setting NW to 0 triggers the weird corner case in which some of
    # the symmetric tapers have a negative average
    Kmax = 7

    # But that's corrected by the algorithm:
    d, w = tsa.dpss_windows(1024, 0, 7)
    for this_d in d[0::2]:
        npt.assert_equal(this_d.sum(axis=-1) < 0, False)
コード例 #12
0
ファイル: test_algorithms.py プロジェクト: zyq11223/nitime
def test_long_dpss_win():
    """ Test that very long dpss windows can be generated (using interpolation)"""

    # This one is generated using interpolation:
    a1, e = tsa.dpss_windows(166800, 4, 8, interp_from=4096)

    # This one is calculated:
    a2, e = tsa.dpss_windows(166800, 4, 8)

    # They should be very similar:
    npt.assert_almost_equal(a1, a2, decimal=5)

    # They should both be very similar to the same one calculated in matlab
    # (using 'a = dpss(166800, 4, 8)').
    test_dir_path = os.path.join(nitime.__path__[0], 'tests')
    matlab_long_dpss = np.load(
        os.path.join(test_dir_path, 'long_dpss_matlab.npy'))
    # We only have the first window to compare against:
    # Both for the interpolated case:
    npt.assert_almost_equal(a1[0], matlab_long_dpss, decimal=5)
    # As well as the calculated case:
    npt.assert_almost_equal(a1[0], matlab_long_dpss, decimal=5)
コード例 #13
0
ファイル: test_algorithms.py プロジェクト: zyq11223/nitime
def test_dpss_matlab():
    """Do the dpss windows resemble the equivalent matlab result

    The variable b is read in from a text file generated by issuing:

    dpss(100,2)

    in matlab

    """
    a, _ = tsa.dpss_windows(100, 2, 4)
    b = np.loadtxt(os.path.join(test_dir_path, 'dpss_matlab.txt'))
    npt.assert_almost_equal(a, b.T)
コード例 #14
0
ファイル: test_algorithms.py プロジェクト: TomDLT/nitime
def test_dpss_matlab():
    """Do the dpss windows resemble the equivalent matlab result

    The variable b is read in from a text file generated by issuing:

    dpss(100,2)

    in matlab

    """
    a, _ = tsa.dpss_windows(100, 2, 4)
    b = np.loadtxt(os.path.join(test_dir_path, 'dpss_matlab.txt'))
    npt.assert_almost_equal(a, b.T)
コード例 #15
0
ファイル: test_spectral.py プロジェクト: ilustreous/nitime
def test_mtm_cross_spectrum():
    """
    
    Test the multi-taper cross-spectral estimation. Based on the example in
    doc/examples/multi_taper_coh.py

    """ 
    NW = 4
    K = 2 * NW - 1

    N = 2 ** 10
    n_reps = 10
    n_freqs = N

    tapers, eigs = tsa.dpss_windows(N, NW, 2 * NW - 1)

    est_psd = []
    for k in xrange(n_reps):
        data,nz,alpha = utils.ar_generator(N=N)
        fgrid, hz = tsa.freq_response(1.0, a=np.r_[1, -alpha], n_freqs=n_freqs)
        # 'one-sided', so multiply by 2:
        psd = 2 * (hz * hz.conj()).real

        tdata = tapers * data

        tspectra = np.fft.fft(tdata)

        L = N / 2 + 1
        sides = 'onesided'
        w, _ = utils.adaptive_weights(tspectra, eigs, sides=sides)

        sxx = tsa.mtm_cross_spectrum(tspectra, tspectra, w, sides=sides)
        est_psd.append(sxx)

    fxx = np.mean(est_psd, 0)

    psd_ratio = np.mean(fxx / psd)

    # This is a rather lenient test, making sure that the average ratio is 1 to
    # within an order of magnitude. That is, that they are equal on average:
    npt.assert_array_almost_equal(psd_ratio, 1, decimal=1)

    # Test raising of error in case the inputs don't make sense:
    npt.assert_raises(ValueError,
                      tsa.mtm_cross_spectrum,
                      tspectra,np.r_[tspectra, tspectra],
                      (w, w))
コード例 #16
0
def test_mtm_cross_spectrum():
    """

    Test the multi-taper cross-spectral estimation. Based on the example in
    doc/examples/multi_taper_coh.py

    """
    NW = 4
    K = 2 * NW - 1

    N = 2**10
    n_reps = 10
    n_freqs = N

    tapers, eigs = tsa.dpss_windows(N, NW, 2 * NW - 1)

    est_psd = []
    for k in range(n_reps):
        data, nz, alpha = utils.ar_generator(N=N)
        fgrid, hz = tsa.freq_response(1.0, a=np.r_[1, -alpha], n_freqs=n_freqs)
        # 'one-sided', so multiply by 2:
        psd = 2 * (hz * hz.conj()).real

        tdata = tapers * data

        tspectra = fftpack.fft(tdata)

        L = N / 2 + 1
        sides = 'onesided'
        w, _ = utils.adaptive_weights(tspectra, eigs, sides=sides)

        sxx = tsa.mtm_cross_spectrum(tspectra, tspectra, w, sides=sides)
        est_psd.append(sxx)

    fxx = np.mean(est_psd, 0)

    psd_ratio = np.mean(fxx / psd)

    # This is a rather lenient test, making sure that the average ratio is 1 to
    # within an order of magnitude. That is, that they are equal on average:
    npt.assert_array_almost_equal(psd_ratio, 1, decimal=1)

    # Test raising of error in case the inputs don't make sense:
    npt.assert_raises(ValueError, tsa.mtm_cross_spectrum, tspectra,
                      np.r_[tspectra, tspectra], (w, w))
コード例 #17
0
def test_dpss_properties():
    """ Test conventions of Slepian eigenvectors """

    N = 2000
    NW = 200
    d, lam = tsa.dpss_windows(N, NW, 2 * NW - 2)
    # 2NW-2 lamdas should be all > 0.9
    nt.assert_true((lam > 0.9).all(),
                   'Eigenvectors show poor spectral concentration')
    # test orthonomality
    err = np.linalg.norm(d.dot(d.T) - np.eye(2 * NW - 2), ord='fro')
    nt.assert_true(err**2 < 1e-16, 'Eigenvectors not numerically orthonormal')
    # test positivity of even functions
    nt.assert_true((d[::2].sum(axis=1) > 0).all(),
                   'Even Slepian sequences should have positive DC')
    # test positive initial slope of odd functions
    # (this tests the sign of a linear slope)
    pk = np.argmax(np.abs(d[1::2, :N / 2]), axis=1)
    t = True
    for p, f in zip(pk, d[1::2]):
        t = t and np.sum(np.arange(1, p + 1) * f[:p]) >= 0
    nt.assert_true(t, 'Odd Slepians should begin positive-going')
コード例 #18
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtspecraw(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Spectrum (of raw signal)

    Parameters
    ----------
    x - Numpy array
        Input data numpy array (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    Normal mode:
        Tuple (mtspecraw, f)
          mtspecraw - multitapered spectrum

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:
          mtspecraw - Multitapered spectrum (channel x frequency)

          f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Raw Spectrum Estimation')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        nchans = x.shape[0]
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        nchans = 1
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the results

    Sraw = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        Sraw[k, :, :] = (abs(xw)**2).mean(axis=trialdim)

    # Average over tapers and squeeze to pretty shapes
    Sraw = Sraw.mean(axis=0)
    Sraw = Sraw[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtspecraw'] = Sraw
        out['f'] = f

        return out
    else:
        return (Sraw, f)
コード例 #19
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtpspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Pairwise Power Spectral estimate

    Parameters
    ----------
    x - Numpy Array
        Input data numpy array (channel x trial x time) or (trials x time)
    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['Npairs'] - Number of pairs for pairwise analysis
    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
      Tuple (pspec, f):
          pspec -  Multitapered Pairwise Power estimate (channel x frequency)

          f - Frequency vector matching plv

    In bootstrap mode:

      Dictionary with following keys:
          pspec -  Multitapered Pairwise Power estimate (channel x frequency)

          f - Frequency vector matching plv

    """
    logger.info('Running Multitaper Pairwise Power Estimate')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    pspec = np.zeros((ntaps, nchans, nfft))

    for ch in np.arange(0, nchans):
        for k, tap in enumerate(w):
            logger.debug('Running Channel # %d, taper #%d', ch, k)
            xw = sci.fft(tap * x, n=nfft, axis=timedim)
            npairs = params['Npairs']
            trial_pairs = np.random.randint(0, ntrials, (npairs, 2))

            # For unbiasedness, pairs should be made of independent trials!
            trial_pairs = trial_pairs[np.not_equal(trial_pairs[:, 0],
                                                   trial_pairs[:, 1])]
            if(nchans == 1):
                xw_1 = xw[trial_pairs[:, 0]]
                xw_2 = xw[trial_pairs[:, 1]]
                pspec[k, ch, :] = np.real((xw_1*xw_2.conj()).mean(axis=0))
            else:
                xw_1 = xw[ch, trial_pairs[:, 0], :]
                xw_2 = xw[ch, trial_pairs[:, 1], :]
                pspec[k, ch, :] = np.real((xw_1*xw_2.conj()).mean(axis=0))

    pspec = pspec.mean(axis=0)
    pspec = pspec[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['pspec'] = pspec
        out['f'] = f

        return out
    else:
        return (pspec, f)
コード例 #20
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Spectrum and SNR estimate

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['noisefloortype'] - (optional) 1: random phase,
      0 (default): flip-phase on half the trials

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:

        (S, N ,f): Tuple
          S - Multitapered spectrum (channel x frequency)

          N - Noise floor estimate

          f - Frequency vector matching S and N

    In bootstrap mode:
        Dictionary with the following keys:
         mtspec - Multitapered spectrum (channel x frequency)

         mtspec_* - Noise floor estimate, where * is 'randomPhase' if
         params['noisefloortype'] == 1, and 'noiseFloorViaPhaseFlip' otherwise

         f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Spectrum and Noise-floor Estimation')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    S = np.zeros((ntaps, nchans, nfft))
    N = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        S[k, :, :] = abs(xw.mean(axis=trialdim))

        if ('noisefloortype' in params) and (params['noisefloortype'] == 1):
            randph = sci.rand(nchans, ntrials, nfft) * 2 * sci.pi
            N[k, :, :] = abs((xw*sci.exp(1j*randph)).mean(axis=trialdim))
            noiseTag = 'noiseFloorViaRandomPhase'
            logger.info('using random phase for noise floor estimate')
        else:
            randsign = np.ones((nchans, ntrials, nfft))

            # reflects fix to bootstrapmode parameter
            if bootstrapMode and 'bootstrapTrialsSelected' in params:
                flipTheseTrials = np.where(
                    (params['bootstrapTrialsSelected'] % 2) == 0)
            else:
                flipTheseTrials = np.arange(0, ntrials, 2)

            randsign[:, flipTheseTrials, :] = -1
            N[k, :, :] = abs((xw*(randsign.squeeze())).mean(axis=trialdim))
            noiseTag = 'noiseFloorViaPhaseFlip'
            logger.info('flipping phase of half of the trials ' +
                        'for noise floor estimate')

    # Average over tapers and squeeze to pretty shapes
    S = S.mean(axis=0)
    N = N.mean(axis=0)
    S = S[:, fInd].squeeze()
    N = N[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtspec'] = S
        out['mtspec_' + noiseTag] = N
        out['f'] = f

        return out
    else:
        return (S, N, f)
コード例 #21
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtcspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper complex PCA and power spectral estimate

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - 1 for ITC, 0 for PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (cspec, f):

          cspec - Multitapered PLV estimate using cPCA

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:

          cspec - Multitapered PLV estimate using cPCA

          f - Frequency vector matching plv
    """

    logger.info('Running Multitaper Complex PCA based power estimation!')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    cspec = np.zeros((ntaps, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        C = (xw.mean(axis=trialdim)).squeeze()
        for fi in np.arange(0, nfft):
            Csd = np.outer(C[:, fi], C[:, fi].conj())
            vals = linalg.eigh(Csd, eigvals_only=True)
            cspec[k, fi] = vals[-1] / nchans

    # Average over tapers and squeeze to pretty shapes
    cspec = (cspec.mean(axis=0)).squeeze()
    cspec = cspec[fInd]

    if bootstrapMode:
        out = {}
        out['mtcspec'] = cspec
        out['f'] = f

        return out
    else:
        return (cspec, f)
コード例 #22
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtplv(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Phase-Locking Value

    Parameters
    ----------
    x - NumPy Array
        Input Data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - 1 for ITC, 0 for PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        (plvtap, f): Tuple
           plvtap - Multitapered phase-locking estimate (channel x frequency)

    In bootstrap mode:
        Dictionary with the following keys:
         mtplv - Multitapered phase-locking estimate (channel x frequency)i

         f - Frequency vector matching plv

    """

    logger.info('Running Multitaper PLV Estimation')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        nchans = x.shape[0]
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry, The data should be a 2 or 3 dimensional array')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    plvtap = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        if(params['itc'] == 0):
            plvtap[k, :, :] = abs((xw/abs(xw)).mean(axis=trialdim))**2
        else:
            plvtap[k, :, :] = ((abs(xw.mean(axis=trialdim))**2) /
                               ((abs(xw) ** 2).mean(axis=trialdim)))

    plvtap = plvtap.mean(axis=0)

    plvtap = plvtap[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtplv'] = plvtap
        out['f'] = f
    else:
        return (plvtap, f)

    return out
コード例 #23
0
ファイル: multi_taper_coh.py プロジェクト: ilustreous/nitime
"""

We start by performing the detailed analysis, but note that a significant
short-cut is presented below, so if you just want to know how to do this
(without needing to understand the details), skip on down.

We start by defining how many tapers will be used and calculate the values of
the tapers and the associated eigenvalues of each taper:

"""

NW = 4
K = 2 * NW - 1

tapers, eigs = alg.dpss_windows(n_samples, NW, K)

"""

We multiply the data by the tapers and derive the fourier transform and the
magnitude of the squared spectra (the power) for each tapered time-series:

"""


tdata = tapers[None, :, :] * pdata[:, None, :]
tspectra = np.fft.fft(tdata)
## mag_sqr_spectra = np.abs(tspectra)
## np.power(mag_sqr_spectra, 2, mag_sqr_spectra)

コード例 #24
0
ファイル: array_analysis.py プロジェクト: ProjectISP/ISP
    def FKCoherence(self, st, inv, DT, linf, lsup, slim, win_len, sinc,
                    method):
        def find_nearest(array, value):

            idx, val = min(enumerate(array), key=lambda x: abs(x[1] - value))
            return idx, val

        sides = 'onesided'
        pi = math.pi

        smax = slim
        smin = -1 * smax
        Sx = np.arange(smin, smax, sinc)[np.newaxis]
        Sy = np.arange(smin, smax, sinc)[np.newaxis]
        nx = ny = len(Sx[0])
        Sy = np.fliplr(Sy)

        #####Convert start from Greogorian to actual date###############
        Time = DT
        Time = Time - int(Time)
        d = date.fromordinal(int(DT))
        date1 = d.isoformat()
        H = (Time * 24)
        H1 = int(H)  # Horas
        minutes = (H - int(H)) * 60
        minutes1 = int(minutes)
        seconds = (minutes - int(minutes)) * 60
        H1 = str(H1).zfill(2)
        minutes1 = str(minutes1).zfill(2)
        seconds = "%.2f" % seconds
        seconds = str(seconds).zfill(2)
        DATE = date1 + "T" + str(H1) + minutes1 + seconds
        t1 = UTCDateTime(DATE)
        ########End conversion###############################

        st.trim(starttime=t1, endtime=t1 + win_len)
        st.sort()
        n = len(st)
        for i in range(n):
            coords = inv.get_coordinates(st[i].id)
            st[i].stats.coordinates = AttribDict({
                'latitude':
                coords['latitude'],
                'elevation':
                coords['elevation'],
                'longitude':
                coords['longitude']
            })

        coord = get_geometry(st, coordsys='lonlat', return_center=True)

        tr = st[0]
        win = len(tr.data)
        if (win % 2) == 0:
            nfft = win / 2 + 1
        else:
            nfft = (win + 1) / 2

        nr = st.count()  # number of stations
        delta = st[0].stats.delta
        fs = 1 / delta
        fn = fs / 2
        freq = np.arange(0, fn, fn / nfft)
        value1, freq1 = find_nearest(freq, linf)
        value2, freq2 = find_nearest(freq, lsup)
        df = value2 - value1
        m = np.zeros((win, nr))

        WW = np.hamming(int(win))
        WW = np.transpose(WW)
        for i in range(nr):
            tr = st[i]
            if method == "FK":
                m[:, i] = (tr.data - np.mean(tr.data)) * WW
            else:
                m[:, i] = (tr.data - np.mean(tr.data))
        pdata = np.transpose(m)

        #####Coherence######
        NW = 2  # the time-bandwidth product##Buena seleccion de 2-3
        K = 2 * NW - 1
        tapers, eigs = alg.dpss_windows(win, NW, K)
        tdata = tapers[None, :, :] * pdata[:, None, :]
        tspectra = fftpack.fft(tdata)

        w = np.empty((nr, int(K), int(nfft)))
        for i in range(nr):
            w[i], _ = utils.adaptive_weights(tspectra[i], eigs, sides=sides)

        nseq = nr
        L = int(nfft)
        #csd_mat = np.zeros((nseq, nseq, L), 'D')
        #psd_mat = np.zeros((2, nseq, nseq, L), 'd')
        coh_mat = np.zeros((nseq, nseq, L), 'd')
        #coh_var = np.zeros_like(coh_mat)
        Cx = np.ones((nr, nr, df), dtype=np.complex128)

        if method == "MTP.COHERENCE":
            for i in range(nr):
                for j in range(nr):
                    sxy = alg.mtm_cross_spectrum(tspectra[i], (tspectra[j]),
                                                 (w[i], w[j]),
                                                 sides='onesided')
                    sxx = alg.mtm_cross_spectrum(tspectra[i],
                                                 tspectra[i],
                                                 w[i],
                                                 sides='onesided')
                    syy = alg.mtm_cross_spectrum(tspectra[j],
                                                 tspectra[j],
                                                 w[j],
                                                 sides='onesided')
                    s = sxy / np.sqrt((sxx * syy))
                    cxcohe = s[value1:value2]
                    Cx[i, j, :] = cxcohe

        # Calculates Conventional FK-power
        if method == "FK":
            for i in range(nr):
                for j in range(nr):
                    A = np.fft.rfft(m[:, i])
                    B = np.fft.rfft(m[:, j])
                    #Relative Power
                    den = np.absolute(A) * np.absolute(np.conjugate(B))
                    out = (A * np.conjugate(B)) / den
                    cxcohe = out[value1:value2]
                    Cx[i, j, :] = cxcohe

        r = np.zeros((nr, 2), dtype=np.complex128)
        S = np.zeros((1, 2), dtype=np.complex128)
        Pow = np.zeros((len(Sx[0]), len(Sy[0]), df))
        for n in range(nr):
            r[n, :] = coord[n][0:2]

        freq = freq[value1:value2]

        for i in range(ny):
            for j in range(nx):
                S[0, 0] = Sx[0][j]
                S[0, 1] = Sy[0][i]
                k = (S * r)
                K = np.sum(k, axis=1)
                n = 0
                for f in freq:
                    A = np.exp(-1j * 2 * pi * f * K)
                    B = np.conjugate(np.transpose(A))
                    D = np.matmul(B, Cx[:, :, n]) / nr
                    P = np.matmul(D, A) / nr
                    Pow[i, j, n] = np.abs(P)
                    n = n + 1
        Pow = np.mean(Pow, axis=2)
        #Pow = Pow / len(freq)
        Pow = np.fliplr(Pow)
        x = y = np.linspace(smin, smax, nx)

        nn = len(x)
        maximum_power = np.where(Pow == np.amax(Pow))
        Sxpow = (maximum_power[1] - nn / 2) * sinc
        Sypow = (maximum_power[0] - nn / 2) * sinc

        return Pow, Sxpow, Sypow, coord
コード例 #25
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtcpca_timeDomain(x, params, verbose=None, bootstrapMode=False):
    """Multitaper complex PCA and regular time-domain PCA and return time
    domain waveforms.

    Note of caution
    ---------------
    The cPCA method is not really suited to extract fast transient features of
    the time domain waveform. This is because, the frequency domain
    representation of any signal (when you think of it as random process) is
    interpretable only when the signal is stationary, i.e., in steady-state.
    Practically speaking, the process of transforming short epochs to the
    frequency domain necessarily involves smoothing in frequency. This
    leakage is minimized by tapering the original signal using DPSS windows,
    also known as Slepian sequences. The effect of this tapering would be
    present when going back to the time domain. Note that only a single taper
    is used here as combining tapers with different symmetries in the time-
    domain leads to funny cancellations.

    Also, for transient features, simple time-domain PCA is likely
    to perform better as the cPCA smoothes out transient features. Thus
    both regular time-domain PCA and cPCA outputs are returned.

    Note that for sign of the output is indeterminate (you may need to flip
    the output to match the polarity of signal channel responses)

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (y_cpc, y_pc):
          'y_cpc' - Multitapered cPCA estimate of time-domain waveform

          'y_pc' - Regular time-domain PCA

    In bootstrap mode:
        Dictionary with the following keys:
          'y_cpc' - Multitapered cPCA estimate of time-domain waveform

          'y_pc' - Regular time-domain PCA

    """

    logger.info('Running Multitaper Complex PCA to extract time waveform!')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    w, conc = dpss_windows(x.shape[timedim], 1, 1)
    w = w.squeeze() / w.max()

    cpc_freq = np.zeros(nfft, dtype=np.complex)
    cspec = np.zeros(nfft)
    xw = sci.fft(w * x, n=nfft, axis=timedim)
    C = (xw.mean(axis=trialdim)).squeeze()
    Cnorm = C / ((abs(xw).mean(axis=trialdim)).squeeze())
    for fi in np.arange(0, nfft):
        Csd = np.outer(Cnorm[:, fi], Cnorm[:, fi].conj())
        vals, vecs = linalg.eigh(Csd, eigvals_only=False)
        cspec[fi] = vals[-1]
        cwts = vecs[:, -1] / (np.abs(vecs[:, -1]).sum())
        cpc_freq[fi] = (cwts.conjugate() * C[:, fi]).sum()

    # Filter through spectrum, do ifft.
    cscale = cspec**0.5
    cscale = cscale / cscale.max()  # Maxgain of filter = 1
    y_cpc = sci.ifft(cpc_freq * cscale)[:x.shape[timedim]]

    # Do time domain PCA
    x_ave = x.mean(axis=trialdim)
    C_td = np.cov(x_ave)
    vals, vecs = linalg.eigh(C_td, eigvals_only=False)
    y_pc = np.dot(vecs[:, -1].T, x_ave) / (vecs[:, -1].sum())

    if bootstrapMode:
        out = {}
        out['y_cpc'] = y_cpc
        out['y_pc'] = y_pc

        return out
    else:
        return (y_cpc, y_pc)
コード例 #26
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtcspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper complex PCA and power spectral estimate

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - 1 for ITC, 0 for PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (cspec, f):

          cspec - Multitapered PLV estimate using cPCA

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:

          cspec - Multitapered PLV estimate using cPCA

          f - Frequency vector matching plv
    """

    logger.info('Running Multitaper Complex PCA based power estimation!')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    cspec = np.zeros((ntaps, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        C = (xw.mean(axis=trialdim)).squeeze()
        for fi in np.arange(0, nfft):
            Csd = np.outer(C[:, fi], C[:, fi].conj())
            vals = linalg.eigh(Csd, eigvals_only=True)
            cspec[k, fi] = vals[-1] / nchans

    # Average over tapers and squeeze to pretty shapes
    cspec = (cspec.mean(axis=0)).squeeze()
    cspec = cspec[fInd]

    if bootstrapMode:
        out = {}
        out['mtcspec'] = cspec
        out['f'] = f

        return out
    else:
        return (cspec, f)
コード例 #27
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtphase(x, params, verbose=None, bootstrapMode=False):
    """Multitaper phase estimation

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns:
    -------
    In normal mode:
        (Ph, f): Tuple
          Ph - Multitapered phase spectrum (channel x frequency)

          f - Frequency vector matching S and N

    In bootstrap mode:
        Dictionary with the following keys:

        Ph - Multitapered phase spectrum (channel x frequency)

        f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Spectrum and Noise-floor Estimation')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    Ph = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        Ph[k, :, :] = np.angle(xw.mean(axis=trialdim))

    # Average over tapers and squeeze to pretty shapes
    Ph = Ph[:, :, fInd].mean(axis=0).squeeze()

    if bootstrapMode:
        out = {}
        out['mtphase'] = Ph
        out['f'] = f

        return out
    else:
        return (Ph, f)
コード例 #28
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Spectrum and SNR estimate

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['noisefloortype'] - (optional) 1: random phase,
      0 (default): flip-phase on half the trials

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:

        (S, N ,f): Tuple
          S - Multitapered spectrum (channel x frequency)

          N - Noise floor estimate

          f - Frequency vector matching S and N

    In bootstrap mode:
        Dictionary with the following keys:
         mtspec - Multitapered spectrum (channel x frequency)

         mtspec_* - Noise floor estimate, where * is 'randomPhase' if
         params['noisefloortype'] == 1, and 'noiseFloorViaPhaseFlip' otherwise

         f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Spectrum and Noise-floor Estimation')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    S = np.zeros((ntaps, nchans, nfft))
    N = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        S[k, :, :] = abs(xw.mean(axis=trialdim))

        if ('noisefloortype' in params) and (params['noisefloortype'] == 1):
            randph = sci.rand(nchans, ntrials, nfft) * 2 * sci.pi
            N[k, :, :] = abs((xw * sci.exp(1j * randph)).mean(axis=trialdim))
            noiseTag = 'noiseFloorViaRandomPhase'
            logger.info('using random phase for noise floor estimate')
        else:
            randsign = np.ones((nchans, ntrials, nfft))

            # reflects fix to bootstrapmode parameter
            if bootstrapMode and 'bootstrapTrialsSelected' in params:
                flipTheseTrials = np.where((params['bootstrapTrialsSelected'] %
                                            2) == 0)
            else:
                flipTheseTrials = np.arange(0, ntrials, 2)

            randsign[:, flipTheseTrials, :] = -1
            N[k, :, :] = abs((xw * (randsign.squeeze())).mean(axis=trialdim))
            noiseTag = 'noiseFloorViaPhaseFlip'
            logger.info('flipping phase of half of the trials ' +
                        'for noise floor estimate')

    # Average over tapers and squeeze to pretty shapes
    S = S.mean(axis=0)
    N = N.mean(axis=0)
    S = S[:, fInd].squeeze()
    N = N[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtspec'] = S
        out['mtspec_' + noiseTag] = N
        out['f'] = f

        return out
    else:
        return (S, N, f)
コード例 #29
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def _mtcpca_complete(x, params, verbose=None, bootstrapMode=False):
    """
    Internal convenience function to obtain plv and spectrum with cpca and
    multitaper.  Equivalent to calling:

    spectral.mtcpca(data, params, ...)
    spectral.mtcspec(data, params, ...)

    With the exception that this function returns a dictionary for S + N, each
    of which have keys "plv_*" and "spectrum_*", where * is "normalPhase" or
    "noiseFloorViaPhaseFlip".

    Gets power spectra and plv on the same set of data using multitaper and
    complex PCA. Returns a noise floor esimate of each by running the same
    computations on the original data, as well as the original data with the
    phase of half of the trials flipped. For a large number of trials, the
    spectra of the data and the half-trials-phase-flipped data should be
    similar, while the PLV values for the half-trials-flipped data should be
    hovering near the PLV value of off-frequency components in the original
    data.

    Primarily useful when debugging, bootstrapping, or when using scripts that
    for some reason randomizes data in between calls to mtcpca and mtcspec.


    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - dictionary. Must contain the following fields:
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - If True, normalize after mean like ITC instead of PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (S, N, f)

        Where S and N are data for signal and for noise floor, respectively,
        each as a dictionary with the following keys:

          mtcpcaSpectrum - Multitapered power spectral estimate using cPCA

          mtcpcaPLV- Multitapered PLV using cPCA

        f - frequency vector

    In bootstrap mode:
        dictionary with keys:
          mtcpcaSpectrum_* - Multitapered power spectral estimate using cPCA

          mtcpcaPLV_*- Multitapered PLV using cPCA

          f - frequency vector

     where * in the above is the type of noise floor
    """

    out = {}

    logger.info('Running Multitaper Complex PCA based ' +
                'plv and power estimation.')
    x = x.squeeze()
    if len(x.shape) == 3:
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers

    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]

    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    plv = np.zeros((ntaps, len(f)))
    cspec = np.zeros((ntaps, len(f)))

    phaseTypes = list(['normalPhase', 'noiseFloorViaPhaseFlip'])

    for thisType in phaseTypes:
        if thisType == 'noiseFloorViaPhaseFlip':
            # flip the phase of every other trial
            phaseFlipper = np.ones(x.shape)

            # important change: when noise floor is computed, it will
            # only select trials that were originally labeled as even-numbered
            # this way, bootstrapped noise floors are where they would be
            # expected to be rather than artificially low
            if bootstrapMode and 'bootstrapTrialsSelected' in params:
                flipTheseTrials = np.where((params['bootstrapTrialsSelected'] %
                                            2) == 0)
            else:
                flipTheseTrials = np.arange(0, x.shape[1], 2)

            phaseFlipper[:, flipTheseTrials, :] = -1.0

        elif thisType == 'normalPhase':
            phaseFlipper = 1.0

        useData = x * phaseFlipper

        for k, tap in enumerate(w):
            logger.info(thisType + 'Doing Taper #%d', k)

            xw = sci.fft((tap * useData), n=nfft, axis=timedim)

            # no point keeping everything if fpass was already set
            xw = xw[:, :, fInd]

            C = xw.mean(axis=trialdim).squeeze()

            if params['itc']:
                plvC = (xw.mean(axis=trialdim) /
                        (abs(xw).mean(axis=trialdim))).squeeze()
            else:
                plvC = (xw / abs(xw)).mean(axis=trialdim).squeeze()

            for fi in np.arange(0, len(f)):
                powerCsd = np.outer(C[:, fi], C[:, fi].conj())
                powerEigenvals = linalg.eigh(powerCsd, eigvals_only=True)
                cspec[k, fi] = powerEigenvals[-1] / nchans

                plvCsd = np.outer(plvC[:, fi], plvC[:, fi].conj())
                plvEigenvals = linalg.eigh(plvCsd, eigvals_only=True)
                plv[k, fi] = plvEigenvals[-1] / nchans

        # Avage over tapers and squeeze to pretty shapes
        mtcpcaSpectrum = (cspec.mean(axis=0)).squeeze()
        mtcpcaPhaseLockingValue = (plv.mean(axis=0)).squeeze()

        if mtcpcaSpectrum.shape != mtcpcaPhaseLockingValue.shape:
            logger.error('internal error: shape mismatch between PLV ' +
                         ' and magnitude result arrays')

        out['mtcpcaSpectrum_' + thisType] = mtcpcaSpectrum
        out['mtcpcaPLV_' + thisType] = mtcpcaPhaseLockingValue

    if bootstrapMode:
        out['f'] = f
        return out
    else:
        S = {}
        S['spectrum'] = ['mtcpcaSpectrum_normalPhase']
        S['plv'] = ['mtcpcaPLV_normalPhase']

        N = {}
        N['spectrum'] = out['mtcpcaSpectrum_noiseFloorViaPhaseFlip']
        N['plv'] = out['mtcpcaPLV_noiseFloorViaPhaseFlip']

        return (S, N, f)
コード例 #30
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtpspec(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Pairwise Power Spectral estimate

    Parameters
    ----------
    x - Numpy Array
        Input data numpy array (channel x trial x time) or (trials x time)
    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['Npairs'] - Number of pairs for pairwise analysis
    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
      Tuple (pspec, f):
          pspec -  Multitapered Pairwise Power estimate (channel x frequency)

          f - Frequency vector matching plv

    In bootstrap mode:

      Dictionary with following keys:
          pspec -  Multitapered Pairwise Power estimate (channel x frequency)

          f - Frequency vector matching plv

    """
    logger.info('Running Multitaper Pairwise Power Estimate')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    pspec = np.zeros((ntaps, nchans, nfft))

    for ch in np.arange(0, nchans):
        for k, tap in enumerate(w):
            logger.debug('Running Channel # %d, taper #%d', ch, k)
            xw = sci.fft(tap * x, n=nfft, axis=timedim)
            npairs = params['Npairs']
            trial_pairs = np.random.randint(0, ntrials, (npairs, 2))

            # For unbiasedness, pairs should be made of independent trials!
            trial_pairs = trial_pairs[np.not_equal(trial_pairs[:, 0],
                                                   trial_pairs[:, 1])]
            if (nchans == 1):
                xw_1 = xw[trial_pairs[:, 0]]
                xw_2 = xw[trial_pairs[:, 1]]
                pspec[k, ch, :] = np.real((xw_1 * xw_2.conj()).mean(axis=0))
            else:
                xw_1 = xw[ch, trial_pairs[:, 0], :]
                xw_2 = xw[ch, trial_pairs[:, 1], :]
                pspec[k, ch, :] = np.real((xw_1 * xw_2.conj()).mean(axis=0))

    pspec = pspec.mean(axis=0)
    pspec = pspec[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['pspec'] = pspec
        out['f'] = f

        return out
    else:
        return (pspec, f)
コード例 #31
0
 def eigs(self):
     return tsa.dpss_windows(self.input.shape[-1], self.NW,
                             2 * self.NW - 1)[1]
コード例 #32
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtspecraw(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Spectrum (of raw signal)

    Parameters
    ----------
    x - Numpy array
        Input data numpy array (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    Normal mode:
        Tuple (mtspecraw, f)
          mtspecraw - multitapered spectrum

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:
          mtspecraw - Multitapered spectrum (channel x frequency)

          f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Raw Spectrum Estimation')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        nchans = x.shape[0]
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        nchans = 1
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the results

    Sraw = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        Sraw[k, :, :] = (abs(xw)**2).mean(axis=trialdim)

    # Average over tapers and squeeze to pretty shapes
    Sraw = Sraw.mean(axis=0)
    Sraw = Sraw[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtspecraw'] = Sraw
        out['f'] = f

        return out
    else:
        return (Sraw, f)
コード例 #33
0
ファイル: coherence.py プロジェクト: fedeadolfi/soundsig
def compute_coherence_original(s1,
                               s2,
                               sample_rate,
                               bandwidth,
                               jackknife=False,
                               tanh_transform=False):
    """
        An implementation of computing the coherence. Don't use this.
    """

    minlen = min(len(s1), len(s2))
    if s1.shape != s2.shape:
        s1 = s1[:minlen]
        s2 = s2[:minlen]

    window_length = len(s1) / sample_rate
    window_length_bins = int(window_length * sample_rate)

    #compute DPSS tapers for signals
    NW = int(window_length * bandwidth)
    K = 2 * NW - 1
    print 'compute_coherence: NW=%d, K=%d' % (NW, K)
    tapers, eigs = ntalg.dpss_windows(window_length_bins, NW, K)

    njn = len(eigs)
    jn_indices = [range(njn)]
    #compute jackknife indices
    if jackknife:
        jn_indices = list()
        for i in range(len(eigs)):
            jn = range(len(eigs))
            jn.remove(i)
            jn_indices.append(jn)

    #taper the signals
    s1_tap = tapers * s1
    s2_tap = tapers * s2

    #compute fft of tapered signals
    s1_fft = fftpack.fft(s1_tap, axis=1)
    s2_fft = fftpack.fft(s2_tap, axis=1)

    #compute adaptive weights for each taper
    w1, nu1 = ntutils.adaptive_weights(s1_fft, eigs, sides='onesided')
    w2, nu2 = ntutils.adaptive_weights(s2_fft, eigs, sides='onesided')

    coherence_estimates = list()
    for jn in jn_indices:

        #compute cross spectral density
        sxy = ntalg.mtm_cross_spectrum(s1_fft[jn, :],
                                       s2_fft[jn, :], (w1[jn], w2[jn]),
                                       sides='onesided')

        #compute individual power spectrums
        sxx = ntalg.mtm_cross_spectrum(s1_fft[jn, :],
                                       s1_fft[jn, :],
                                       w1[jn],
                                       sides='onesided')
        syy = ntalg.mtm_cross_spectrum(s2_fft[jn, :],
                                       s2_fft[jn, :],
                                       w2[jn],
                                       sides='onesided')

        #compute coherence
        coherence = np.abs(sxy)**2 / (sxx * syy)
        coherence_estimates.append(coherence)

    #compute variance
    coherence_estimates = np.array(coherence_estimates)
    coherence_variance = np.zeros([coherence_estimates.shape[1]])
    coherence_mean = coherence_estimates[0]
    if jackknife:
        coherence_mean = coherence_estimates.mean(axis=0)
        #mean subtract and square
        cv = np.sum((coherence_estimates - coherence_mean)**2, axis=0)
        coherence_variance[:] = (1.0 - 1.0 / njn) * cv

    #compute frequencies
    sampint = 1.0 / sample_rate
    L = minlen / 2 + 1
    freq = np.linspace(0, 1 / (2 * sampint), L)

    #compute upper and lower bounds
    cmean = coherence_mean
    coherence_lower = cmean - 2 * np.sqrt(coherence_variance)
    coherence_upper = cmean + 2 * np.sqrt(coherence_variance)

    cdata = CoherenceData()
    cdata.coherence = coherence_mean
    cdata.coherence_lower = coherence_lower
    cdata.coherence_upper = coherence_upper
    cdata.frequency = freq
    cdata.sample_rate = sample_rate

    return cdata
コード例 #34
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtppc(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Pairwise Phase Consistency

    Parameters
    ----------
    x - Numpy array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['Npairs'] - Number of pairs for PPC analysis

      params['itc'] - If True, normalize after mean like ITC instead of PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (ppc, f):
          ppc - Multitapered PPC estimate (channel x frequency)

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:
          mtppc - Multitapered PPC estimate (channel x frequency)

          f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Pairwise Phase Consistency Estimate')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the result

    ppc = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        npairs = params['nPairs']
        trial_pairs = np.random.randint(0, ntrials, (npairs, 2))

        if(nchans == 1):
            if(not params['itc']):
                xw_1 = xw[trial_pairs[:, 0], :]/abs(xw[trial_pairs[:, 0], :])
                xw_2 = xw[trial_pairs[:, 1], :]/abs(xw[trial_pairs[:, 1], :])
                ppc[k, :, :] = np.real((xw_1*xw_2.conj()).mean(axis=trialdim))
            else:
                xw_1 = xw[trial_pairs[:, 0]]
                xw_2 = xw[trial_pairs[:, 1]]
                ppc_unnorm = np.real((xw_1 * xw_2.conj()).mean(axis=trialdim))
                ppc[k, :, :] = (ppc_unnorm /
                                (abs(xw_1).mean(trialdim) *
                                 abs(xw_2).mean(trialdim)))

        else:
            if(not params['itc']):
                xw_1 = (xw[:, trial_pairs[:, 0], :] /
                        abs(xw[:, trial_pairs[:, 0], :]))
                xw_2 = (xw[:, trial_pairs[:, 1], :] /
                        abs(xw[:, trial_pairs[:, 1], :]))
                ppc[k, :, :] = np.real((xw_1*xw_2.conj()).
                                       mean(axis=trialdim))
            else:
                xw_1 = xw[:, trial_pairs[:, 0], :]
                xw_2 = xw[:, trial_pairs[:, 1], :]
                ppc_unnorm = np.real((xw_1 * xw_2.conj()).mean(axis=trialdim))
                ppc[k, :, :] = (ppc_unnorm /
                                (abs(xw_1).mean(trialdim) *
                                 abs(xw_2).mean(trialdim)))

    ppc = ppc.mean(axis=0)
    ppc = ppc[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtppc'] = ppc
        out['f'] = f

        return out
    else:
        return (ppc, f)
コード例 #35
0
"""

(b, a) = signal.butter(3, W, btype='lowpass')
slp = signal.lfilter(b, a, s)
"""
Modulate both signals away from baseband.
"""

s_mod = s * np.cos(2 * np.pi * np.arange(N) * float(200) / N)
slp_mod = slp * np.cos(2 * np.pi * np.arange(N) * float(200) / N)
fm = int(np.round(float(200) * nfft / N))
"""
Create Slepians with the desired bandpass resolution (2W).
"""

(dpss, eigs) = nt_alg.dpss_windows(N, NW, 2 * NW)
keep = eigs > 0.9
dpss = dpss[keep]
eigs = eigs[keep]
"""

Test 1
------

We'll compare multitaper baseband power estimation with regular
Hilbert transform method under actual narrowband conditions.
"""

# MT method
xk = nt_alg.tapered_spectra(slp_mod, dpss, NFFT=nfft)
mtm_bband = np.sum(2 * (xk[:, fm] * np.sqrt(eigs))[:, None] * dpss, axis=0)
コード例 #36
0
ファイル: coherence.py プロジェクト: JohnGriffiths/nitime
 def eigs(self):
     return tsa.dpss_windows(self.input.shape[-1], self.NW,
                                   2 * self.NW - 1)[1]
コード例 #37
0
def multitaper_cross_spectral_estimates(traces,
                                        delta,
                                        NW,
                                        compute_confidence_intervals=True,
                                        confidence_interval=0.95):

    # Define the number of tapers, their values and associated eigenvalues:
    npts = len(traces[0])
    K = 2 * NW - 1
    tapers, eigs = alg.dpss_windows(npts, NW, K)

    # Multiply the data by the tapers, calculate the Fourier transform
    # We multiply the data by the tapers and derive the fourier transform and the
    # magnitude of the squared spectra (the power) for each tapered time-series:
    tdata = tapers[None, :, :] * traces[:, None, :]
    tspectra = fftpack.fft(tdata)

    # The coherency for real sequences is symmetric so only half
    # the spectrum if required
    L = npts // 2 + 1

    if L < npts:
        freqs = np.linspace(0, 1. / (2. * delta), L)
    else:
        freqs = np.linspace(0, 1. / delta, L, endpoint=False)

    # Estimate adaptive weighting of the tapers, based on the data
    # (see Thomsen, 2007; 10.1109/MSP.2007.4286561)
    w = np.empty((2, K, L))
    for i in range(2):
        w[i], _ = utils.adaptive_weights(tspectra[i], eigs, sides='onesided')

    # Calculate the multi-tapered cross spectrum
    # and the PSDs for the two time-series:
    sxy = alg.mtm_cross_spectrum(tspectra[0],
                                 tspectra[1], (w[0], w[1]),
                                 sides='onesided')
    sxx = alg.mtm_cross_spectrum(tspectra[0],
                                 tspectra[0],
                                 w[0],
                                 sides='onesided')
    syy = alg.mtm_cross_spectrum(tspectra[1],
                                 tspectra[1],
                                 w[1],
                                 sides='onesided')

    Z = sxy / syy

    spectral_estimates = {}
    spectral_estimates['frequencies'] = freqs
    spectral_estimates['magnitude_squared_coherence'] = np.abs(sxy)**2 / (sxx *
                                                                          syy)
    spectral_estimates['transfer_function'] = Z  # Transfer function
    spectral_estimates['admittance'] = np.real(Z)
    spectral_estimates['gain'] = np.absolute(Z)
    spectral_estimates['phase'] = np.angle(Z, deg=True)

    # Estimate confidence intervals
    if compute_confidence_intervals:
        spectral_estimates['confidence_bounds'] = {}
        c_bnds = [
            0.5 - confidence_interval / 2., 0.5 + confidence_interval / 2.
        ]
        variances = jackknifed_variances(tspectra[0],
                                         tspectra[1],
                                         eigs,
                                         adaptive=True)
        spectral_estimates['confidence_bounds']['admittance'] = [
            spectral_estimates['admittance'] +
            dist.t.ppf(c_bnds[0], K - 1) * np.sqrt(variances['admittance']),
            spectral_estimates['admittance'] +
            dist.t.ppf(c_bnds[1], K - 1) * np.sqrt(variances['admittance'])
        ]
        spectral_estimates['confidence_bounds']['gain'] = [
            spectral_estimates['gain'] +
            dist.t.ppf(c_bnds[0], K - 1) * np.sqrt(variances['gain']),
            spectral_estimates['gain'] +
            dist.t.ppf(c_bnds[1], K - 1) * np.sqrt(variances['gain'])
        ]
        spectral_estimates['confidence_bounds']['phase'] = [
            spectral_estimates['phase'] +
            dist.t.ppf(c_bnds[0], K - 1) * np.sqrt(variances['phase']),
            spectral_estimates['phase'] +
            dist.t.ppf(c_bnds[1], K - 1) * np.sqrt(variances['phase'])
        ]
        spectral_estimates['confidence_bounds'][
            'magnitude_squared_coherence'] = [
                spectral_estimates['magnitude_squared_coherence'] +
                dist.t.ppf(c_bnds[0], K - 1) *
                np.sqrt(variances['magnitude_squared_coherence']),
                spectral_estimates['magnitude_squared_coherence'] +
                dist.t.ppf(c_bnds[1], K - 1) *
                np.sqrt(variances['magnitude_squared_coherence'])
            ]

    return spectral_estimates
コード例 #38
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtcpca_timeDomain(x, params, verbose=None, bootstrapMode=False):
    """Multitaper complex PCA and regular time-domain PCA and return time
    domain waveforms.

    Note of caution
    ---------------
    The cPCA method is not really suited to extract fast transient features of
    the time domain waveform. This is because, the frequency domain
    representation of any signal (when you think of it as random process) is
    interpretable only when the signal is stationary, i.e., in steady-state.
    Practically speaking, the process of transforming short epochs to the
    frequency domain necessarily involves smoothing in frequency. This
    leakage is minimized by tapering the original signal using DPSS windows,
    also known as Slepian sequences. The effect of this tapering would be
    present when going back to the time domain. Note that only a single taper
    is used here as combining tapers with different symmetries in the time-
    domain leads to funny cancellations.

    Also, for transient features, simple time-domain PCA is likely
    to perform better as the cPCA smoothes out transient features. Thus
    both regular time-domain PCA and cPCA outputs are returned.

    Note that for sign of the output is indeterminate (you may need to flip
    the output to match the polarity of signal channel responses)

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (y_cpc, y_pc):
          'y_cpc' - Multitapered cPCA estimate of time-domain waveform

          'y_pc' - Regular time-domain PCA

    In bootstrap mode:
        Dictionary with the following keys:
          'y_cpc' - Multitapered cPCA estimate of time-domain waveform

          'y_pc' - Regular time-domain PCA

    """

    logger.info('Running Multitaper Complex PCA to extract time waveform!')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    w, conc = dpss_windows(x.shape[timedim], 1, 1)
    w = w.squeeze() / w.max()

    cpc_freq = np.zeros(nfft, dtype=np.complex)
    cspec = np.zeros(nfft)
    xw = sci.fft(w * x, n=nfft, axis=timedim)
    C = (xw.mean(axis=trialdim)).squeeze()
    Cnorm = C / ((abs(xw).mean(axis=trialdim)).squeeze())
    for fi in np.arange(0, nfft):
        Csd = np.outer(Cnorm[:, fi], Cnorm[:, fi].conj())
        vals, vecs = linalg.eigh(Csd, eigvals_only=False)
        cspec[fi] = vals[-1]
        cwts = vecs[:, -1] / (np.abs(vecs[:, -1]).sum())
        cpc_freq[fi] = (cwts.conjugate() * C[:, fi]).sum()

    # Filter through spectrum, do ifft.
    cscale = cspec ** 0.5
    cscale = cscale / cscale.max()  # Maxgain of filter = 1
    y_cpc = sci.ifft(cpc_freq * cscale)[:x.shape[timedim]]

    # Do time domain PCA
    x_ave = x.mean(axis=trialdim)
    C_td = np.cov(x_ave)
    vals, vecs = linalg.eigh(C_td, eigvals_only=False)
    y_pc = np.dot(vecs[:, -1].T, x_ave) / (vecs[:, -1].sum())

    if bootstrapMode:
        out = {}
        out['y_cpc'] = y_cpc
        out['y_pc'] = y_pc

        return out
    else:
        return (y_cpc, y_pc)
コード例 #39
0
ファイル: coherence.py プロジェクト: choldgraf/LaSP
def compute_coherence_original(s1, s2, sample_rate, bandwidth, jackknife=False, tanh_transform=False):
    """
        An implementation of computing the coherence. Don't use this.
    """

    minlen = min(len(s1), len(s2))
    if s1.shape != s2.shape:
        s1 = s1[:minlen]
        s2 = s2[:minlen]

    window_length = len(s1) / sample_rate
    window_length_bins = int(window_length * sample_rate)

    #compute DPSS tapers for signals
    NW = int(window_length*bandwidth)
    K = 2*NW - 1
    print 'compute_coherence: NW=%d, K=%d' % (NW, K)
    tapers,eigs = ntalg.dpss_windows(window_length_bins, NW, K)

    njn = len(eigs)
    jn_indices = [range(njn)]
    #compute jackknife indices
    if jackknife:
        jn_indices = list()
        for i in range(len(eigs)):
            jn = range(len(eigs))
            jn.remove(i)
            jn_indices.append(jn)

    #taper the signals
    s1_tap = tapers * s1
    s2_tap = tapers * s2

    #compute fft of tapered signals
    s1_fft = fftpack.fft(s1_tap, axis=1)
    s2_fft = fftpack.fft(s2_tap, axis=1)

    #compute adaptive weights for each taper
    w1,nu1 = ntutils.adaptive_weights(s1_fft, eigs, sides='onesided')
    w2,nu2 = ntutils.adaptive_weights(s2_fft, eigs, sides='onesided')

    coherence_estimates = list()
    for jn in jn_indices:

        #compute cross spectral density
        sxy = ntalg.mtm_cross_spectrum(s1_fft[jn, :], s2_fft[jn, :], (w1[jn], w2[jn]), sides='onesided')

        #compute individual power spectrums
        sxx = ntalg.mtm_cross_spectrum(s1_fft[jn, :], s1_fft[jn, :], w1[jn], sides='onesided')
        syy = ntalg.mtm_cross_spectrum(s2_fft[jn, :], s2_fft[jn, :], w2[jn], sides='onesided')

        #compute coherence
        coherence = np.abs(sxy)**2 / (sxx * syy)
        coherence_estimates.append(coherence)

    #compute variance
    coherence_estimates = np.array(coherence_estimates)
    coherence_variance = np.zeros([coherence_estimates.shape[1]])
    coherence_mean = coherence_estimates[0]
    if jackknife:
        coherence_mean = coherence_estimates.mean(axis=0)
        #mean subtract and square
        cv = np.sum((coherence_estimates - coherence_mean)**2, axis=0)
        coherence_variance[:] = (1.0 - 1.0/njn) * cv

    #compute frequencies
    sampint = 1.0 / sample_rate
    L = minlen / 2 + 1
    freq = np.linspace(0, 1 / (2 * sampint), L)

    #compute upper and lower bounds
    cmean = coherence_mean
    coherence_lower = cmean - 2*np.sqrt(coherence_variance)
    coherence_upper = cmean + 2*np.sqrt(coherence_variance)

    cdata = CoherenceData()
    cdata.coherence = coherence_mean
    cdata.coherence_lower = coherence_lower
    cdata.coherence_upper = coherence_upper
    cdata.frequency = freq
    cdata.sample_rate = sample_rate

    return cdata
コード例 #40
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def mtphase(x, params, verbose=None, bootstrapMode=False):
    """Multitaper phase estimation

    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns:
    -------
    In normal mode:
        (Ph, f): Tuple
          Ph - Multitapered phase spectrum (channel x frequency)

          f - Frequency vector matching S and N

    In bootstrap mode:
        Dictionary with the following keys:

        Ph - Multitapered phase spectrum (channel x frequency)

        f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Spectrum and Noise-floor Estimation')
    x = x.squeeze()
    if(len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif(len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    Ph = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)
        Ph[k, :, :] = np.angle(xw.mean(axis=trialdim))

    # Average over tapers and squeeze to pretty shapes
    Ph = Ph[:, :, fInd].mean(axis=0).squeeze()

    if bootstrapMode:
        out = {}
        out['mtphase'] = Ph
        out['f'] = f

        return out
    else:
        return (Ph, f)
コード例 #41
0
ファイル: coherence.py プロジェクト: choldgraf/LaSP
def compute_mtcoherence(s1, s2, sample_rate, window_size, bandwidth=15.0, chunk_len_percentage_tolerance=0.30,
                      frequency_cutoff=None, tanh_transform=False, debug=False):
    """
        Computing the multi-taper coherence between signals s1 and s2. To do so, the signals are broken up into segments of length
        specified by window_size. Then the multi-taper coherence is computed between each segment. The mean coherence
        is computed across segments, and an estimate of the coherence variance is computed across segments.

        sample_rate: the sample rate in Hz of s1 and s2

        window_size: size of the segments in seconds

        bandwidth: related to the # of tapers used to compute the spectral density. The higher the bandwidth, the more tapers.

        chunk_len_percentage_tolerance: If there are leftover segments whose lengths are less than window_size, use them
            if they comprise at least the fraction of window_size specified by chunk_len_percentage_tolerance

        frequency_cutoff: the frequency at which to cut off the coherence when computing the normal mutual information

        tanh_transform: whether to transform the coherences when computing the upper and lower bounds, supposedly
            improves the estimate of variance.
    """

    minlen = min(len(s1), len(s2))
    if s1.shape != s2.shape:
        s1 = s1[:minlen]
        s2 = s2[:minlen]

    sample_length_bins = min(len(s1), int(window_size * sample_rate))

    #compute DPSS tapers for signals
    NW = int(window_size*bandwidth)
    K = 2*NW - 1
    #print 'compute_coherence: NW=%d, K=%d' % (NW, K)
    tapers,eigs = ntalg.dpss_windows(sample_length_bins, NW, K)
    if debug:
        print '[compute_coherence] bandwidth=%0.1f, # of tapers: %d' % (bandwidth, len(eigs))

    #break signal into chunks and estimate coherence for each chunk
    nchunks = int(np.floor(len(s1) / float(sample_length_bins)))
    nleft = len(s1) % sample_length_bins
    if nleft > 0:
        nchunks += 1
    #print 'sample_length_bins=%d, # of chunks:%d, # samples in last chunk: %d' % (sample_length_bins, nchunks, nleft)
    coherence_estimates = list()
    for k in range(nchunks):
        s = k*sample_length_bins
        e = min(len(s1), s + sample_length_bins)
        chunk_len = e - s
        chunk_percentage = chunk_len / float(sample_length_bins)
        if chunk_percentage < chunk_len_percentage_tolerance:
            #don't compute coherence for a chunk whose length is less than a certain percentage of sample_length_bins
            continue
        s1_chunk = np.zeros([sample_length_bins])
        s2_chunk = np.zeros([sample_length_bins])
        s1_chunk[:chunk_len] = s1[s:e]
        s2_chunk[:chunk_len] = s2[s:e]

        #taper the signals
        s1_tap = tapers * s1_chunk
        s2_tap = tapers * s2_chunk

        #compute fft of tapered signals
        s1_fft = fftpack.fft(s1_tap, axis=1)
        s2_fft = fftpack.fft(s2_tap, axis=1)

        #compute adaptive weights for each taper
        w1,nu1 = ntutils.adaptive_weights(s1_fft, eigs, sides='onesided')
        w2,nu2 = ntutils.adaptive_weights(s2_fft, eigs, sides='onesided')

        #compute cross spectral density
        sxy = ntalg.mtm_cross_spectrum(s1_fft, s2_fft, (w1, w2), sides='onesided')

        #compute individual power spectrums
        sxx = ntalg.mtm_cross_spectrum(s1_fft, s1_fft, w1, sides='onesided')
        syy = ntalg.mtm_cross_spectrum(s2_fft, s2_fft, w2, sides='onesided')

        #compute coherence
        coherence = np.abs(sxy)**2 / (sxx * syy)
        coherence_estimates.append(coherence)

    #compute variance
    coherence_estimates = np.array(coherence_estimates)

    if tanh_transform:
        coherence_estimates = np.arctanh(coherence_estimates)

    coherence_variance = np.zeros([coherence_estimates.shape[1]])
    coherence_mean = coherence_estimates.mean(axis=0)
    #mean subtract and square
    cv = np.sum((coherence_estimates - coherence_mean)**2, axis=0)
    coherence_variance[:] = (1.0 - 1.0/nchunks) * cv

    if tanh_transform:
        coherence_variance = np.tanh(coherence_variance)
        coherence_mean = np.tanh(coherence_mean)

    #compute frequencies
    sampint = 1.0 / sample_rate
    L = sample_length_bins / 2 + 1
    freq = np.linspace(0, 1 / (2 * sampint), L)

    #compute upper and lower bounds
    coherence_lower = coherence_mean - 2*np.sqrt(coherence_variance)
    coherence_upper = coherence_mean + 2*np.sqrt(coherence_variance)

    cdata = CoherenceData(frequency_cutoff=frequency_cutoff)
    cdata.coherence = coherence_mean
    cdata.coherence_lower = coherence_lower
    cdata.coherence_upper = coherence_upper
    cdata.frequency = freq
    cdata.sample_rate = sample_rate

    return cdata
コード例 #42
0
ファイル: spectral.py プロジェクト: SusanMcL/ANLffr
def _mtcpca_complete(x, params, verbose=None, bootstrapMode=False):
    """
    Internal convenience function to obtain plv and spectrum with cpca and
    multitaper.  Equivalent to calling:

    spectral.mtcpca(data, params, ...)
    spectral.mtcspec(data, params, ...)

    With the exception that this function returns a dictionary for S + N, each
    of which have keys "plv_*" and "spectrum_*", where * is "normalPhase" or
    "noiseFloorViaPhaseFlip".

    Gets power spectra and plv on the same set of data using multitaper and
    complex PCA. Returns a noise floor esimate of each by running the same
    computations on the original data, as well as the original data with the
    phase of half of the trials flipped. For a large number of trials, the
    spectra of the data and the half-trials-phase-flipped data should be
    similar, while the PLV values for the half-trials-flipped data should be
    hovering near the PLV value of off-frequency components in the original
    data.

    Primarily useful when debugging, bootstrapping, or when using scripts that
    for some reason randomizes data in between calls to mtcpca and mtcspec.


    Parameters
    ----------
    x - NumPy Array
        Input data (channel x trial x time)

    params - dictionary. Must contain the following fields:
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - If True, normalize after mean like ITC instead of PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (S, N, f)

        Where S and N are data for signal and for noise floor, respectively,
        each as a dictionary with the following keys:

          mtcpcaSpectrum - Multitapered power spectral estimate using cPCA

          mtcpcaPLV- Multitapered PLV using cPCA

        f - frequency vector

    In bootstrap mode:
        dictionary with keys:
          mtcpcaSpectrum_* - Multitapered power spectral estimate using cPCA

          mtcpcaPLV_*- Multitapered PLV using cPCA

          f - frequency vector

     where * in the above is the type of noise floor
    """

    out = {}

    logger.info('Running Multitaper Complex PCA based ' +
                'plv and power estimation.')
    x = x.squeeze()
    if len(x.shape) == 3:
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    else:
        logger.error('Sorry! The data should be a 3 dimensional array!')

    # Calculate the tapers

    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]

    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    plv = np.zeros((ntaps, len(f)))
    cspec = np.zeros((ntaps, len(f)))

    phaseTypes = list(['normalPhase', 'noiseFloorViaPhaseFlip'])

    for thisType in phaseTypes:
        if thisType == 'noiseFloorViaPhaseFlip':
            # flip the phase of every other trial
            phaseFlipper = np.ones(x.shape)

            # important change: when noise floor is computed, it will
            # only select trials that were originally labeled as even-numbered
            # this way, bootstrapped noise floors are where they would be
            # expected to be rather than artificially low
            if bootstrapMode and 'bootstrapTrialsSelected' in params:
                flipTheseTrials = np.where(
                    (params['bootstrapTrialsSelected'] % 2) == 0)
            else:
                flipTheseTrials = np.arange(0, x.shape[1], 2)

            phaseFlipper[:, flipTheseTrials, :] = -1.0

        elif thisType == 'normalPhase':
            phaseFlipper = 1.0

        useData = x * phaseFlipper

        for k, tap in enumerate(w):
            logger.info(thisType + 'Doing Taper #%d', k)

            xw = sci.fft((tap * useData), n=nfft, axis=timedim)

            # no point keeping everything if fpass was already set
            xw = xw[:, :, fInd]

            C = xw.mean(axis=trialdim).squeeze()

            if params['itc']:
                plvC = (xw.mean(axis=trialdim) /
                        (abs(xw).mean(axis=trialdim))).squeeze()
            else:
                plvC = (xw / abs(xw)).mean(axis=trialdim).squeeze()

            for fi in np.arange(0, len(f)):
                powerCsd = np.outer(C[:, fi], C[:, fi].conj())
                powerEigenvals = linalg.eigh(powerCsd, eigvals_only=True)
                cspec[k, fi] = powerEigenvals[-1] / nchans

                plvCsd = np.outer(plvC[:, fi], plvC[:, fi].conj())
                plvEigenvals = linalg.eigh(plvCsd, eigvals_only=True)
                plv[k, fi] = plvEigenvals[-1] / nchans

        # Avage over tapers and squeeze to pretty shapes
        mtcpcaSpectrum = (cspec.mean(axis=0)).squeeze()
        mtcpcaPhaseLockingValue = (plv.mean(axis=0)).squeeze()

        if mtcpcaSpectrum.shape != mtcpcaPhaseLockingValue.shape:
            logger.error('internal error: shape mismatch between PLV ' +
                         ' and magnitude result arrays')

        out['mtcpcaSpectrum_' + thisType] = mtcpcaSpectrum
        out['mtcpcaPLV_' + thisType] = mtcpcaPhaseLockingValue

    if bootstrapMode:
        out['f'] = f
        return out
    else:
        S = {}
        S['spectrum'] = ['mtcpcaSpectrum_normalPhase']
        S['plv'] = ['mtcpcaPLV_normalPhase']

        N = {}
        N['spectrum'] = out['mtcpcaSpectrum_noiseFloorViaPhaseFlip']
        N['plv'] = out['mtcpcaPLV_noiseFloorViaPhaseFlip']

        return (S, N, f)
コード例 #43
0
 def __getitem__(self, k):
     return self.pop(k, dpss_windows(*k))
コード例 #44
0
ファイル: multi_taper_coh.py プロジェクト: saifrahmed/nitime
pdata = utils.percent_change(data)
"""

We start by performing the detailed analysis, but note that a significant
short-cut is presented below, so if you just want to know how to do this
(without needing to understand the details), skip on down.

We start by defining how many tapers will be used and calculate the values of
the tapers and the associated eigenvalues of each taper:

"""

NW = 4
K = 2 * NW - 1

tapers, eigs = alg.dpss_windows(n_samples, NW, K)
"""

We multiply the data by the tapers and derive the fourier transform and the
magnitude of the squared spectra (the power) for each tapered time-series:

"""

tdata = tapers[None, :, :] * pdata[:, None, :]
tspectra = fftpack.fft(tdata)
## mag_sqr_spectra = np.abs(tspectra)
## np.power(mag_sqr_spectra, 2, mag_sqr_spectra)
"""

Coherence for real sequences is symmetric, so we calculate this for only half
the spectrum (the other half is equal):
コード例 #45
0
(b, a) = signal.butter(3, W, btype='lowpass')
slp = signal.lfilter(b, a, s)

"""
Modulate both signals away from baseband.
"""

s_mod = s * np.cos(2*np.pi*np.arange(N) * float(200) / N)
slp_mod = slp * np.cos(2*np.pi*np.arange(N) * float(200) / N)
fm = int( np.round(float(200) * nfft / N) )

"""
Create Slepians with the desired bandpass resolution (2W).
"""

(dpss, eigs) = nt_alg.dpss_windows(N, NW, 2*NW)
keep = eigs > 0.9
dpss = dpss[keep]; eigs = eigs[keep]

"""

Test 1
------

We'll compare multitaper baseband power estimation with regular
Hilbert transform method under actual narrowband conditions.
"""

# MT method
xk = nt_alg.tapered_spectra(slp_mod, dpss, NFFT=nfft)
mtm_bband = np.sum( 2 * (xk[:,fm] * np.sqrt(eigs))[:,None] * dpss, axis=0 )
コード例 #46
0
def extract_features(EEG_segs, channel_names, combined_channel_names, Fs, NW, total_freq_range, sub_window_time, sub_window_step, seg_start_ids, return_feature_names=False, n_jobs=-1, verbose=True):
    """Extract features from EEG segments.

    Arguments:
    EEG_segs -- a list of EEG segments in numpy.ndarray type, size=(sample_point, channel_num)
    channel_names -- a list of channel names for each column of EEG_segs
    ##combined_channel_names -- a list of combined column_channels_names, for example from 'F3M2' and 'F4M1' to 'F'
    Fs -- sampling frequency in Hz

    Keyword arguments:
    process_num -- default None, number of parallel processes, if None, equals to 4x #CPU.

    Outputs:
    features from each segment in numpy.ndarray type, size=(seg_num, feature_num)
    a list of names of each feature
    psd estimation, size=(window_num, freq_point_num, channel_num), or a list of them for each band
    frequencies, size=(freq_point_num,), or a list of them for each band
    """

    #if type(EEG_segs)!=list:
    #    raise TypeError('EEG segments should be list of numpy.ndarray, with size=(sample_point, channel_num).')

    seg_num, channel_num, window_size = EEG_segs.shape
    if seg_num <= 0:
        return []
    
    sub_window_size = int(round(sub_window_time*Fs))
    sub_step_size = int(round(sub_window_step*Fs))
    dpss, eigvals = tsa.dpss_windows(sub_window_size,NW,2*NW)
    nfft = max(1<<(sub_window_size-1).bit_length(), sub_window_size)
    freq = np.arange(0, Fs, Fs*1.0/nfft)[:nfft//2+1]
    total_freq_id = np.where(np.logical_and(freq>=total_freq_range[0], freq<total_freq_range[1]))[0]
    
    old_threshold = np.get_printoptions()['threshold']
    np.set_printoptions(threshold=sys.maxsize)#np.nan)
    
    features = Parallel(n_jobs=n_jobs,verbose=verbose,backend='multiprocessing')(delayed(compute_features_each_seg)(EEG_segs[segi], window_size, channel_num, band_num, NW, Fs, freq, band_freq, total_freq_range, total_freq_id, sub_window_size, sub_step_size, dpss=dpss, eigvals=eigvals) for segi in range(seg_num))
    
    np.set_printoptions(threshold=old_threshold)

    if return_feature_names:
        feature_names = ['mean_gradient_%s'%chn for chn in channel_names]
        feature_names += ['kurtosis_%s'%chn for chn in channel_names]
        feature_names += ['sample_entropy_%s'%chn for chn in channel_names]
        for ffn in ['max','min','mean','std','kurtosis']:#,'skewness'
            for bn in band_names:
                if ffn=='kurtosis' or bn!='sigma': # no need for sigma band
                    feature_names += ['%s_bandpower_%s_%s'%(bn,ffn,chn) for chn in combined_channel_names]

        power_ratios = ['delta/theta','delta/alpha','theta/alpha']
        for pr in power_ratios:
            feature_names += ['%s_max_%s'%(pr,chn) for chn in combined_channel_names]
            feature_names += ['%s_min_%s'%(pr,chn) for chn in combined_channel_names]
            feature_names += ['%s_mean_%s'%(pr,chn) for chn in combined_channel_names]
            feature_names += ['%s_std_%s'%(pr,chn) for chn in combined_channel_names]

    # features.shape = (#epoch, 102)
    
    if return_feature_names:
        return np.array(features), feature_names#, pxx_mts, freqs
    else:
        return np.array(features)#, pxx_mts, freqs
コード例 #47
0
ファイル: array_analysis.py プロジェクト: ProjectISP/ISP
    def __vespa_az(self, st):
        def find_nearest(array, value):

            idx, val = min(enumerate(array), key=lambda x: abs(x[1] - value))
            return idx, val

        sides = 'onesided'
        pi = math.pi
        st.sort()
        n = len(st)
        for i in range(n):
            coords = self.inv.get_coordinates(st[i].id)
            st[i].stats.coordinates = AttribDict({
                'latitude':
                coords['latitude'],
                'elevation':
                coords['elevation'],
                'longitude':
                coords['longitude']
            })

        coord = get_geometry(st, coordsys='lonlat', return_center=True)

        tr = st[0]
        win = len(tr.data)
        if (win % 2) == 0:
            nfft = win / 2 + 1
        else:
            nfft = (win + 1) / 2

        nr = st.count()  # number of stations
        delta = st[0].stats.delta
        fs = 1 / delta
        fn = fs / 2
        freq = np.arange(0, fn, fn / nfft)

        value1, freq1 = find_nearest(freq, self.linf)
        value2, freq2 = find_nearest(freq, self.lsup)
        df = value2 - value1
        m = np.zeros((win, nr))

        WW = np.hamming(int(win))
        WW = np.transpose(WW)
        for i in range(nr):
            tr = st[i]
            if self.method == "FK":
                m[:, i] = (tr.data - np.mean(tr.data)) * WW
            else:
                m[:, i] = (tr.data - np.mean(tr.data))
        pdata = np.transpose(m)

        #####Coherence######
        NW = 2  # the time-bandwidth product##Buena seleccion de 2-3
        K = 2 * NW - 1
        tapers, eigs = alg.dpss_windows(win, NW, K)
        tdata = tapers[None, :, :] * pdata[:, None, :]
        tspectra = fftpack.fft(tdata)

        w = np.empty((nr, int(K), int(nfft)))
        for i in range(nr):
            w[i], _ = utils.adaptive_weights(tspectra[i], eigs, sides=sides)

        Cx = np.ones((nr, nr, df), dtype=np.complex128)

        if self.method == "MTP.COHERENCE":
            for i in range(nr):
                for j in range(nr):
                    sxy = alg.mtm_cross_spectrum(tspectra[i], (tspectra[j]),
                                                 (w[i], w[j]),
                                                 sides='onesided')
                    sxx = alg.mtm_cross_spectrum(tspectra[i],
                                                 tspectra[i],
                                                 w[i],
                                                 sides='onesided')
                    syy = alg.mtm_cross_spectrum(tspectra[j],
                                                 tspectra[j],
                                                 w[j],
                                                 sides='onesided')
                    s = sxy / np.sqrt((sxx * syy))
                    cxcohe = s[value1:value2]
                    Cx[i, j, :] = cxcohe

        ####Calculates Conventional FK-power  ##without normalization
        if self.method == "FK":
            for i in range(nr):
                for j in range(nr):
                    A = np.fft.rfft(m[:, i])
                    B = np.fft.rfft(m[:, j])
                    #Power
                    #out = A * np.conjugate(B)

                    #Relative Power
                    den = np.absolute(A) * np.absolute(np.conjugate(B))
                    out = (A * np.conjugate(B)) / den

                    cxcohe = out[value1:value2]
                    Cx[i, j, :] = cxcohe

        r = np.zeros((nr, 2))
        S = np.zeros((1, 2))
        Pow = np.zeros((360, df))
        for n in range(nr):
            r[n, :] = coord[n][0:2]

        freq = freq[value1:value2]

        rad = np.pi / 180

        slow_range = np.linspace(0, self.slow, 360)

        for j in range(360):

            ang = self.azimuth2mathangle(self.baz)
            S[0, 0] = slow_range[j] * np.cos(rad * ang)
            S[0, 1] = slow_range[j] * np.sin(rad * ang)

            k = (S * r)
            K = np.sum(k, axis=1)
            n = 0
            for f in freq:
                A = np.exp(-1j * 2 * pi * f * K)
                B = np.conjugate(np.transpose(A))
                D = np.matmul(B, Cx[:, :, n]) / nr
                P = np.matmul(D, A) / nr
                Pow[j, n] = np.abs(P)
                n = n + 1

        Pow = np.mean(Pow, axis=1)

        return Pow
コード例 #48
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtplv(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Phase-Locking Value

    Parameters
    ----------
    x - NumPy Array
        Input Data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['itc'] - 1 for ITC, 0 for PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        (plvtap, f): Tuple
           plvtap - Multitapered phase-locking estimate (channel x frequency)

    In bootstrap mode:
        Dictionary with the following keys:
         mtplv - Multitapered phase-locking estimate (channel x frequency)i

         f - Frequency vector matching plv

    """

    logger.info('Running Multitaper PLV Estimation')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        nchans = x.shape[0]
        ntrials = x.shape[trialdim]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry, The data should be a 2 or 3 dimensional array')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the PLV result

    plvtap = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        if (params['itc'] == 0):
            plvtap[k, :, :] = abs((xw / abs(xw)).mean(axis=trialdim))**2
        else:
            plvtap[k, :, :] = ((abs(xw.mean(axis=trialdim))**2) /
                               ((abs(xw)**2).mean(axis=trialdim)))

    plvtap = plvtap.mean(axis=0)

    plvtap = plvtap[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtplv'] = plvtap
        out['f'] = f
    else:
        return (plvtap, f)

    return out
コード例 #49
0
ファイル: coherence.py プロジェクト: fedeadolfi/soundsig
def compute_mtcoherence(s1,
                        s2,
                        sample_rate,
                        window_size,
                        bandwidth=15.0,
                        chunk_len_percentage_tolerance=0.30,
                        frequency_cutoff=None,
                        tanh_transform=False,
                        debug=False):
    """
        Computing the multi-taper coherence between signals s1 and s2. To do so, the signals are broken up into segments of length
        specified by window_size. Then the multi-taper coherence is computed between each segment. The mean coherence
        is computed across segments, and an estimate of the coherence variance is computed across segments.

        sample_rate: the sample rate in Hz of s1 and s2

        window_size: size of the segments in seconds

        bandwidth: related to the # of tapers used to compute the spectral density. The higher the bandwidth, the more tapers.

        chunk_len_percentage_tolerance: If there are leftover segments whose lengths are less than window_size, use them
            if they comprise at least the fraction of window_size specified by chunk_len_percentage_tolerance

        frequency_cutoff: the frequency at which to cut off the coherence when computing the normal mutual information

        tanh_transform: whether to transform the coherences when computing the upper and lower bounds, supposedly
            improves the estimate of variance.
    """

    minlen = min(len(s1), len(s2))
    if s1.shape != s2.shape:
        s1 = s1[:minlen]
        s2 = s2[:minlen]

    sample_length_bins = min(len(s1), int(window_size * sample_rate))

    #compute DPSS tapers for signals
    NW = int(window_size * bandwidth)
    K = 2 * NW - 1
    #print 'compute_coherence: NW=%d, K=%d' % (NW, K)
    tapers, eigs = ntalg.dpss_windows(sample_length_bins, NW, K)
    if debug:
        print '[compute_coherence] bandwidth=%0.1f, # of tapers: %d' % (
            bandwidth, len(eigs))

    #break signal into chunks and estimate coherence for each chunk
    nchunks = int(np.floor(len(s1) / float(sample_length_bins)))
    nleft = len(s1) % sample_length_bins
    if nleft > 0:
        nchunks += 1
    #print 'sample_length_bins=%d, # of chunks:%d, # samples in last chunk: %d' % (sample_length_bins, nchunks, nleft)
    coherence_estimates = list()
    for k in range(nchunks):
        s = k * sample_length_bins
        e = min(len(s1), s + sample_length_bins)
        chunk_len = e - s
        chunk_percentage = chunk_len / float(sample_length_bins)
        if chunk_percentage < chunk_len_percentage_tolerance:
            #don't compute coherence for a chunk whose length is less than a certain percentage of sample_length_bins
            continue
        s1_chunk = np.zeros([sample_length_bins])
        s2_chunk = np.zeros([sample_length_bins])
        s1_chunk[:chunk_len] = s1[s:e]
        s2_chunk[:chunk_len] = s2[s:e]

        #taper the signals
        s1_tap = tapers * s1_chunk
        s2_tap = tapers * s2_chunk

        #compute fft of tapered signals
        s1_fft = fftpack.fft(s1_tap, axis=1)
        s2_fft = fftpack.fft(s2_tap, axis=1)

        #compute adaptive weights for each taper
        w1, nu1 = ntutils.adaptive_weights(s1_fft, eigs, sides='onesided')
        w2, nu2 = ntutils.adaptive_weights(s2_fft, eigs, sides='onesided')

        #compute cross spectral density
        sxy = ntalg.mtm_cross_spectrum(s1_fft,
                                       s2_fft, (w1, w2),
                                       sides='onesided')

        #compute individual power spectrums
        sxx = ntalg.mtm_cross_spectrum(s1_fft, s1_fft, w1, sides='onesided')
        syy = ntalg.mtm_cross_spectrum(s2_fft, s2_fft, w2, sides='onesided')

        #compute coherence
        coherence = np.abs(sxy)**2 / (sxx * syy)
        coherence_estimates.append(coherence)

    #compute variance
    coherence_estimates = np.array(coherence_estimates)

    if tanh_transform:
        coherence_estimates = np.arctanh(coherence_estimates)

    coherence_variance = np.zeros([coherence_estimates.shape[1]])
    coherence_mean = coherence_estimates.mean(axis=0)
    #mean subtract and square
    cv = np.sum((coherence_estimates - coherence_mean)**2, axis=0)
    coherence_variance[:] = (1.0 - 1.0 / nchunks) * cv

    if tanh_transform:
        coherence_variance = np.tanh(coherence_variance)
        coherence_mean = np.tanh(coherence_mean)

    #compute frequencies
    sampint = 1.0 / sample_rate
    L = sample_length_bins / 2 + 1
    freq = np.linspace(0, 1 / (2 * sampint), L)

    #compute upper and lower bounds
    coherence_lower = coherence_mean - 2 * np.sqrt(coherence_variance)
    coherence_upper = coherence_mean + 2 * np.sqrt(coherence_variance)

    cdata = CoherenceData(frequency_cutoff=frequency_cutoff)
    cdata.coherence = coherence_mean
    cdata.coherence_lower = coherence_lower
    cdata.coherence_upper = coherence_upper
    cdata.frequency = freq
    cdata.sample_rate = sample_rate

    return cdata
コード例 #50
0
ファイル: spectral.py プロジェクト: ktavabi/ANLffr
def mtppc(x, params, verbose=None, bootstrapMode=False):
    """Multitaper Pairwise Phase Consistency

    Parameters
    ----------
    x - Numpy array
        Input data (channel x trial x time) or (trials x time)

    params - Dictionary of parameter settings
      params['Fs'] - sampling rate

      params['tapers'] - [TW, Number of tapers]

      params['fpass'] - Freqency range of interest, e.g. [5, 1000]

      params['Npairs'] - Number of pairs for PPC analysis

      params['itc'] - If True, normalize after mean like ITC instead of PLV

    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either DEBUG,
        INFO, WARNING, ERROR, or CRITICAL.

    Returns
    -------
    In normal mode:
        Tuple (ppc, f):
          ppc - Multitapered PPC estimate (channel x frequency)

          f - Frequency vector matching plv

    In bootstrap mode:
        Dictionary with the following keys:
          mtppc - Multitapered PPC estimate (channel x frequency)

          f - Frequency vector matching plv

    """

    logger.info('Running Multitaper Pairwise Phase Consistency Estimate')
    x = x.squeeze()
    if (len(x.shape) == 3):
        timedim = 2
        trialdim = 1
        ntrials = x.shape[trialdim]
        nchans = x.shape[0]
        logger.info('The data is of format %d channels x %d trials x time',
                    nchans, ntrials)
    elif (len(x.shape) == 2):
        timedim = 1
        trialdim = 0
        ntrials = x.shape[trialdim]
        nchans = 1
        logger.info('The data is of format %d trials x time (single channel)',
                    ntrials)
    else:
        logger.error('Sorry! The data should be a 2 or 3 dimensional array!')

    # Calculate the tapers
    nfft, f, fInd = _get_freq_stuff(x, params, timedim)
    ntaps = params['tapers'][1]
    TW = params['tapers'][0]
    w, conc = dpss_windows(x.shape[timedim], TW, ntaps)

    # Make space for the result

    ppc = np.zeros((ntaps, nchans, nfft))

    for k, tap in enumerate(w):
        logger.info('Doing Taper #%d', k)
        xw = sci.fft(tap * x, n=nfft, axis=timedim)

        npairs = params['nPairs']
        trial_pairs = np.random.randint(0, ntrials, (npairs, 2))

        if (nchans == 1):
            if (not params['itc']):
                xw_1 = xw[trial_pairs[:, 0], :] / abs(xw[trial_pairs[:, 0], :])
                xw_2 = xw[trial_pairs[:, 1], :] / abs(xw[trial_pairs[:, 1], :])
                ppc[k, :, :] = np.real(
                    (xw_1 * xw_2.conj()).mean(axis=trialdim))
            else:
                xw_1 = xw[trial_pairs[:, 0]]
                xw_2 = xw[trial_pairs[:, 1]]
                ppc_unnorm = np.real((xw_1 * xw_2.conj()).mean(axis=trialdim))
                ppc[k, :, :] = (
                    ppc_unnorm /
                    (abs(xw_1).mean(trialdim) * abs(xw_2).mean(trialdim)))

        else:
            if (not params['itc']):
                xw_1 = (xw[:, trial_pairs[:, 0], :] /
                        abs(xw[:, trial_pairs[:, 0], :]))
                xw_2 = (xw[:, trial_pairs[:, 1], :] /
                        abs(xw[:, trial_pairs[:, 1], :]))
                ppc[k, :, :] = np.real(
                    (xw_1 * xw_2.conj()).mean(axis=trialdim))
            else:
                xw_1 = xw[:, trial_pairs[:, 0], :]
                xw_2 = xw[:, trial_pairs[:, 1], :]
                ppc_unnorm = np.real((xw_1 * xw_2.conj()).mean(axis=trialdim))
                ppc[k, :, :] = (
                    ppc_unnorm /
                    (abs(xw_1).mean(trialdim) * abs(xw_2).mean(trialdim)))

    ppc = ppc.mean(axis=0)
    ppc = ppc[:, fInd].squeeze()

    if bootstrapMode:
        out = {}
        out['mtppc'] = ppc
        out['f'] = f

        return out
    else:
        return (ppc, f)
コード例 #51
0
    fig.savefig('windowing_functions.png')


#%% Slepian tapers

plt.close('all')
Fs = 1000
params = (4000/Fs,Fs/500,15)
talims = np.array([-2500,2500])/Fs
falims = np.array([-2/500,2/500])*Fs


N = int(params[0] * Fs)
NW = params[0]*params[1]
K = params[2]
dpss, eigvals = tsa.dpss_windows(N, NW, K)
ta = np.linspace(-N/2/Fs,N/2/Fs,N)

dpss_f = np.fft.fft(dpss, n=N*pad)
fa = np.fft.fftfreq(N*pad,1/Fs)
dpss_S = dpss_f*dpss_f.conj()

order = np.argsort(fa)
fa = fa[order]
dpss_S = dpss_S[:,order]


for nplot in [1,5]:
    fig,axs = plt.subplots(nrows=1,ncols=2,figsize=[7,2.5])
    axs[0].plot(ta,dpss[:nplot,:].T)
    axs[0].set_xlim(talims)