Пример #1
0
 def test_extremes(self):
     # Test extremes of alpha
     lam = windows.dpss(31, 6, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
     lam = windows.dpss(31, 7, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
     lam = windows.dpss(31, 8, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
Пример #2
0
 def test_extremes(self):
     # Test extremes of alpha
     lam = windows.dpss(31, 6, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
     lam = windows.dpss(31, 7, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
     lam = windows.dpss(31, 8, 4, return_ratios=True)[1]
     assert_array_almost_equal(lam, 1.)
Пример #3
0
def dpss_windows(N, NW, K):
    """
    Convenience wrapper of scipy's DPSS window method that always returns K orthonormal tapers and eigenvalues.

    Parameters
    ----------
    N: int
        Sequence length
    NW: float
        Sequence time-frequency product (half integers).
    K: int
        Number of DPSS to calculate (typically <= 2 * NW)

    Returns
    -------
    dpss: ndarray
        (K, N) orthonormal tapers
    eigs: ndarray
        K eigenvalues (bandpass concentration ratios)

    """
    vecs, eigs = dpss(N,
                      NW,
                      Kmax=int(K),
                      sym=False,
                      norm=2,
                      return_ratios=True)
    return vecs, eigs
def slepian_window(t, args):
    """
    Computes the value of a Slepian modulation shape at a given time.

    Parameters
    ----------
    t: time point at which to compute the value of the modulation shape
    args: dictionnary containing the arguments used by the shape computations. args must contain the keys:
        't_end'    : end time of the desired shape (in s)
        'rabi_freq': Rabi frequency of the pulse (in Hz.rad)
        'alpha'    : value of the shape's free parameter
        'nb_qubits': number of qubits in the array
    """
    from scipy.signal.windows import dpss

    t_end = args['t_end']
    alpha = args['alpha']
    nb_qubits = args['nb_qubits']

    omega0_max = 2 * np.pi * (
        10.0e9 + (nb_qubits - 1) * 0.1e9
    )  # Valid only when the lowest frequency is 1.0 GHz
    #TODO: Add smarter way to recover the proper frequency to consider here
    nb_time_pts = np.ceil(t_end / (1. / (omega0_max) / 100)).astype(int)

    res_full = dpss(nb_time_pts, alpha)
    res = res_full[(nb_time_pts * t / t_end).astype(int)]

    return res
Пример #5
0
def dpsschk(tapers, N, Fs):
	"""
		check tapers
	"""
	tapers, eigs = dpss(N, NW = tapers[0], Kmax=tapers[1], sym=False, return_ratios = True)
	tapers 		= tapers * np.sqrt(Fs)
	tapers 		= tapers.T
	return tapers
Пример #6
0
    def _get_window(self, win_size: int):
        """Get the window to apply to the data"""
        from scipy.signal import get_window
        from scipy.signal.windows import dpss

        if self.win_fnc == "dpss":
            return dpss(win_size, 5)
        return get_window(self.win_fnc, win_size)
Пример #7
0
def pmtm(data, NW=4, Fs=None, NFFT=None):
    '''
    Compute the power spectrum via Multitapering.
    If the number of tapers == 1, it is a stft (short-time fourier transform)
    
    Parameters
    ----------
    data : TYPE
        Input data vector.
    Fs : TYPE
        The sampling frequency.
    tapers : TYPE
        Matrix containing the discrete prolate spheroidal sequences (dpss).
    NFFT : TYPE
        Number of frequency points to evaluate the PSD at.

    Returns
    -------
    Sk : TYPE
        Power spectrum computed via MTM.

    '''

    # Number of channels
    if data.ndim == 1:
        data = np.expand_dims(data, axis=1)
    else:
        data = transpose(data, 'column')

    # Data length
    N = data.shape[0]
    channels = data.shape[1]

    if Fs == None:
        Fs = 2 * np.pi

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

    w = pmtm_params(Fs, NFFT)

    # Compute tapers
    tapers, concentration = dpss(N, NW, Kmax=2 * NW - 1, return_ratios=True)
    tapers = transpose(tapers, 'column')

    Sk = np.empty((NFFT, channels))
    Sk[:] = np.NaN

    for channel in range(channels):
        # Compute the FFT
        Sk_complex = np.fft.fft(
            np.multiply(tapers.transpose(), data[:, channel]), NFFT)
        # Compute the whole power spectrum [Power]
        Sk[:, channel] = np.mean(abs(Sk_complex)**2, axis=0)

    return Sk_complex, Sk, w, NFFT
Пример #8
0
 def test_unity(self):
     # Test unity value handling (gh-2221)
     for M in range(1, 21):
         # corrected w/approximation (default)
         win = windows.dpss(M, M / 2.1)
         expected = M % 2  # one for odd, none for even
         assert_equal(np.isclose(win, 1.).sum(), expected,
                      err_msg='%s' % (win,))
         # corrected w/subsample delay (slower)
         win_sub = windows.dpss(M, M / 2.1, norm='subsample')
         if M > 2:
             # @M=2 the subsample doesn't do anything
             assert_equal(np.isclose(win_sub, 1.).sum(), expected,
                          err_msg='%s' % (win_sub,))
             assert_allclose(win, win_sub, rtol=0.03)  # within 3%
         # not the same, l2-norm
         win_2 = windows.dpss(M, M / 2.1, norm=2)
         expected = 1 if M == 1 else 0
         assert_equal(np.isclose(win_2, 1.).sum(), expected,
                      err_msg='%s' % (win_2,))
Пример #9
0
def get_tapers(N, bandwidth, *, fs=1, min_lambda=0.95, n_tapers=None):
    """
    Compute tapers and associated energy concentrations for the Thomson
    multitaper method

    Parameters
    ----------
    N : int
        Length of taper
    bandwidth : float
        Bandwidth of taper, in Hz
    fs : float, optional
        Sampling rate, in Hz.
        Default is 1 Hz.
    min_lambda : float, optional
        Minimum energy concentration that each taper must satisfy.
        Default is 0.95.
    n_tapers : int, optional
        Number of tapers to compute
        Default is to use all tapers that satisfied 'min_lambda'.
    
    Returns
    -------
    tapers : np.ndarray, with shape (n_tapers, N)
    lambdas : np.ndarray, with shape (n_tapers, )
        Energy concentrations for each taper

    """
    
    NW = bandwidth * N / fs 
    K = int(np.ceil(2*NW)) - 1
    if K < 1:
        raise ValueError(
            f"Not enough tapers, with 'NW' of {NW}. Increase the bandwidth or "
            "use more data points")
        
    tapers, lambdas = dpss(N, NW, Kmax=K, norm=2, return_ratios=True)
    mask = lambdas > min_lambda
    if not np.sum(mask) > 0:
        raise ValueError(
            "None of the tapers satisfied the minimum energy concentration"
            f" criteria of {min_lambda}")
    tapers = tapers[mask]
    lambdas = lambdas[mask]

    if n_tapers is not None:
        if n_tapers > tapers.shape[0]:
            raise ValueError(
                f"'n_tapers' of {n_tapers} is greater than the {tapers.shape[0]}"
                f" that satisfied the minimum energy concentration criteria of {min_lambda}")
        tapers = tapers[:n_tapers]
        lambdas = lambdas[:n_tapers]
    
    return tapers, lambdas
Пример #10
0
 def test_unity(self):
     # Test unity value handling (gh-2221)
     for M in range(1, 21):
         # corrected w/approximation (default)
         win = windows.dpss(M, M / 2.1)
         expected = M % 2  # one for odd, none for even
         assert_equal(np.isclose(win, 1.).sum(), expected,
                      err_msg='%s' % (win,))
         # corrected w/subsample delay (slower)
         win_sub = windows.dpss(M, M / 2.1, norm='subsample')
         if M > 2:
             # @M=2 the subsample doesn't do anything
             assert_equal(np.isclose(win_sub, 1.).sum(), expected,
                          err_msg='%s' % (win_sub,))
             assert_allclose(win, win_sub, rtol=0.03)  # within 3%
         # not the same, l2-norm
         win_2 = windows.dpss(M, M / 2.1, norm=2)
         expected = 1 if M == 1 else 0
         assert_equal(np.isclose(win_2, 1.).sum(), expected,
                      err_msg='%s' % (win_2,))
def filtered_shape(end_time, shape, args):
    """
    Returns an array containing the value of the filtered shape function over its whole duration.

    Parameters
    ----------
    end_time: total duration of the pulse (in ns)
    shape   : string specifying the name of th shape
    args    : tuple containing the parameters of the shapes. For more generality, values for the possible free parameters of the functions are also expected. In case the desired shape does not have free parameters, any dummy value can be provided.
     The tuple is organised as follows: c (optimsed blackman shape parameter), alpha (0th order Kaiser shape parameter), gamma (1st order Kaiser shape parameter), a (gaussian and gaussian-like shape parameter), rabi_frequency, rotation_angle.

     Returns
     -------

    """
    from qubit_utilities import prepare_filter

    c, alpha, gamma, a, rabi_frequency, rotation_angle, omega, omega0_max, nb_time_pts = args

    # args = (c, alpha, gamma, rabi_frequency, rotation_angle)

    if shape == 'kaiser0':
        times = np.linspace(0, end_time, nb_time_pts)
    else:
        times = np.linspace(-end_time / 2, end_time / 2, nb_time_pts)

    # Define the arguments for the shape function
    args = {
        'c': c,
        'alpha': alpha,
        'gamma': gamma,
        'rabi_freq': rabi_frequency,
        't_end': end_time,
    }

    unfiltered_shape = np.zeros(nb_time_pts)
    if shape == 'slepian':
        from scipy.signal.windows import dpss
        unfiltered_shape = dpss(nb_time_pts, alpha)
    else:
        i = 0
        for t in times:
            unfiltered_shape[i] = shapes[shape](t, args)
            i += 1

    b, a = prepare_filter(omega0_max / (2 * np.pi) - 400e6,
                          omega0_max / (2 * np.pi) + 400e6,
                          nb_time_pts / end_time,
                          order=3)

    filtered_shape = lfilter(b, a, unfiltered_shape)

    return filtered_shape
Пример #12
0
    def get_spectrogram(self, nframes, lframes):
        """
        Go through the data frame by frame and perform transformation. They can be plotted using pcolormesh
        x, y and z are ndarrays and have the same shape. In order to access the contents use these kind of
        indexing as below:

        #Slices parallel to frequency axis
        nrows = np.shape(x)[0]
        for i in range (nrows):
            plt.plot(x[i,:], z[i,:])

        #Slices parallel to time axis
        ncols = np.shape(y)[1]
        for i in range (ncols):
            plt.plot(y[:,i], z[:, i])

        :return: frequency, time and power for XYZ plot,
        """

        assert self.method in ['fft', 'welch', 'mtm']

        # define an empty np-array for appending
        pout = np.zeros(nframes * lframes)

        if self.method == 'fft':
            sig = np.reshape(self.data_array, (nframes, lframes))
            zz = np.abs(np.fft.fftshift(np.fft.fft(sig, axis=1)))

        elif self.method == 'welch':
            # go through the data array section wise and create a results array
            for i in range(nframes):
                f, p = self.get_pwelch(
                    self.data_array[i * lframes:(i + 1) * lframes] *
                    self.get_window(lframes))
                pout[i * lframes:(i + 1) * lframes] = p
            # fold the results array to the mesh grid
            zz = np.reshape(pout, (nframes, lframes))

        elif self.method == 'mtm':
            mydpss = dpss(M=lframes, NW=4, Kmax=6)
            #f = self.get_fft_freqs_only(x[0:lframes])
            sig = np.reshape(self.data_array, (nframes, lframes))
            zz = pmtm(sig, mydpss, axis=1)

        # create a mesh grid from 0 to nframes -1 in Y direction
        xx, yy = np.meshgrid(np.arange(lframes), np.arange(nframes))
        yy = yy * lframes / self.fs
        xx = xx - xx[-1, -1] / 2
        xx = xx * self.fs / lframes

        return xx, yy, zz
def integr_slepian(x, *arg):
    from scipy.integrate import simps
    from scipy.signal.windows import dpss

    c, alpha, gamma, a, rabi_frequency, rotation_angle = arg

    #TODO: Add smarter way to recover the proper frequency to consider here
    omega0_max = 2 * np.pi * 10.1e9  # 10.1GHz (valid for 2 qubits simulation)
    nb_time_pts = np.ceil(x / (1. / (omega0_max) / 100)).astype(int)

    integral = simps(dpss(nb_time_pts, alpha),
                     np.linspace(-x / 2, x / 2, nb_time_pts))

    return rotation_angle / rabi_frequency - integral
Пример #14
0
    def get_spectrogram(self, nframes, lframes):
        """
        Go through the data frame by frame and perform transformation. They can be plotted using pcolormesh
        x, y and z are ndarrays and have the same shape. In order to access the contents use these kind of
        indexing as below:

        #Slices parallel to frequency axis
        nrows = np.shape(x)[0]
        for i in range (nrows):
            plt.plot(x[i,:], z[i,:])

        #Slices parallel to time axis
        ncols = np.shape(y)[1]
        for i in range (ncols):
            plt.plot(y[:,i], z[:, i])

        :return: frequency, time and power for XYZ plot,
        """

        assert self.method in ['fft', 'welch', 'mtm']

        # define an empty np-array for appending
        pout = np.zeros(nframes * lframes)

        if self.method == 'fft':
            sig = np.reshape(self.data_array, (nframes, lframes))
            zz = np.abs(np.fft.fftshift(np.fft.fft(sig, axis=1)))

        elif self.method == 'welch':
            # go through the data array section wise and create a results array
            for i in range(nframes):
                f, p = self.get_pwelch(
                    self.data_array[i * lframes:(i + 1) * lframes] * self.get_window(lframes))
                pout[i * lframes:(i + 1) * lframes] = p
            # fold the results array to the mesh grid
            zz = np.reshape(pout, (nframes, lframes))

        elif self.method == 'mtm':
            mydpss = dpss(M=lframes, NW=4, Kmax=6)
            #f = self.get_fft_freqs_only(x[0:lframes])
            sig = np.reshape(self.data_array, (nframes, lframes))
            zz = pmtm(sig, mydpss, axis=1)

        # create a mesh grid from 0 to nframes -1 in Y direction
        xx, yy = np.meshgrid(np.arange(lframes), np.arange(nframes))
        yy = yy * lframes / self.fs
        xx = xx - xx[-1, -1] / 2
        xx = xx * self.fs / lframes

        return xx, yy, zz
Пример #15
0
 def gen_sequences(self, eigenvalue):
     '''
     generate the discrete prolate spheroidal sequences in the time domain
     '''
     try:
         time_0 = time.time()
         self.vecs, self.vals = windows.dpss(self.N, self.N*self.W, self.K, return_ratios=True)
     except:
         diag_main = ((self.N-1)/2-np.arange(self.N))**2 * np.cos(2*np.pi*self.W)
         diag_off = np.arange(1, self.N) * np.arange(self.N-1, 0, -1) / 2
         vecs = eigh_tridiagonal(diag_main, diag_off, select='i', select_range=(self.N-self.K,self.N-1))[1]
         self.vecs = (vecs * np.where(vecs[0,:]>0, 1, -1)).T[::-1] # normalized energy, polarity follows Slepian convention
         if eigenvalue:
             A = toeplitz(np.insert( np.sin(2*np.pi*self.W*np.arange(1,self.N))/(np.pi*np.arange(1,self.N)), 0, 2*self.W ))
             self.vals = np.diag(self.vecs @ A @ self.vecs.T) # @ is matrix multiplication
Пример #16
0
    def tapers(self, N, NW, L):
        """
        Compute data tapers (which are discrete prolate spheroidal sequences (dpss))

        Uses scipy implementation, see:
            https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.windows.dpss.html

        :param N: Size of each taper
        :param NW: Half Bandwidth
        :param L: Number of tapers
        :return: NumPy array of data tapers
        """

        # Note the original ASPIRE implementation is negated from original scipy...
        #  but at time of writing subsequent code was agnostic to sign.
        return dpss(M=N, NW=NW, Kmax=L, return_ratios=False).T
Пример #17
0
def pds_mtm(t, x, f_res):
    '''PDS_MTM - Multi-taper spectral estimate
    This is DW's adaptation of Adam Taylor's PDS_MTM code
    ff,Pxx = PDS_MTM(tt,xx,fres) calculates one-side multi-taper
    spectrogram.

      TT [T] indicates time points.
      XX [T] is the (optical) data.
      FRES [scalar] is the half-width of the transform of the tapers used;
                    It must be in reciprocal units of those of TT.

      FF [F] is the resulting (one-sided) frequency base.
      Pxx [FxK] are the spectral estimates from each individual taper

    Note that the nature of the beast is that the output Pxx has a 
    full width of 2*FRES even if the signal XX is perfectly sinusoidal.'''

    # From Adam's comments:
    # t is a col vector
    # elements of t are evenly spaced and increasing
    # x is a real matrix with the same number of rows as t
    # f_res is the half-width of the transform of the tapers used
    #   it must be in reciprocal units of those of t
    # N_fft is the length to which data is zero-padded before FFTing
    # this works on the columns of x independently
    #
    # f is the frequncy base, which is one-sided
    # Pxx's cols are the the one-sided spectral estimates of the cols of x
    # Pxxs is 3D, (frequency samples)x(cols of x)x(tapers), gives the spectrum
    #   estimate for each taper
    #
    # we assume that x is real, and return the one-side periodogram
    
    tapers = None
    N_fft = 2**np.ceil(np.log2(len(t)))

    N = len(t)  # number of time samples
    dt  =(t[N]-t[1])/(N-1)
    fs=1/dt

    # compute nw and K
    nw = N*dt*f_res
    K = np.floor(2*nw-1)

    tapers = dpss(N,nw,K)
    tapers = np.reshape(tapers, [N, 1, K])
Пример #18
0
def mtspectrumc(data, params):
    '''
    Function responsible for calculating Multi-taper spectrum.

    :param data: numpy array, required.
        2-D matrix [samples, trials]. It contains the data to process.
    :param params: dict, required.
        Contained the executions parameters and necessary constants for the 
        calculations of spectrum of the input data.
        params = dict(fs = srate, fpass = [lowpass, highpass], 
                        tapers = [2, 2, 1], trialave = 1)
        
    :return s: numpy array.
        Contain the aritmetic mean of the spectral power caculated with the fft.
    :return f: numpy array.
        Contains the frecuens obtained from the limits in fpass.    
    '''
    (samples, trials) = data.shape
    tapers, pad, fs, fpass, err, trialave = get_params(params)  #get params
    nfft = 2**(ceil(log(samples, 2)))  #calculate dimensions of window
    f, find = getfgrid(fs, nfft, fpass)  #get de frequencies
    #Calculate  a matrix of tapering windows
    tapers = dpss(samples, tapers[0], tapers[1]).transpose()
    tapers = tapers * sqrt(fs)
    #Resize the data to calculate the spectrum power with fft
    (r, c) = tapers.shape
    tapers = tapers.reshape((r, c, 1))
    matrix_one = ones((samples, c, trials), dtype=float32)
    tapers = tapers * matrix_one
    data = data.reshape((samples, trials, 1))
    matrix_one = ones((samples, trials, c), dtype=float32)
    data = (data * matrix_one).transpose(0, 2, 1)
    data_proj = data * tapers
    #calculate the spectrum power with fft
    j = fft(data_proj, nfft, axis=0) / fs
    #getting the values.
    j = j[find == True, :, :]
    #Eliminate the imaginary part of the data.
    s = real(mean(conj(j) * j, axis=1))

    if trialave == 1: s = squeeze(mean(s, axis=1))
    else: s = squeeze(s)
    return s, f
Пример #19
0
def slepian_basis_gen(n_time_slots,discretization_time,bandwidth,min_digitization):
    """Full bandwidth in Hz, # of cycles in a second
    Slepian sequence also known as discrete prolate spheroidal sequence, or DPSS
    Uses scipy.signal.windows.dpss
    """
    
    NW = bandwidth*discretization_time *n_time_slots
    n_eigenbasis =  np.int(NW*2)
    slepian_basis = windows.dpss(n_time_slots, NW, n_eigenbasis)
    basis_max = np.amax(abs(slepian_basis), axis=1)
    #basis_start = np.amax(abs(slepian_basis[-1:1]), axis=1)
    n_valid_basis = n_eigenbasis
    for i in range(n_eigenbasis):
    #print((slepian_basis[i][0]-(slepian_basis[-1][1]-(slepian_basis[-1][0])))/basis_max[i], (min_digitization*(i+1)))
        if((slepian_basis[i][0]-(slepian_basis[-1][1]-(slepian_basis[-1][0])))/basis_max[i] > (min_digitization*(i+1))):
            n_valid_basis = i
            break
    if(n_valid_basis < 1):
        print("Error: No valid basis! Bandwidth too low or time too short ")   
    return  slepian_basis
Пример #20
0
def mtm_svd_lfv(ts2d,nw,kk,dt) :

	# Compute spectrum at each grid point
	p, n = ts2d.shape

	# Remove the mean and divide by std
	vm = np.nanmean(ts2d, axis=0) # mean
	vmrep = repmat(vm,ts2d.shape[0],1)
	ts2d = ts2d - vmrep
	vs = np.nanstd(ts2d, axis=0) # standard deviation
	vsrep = repmat(vs,ts2d.shape[0],1)
	ts2d = np.divide(ts2d,vsrep)
	ts2d = np.nan_to_num(ts2d)

	# Slepian tapers
	psi = dpss(p,nw,kk)

	npad = 2**int(np.ceil(np.log2(abs(p)))+2)
	nf = int(npad/2)
	ddf = 1./(npad*dt)
	fr = np.arange(0,nf)*ddf
	
	# Get the matrix of spectrums
	psimats = []
	for k in range(kk):
		psimat2 = np.transpose( repmat(psi[k,:],ts2d.shape[1],1) ) 
		psimat2 = np.multiply(psimat2,ts2d)
		psimats.append(psimat2)
	psimats=np.array(psimats)
	nev = np.fft.fft(psimats,n=npad,axis=1)
	nev = np.fft.fftshift(nev,axes=(1))
	nev = nev[:,nf:,:] 

	# Calculate svd for each frequency
	lfvs = np.zeros(nf)*np.nan
	for j in range(nf) :
		U,S,V = np.linalg.svd(nev[:,j,:], full_matrices=False)
		lfvs[j] = S[0]**2/(np.nansum(S[1:])**2)

	return fr, lfvs
Пример #21
0
def mtm_svd_recon(ts2d, nw, kk, dt, fo) :

	imode = 0
	lan = 0
	vw = 0

	# Compute spectrum at each grid point
	p, n = ts2d.shape

	# Remove the mean and divide by std
	vm = np.nanmean(ts2d, axis=0) # mean
	vmrep = repmat(vm,ts2d.shape[0],1)
	ts2d = ts2d - vmrep
	vs = np.nanstd(ts2d, axis=0) # standard deviation
	vsrep = repmat(vs,ts2d.shape[0],1)
	ts2d = np.divide(ts2d,vsrep)
	ts2d = np.nan_to_num(ts2d)

	# Slepian tapers
	psi = dpss(p,nw,kk)

	npad = 2**int(np.ceil(np.log2(abs(p)))+2)
	nf = int(npad/2)
	ddf = 1./(npad*dt)
	fr = np.arange(0,nf)*ddf
	
	# Get the matrix of spectrums
	psimats = []
	for k in range(kk):
		psimat2 = np.transpose( repmat(psi[k,:],ts2d.shape[1],1) ) 
		psimat2 = np.multiply(psimat2,ts2d)
		psimats.append(psimat2)
	psimats=np.array(psimats)
	nev = np.fft.fft(psimats,n=npad,axis=1)
	nev = np.fft.fftshift(nev,axes=(1))
	nev = nev[:,nf:,:] 

	# Initialiser les matrices de sorties
	S = np.ones((kk, len(fo)))*np.nan 
	vexp = [] ; totvarexp = [] ; iis = []

	D = vsrep

	envmax = np.zeros(len(fo))*np.nan

	for i1 in range(len(fo)):

		# closest frequency
		iif = (np.abs(fr - fo[i1])).argmin()
		iis.append(iif)
		ff0 = fr[iif]
		print('( %i ) %.2f cyclesyr | %.2f yr'%(iif,ff0,1/ff0))

		U,S0,Vh = np.linalg.svd(nev[:,iif,:].T,full_matrices=False)
		##V = Vh.T.conj()
		V = Vh
		S[:,i1] = S0

		env1 = envel(ff0, iif, fr, dt, ddf, p, kk, psi, V) # condition 1

		cs=[1]
		sn=[0]
		c=np.cos(2*np.pi*ff0*dt)
		s=np.sin(2*np.pi*ff0*dt)
		for i2 in range(1,p):
			cs.append( cs[i2-1]*c-sn[i2-1]*s )
			sn.append( cs[i2-1]*s+sn[i2-1]*c )
		CS = [complex(cs[i], sn[i]) for i in range(len(cs))]
		CS=np.conj(CS)
	
		# Reconstructions
		R = np.real( D * S[imode, i1] * np.outer(U[:,imode], CS*env1).T )

		vsr=np.var(R,axis=0)
		vexp.append( vsr/(vs**2)*100 )
		totvarexp.append( np.nansum(vsr)/np.nansum(vs**2)*100 )

	return vexp, totvarexp, iis
Пример #22
0
def mtm_svd_conf(ts2d,nw,kk,dt,niter,sl) :

	# Compute spectrum at each grid point
	p, n = ts2d.shape

	npad = 2**int(np.ceil(np.log2(abs(p)))+2)
	nf = int(npad/2)
	ddf = 1./(npad*dt)
	fr = np.arange(0,nf)*ddf
	
	# range of frequencies
	fran = [0, 0.5/dt]
	nfmin = (np.abs(fr-fran[0])).argmin()
	nfmax = (np.abs(fr-fran[1])).argmin()
	fr = fr[nfmin:nfmax]

	q = [int(niter*each) for each in sl]

	# Remove the mean and divide by std
	vm = np.nanmean(ts2d, axis=0) # mean
	vmrep = repmat(vm,ts2d.shape[0],1)
	ts2d = ts2d - vmrep
	vs = np.nanstd(ts2d, axis=0) # standard deviation
	vsrep = repmat(vs,ts2d.shape[0],1)
	ts2d = np.divide(ts2d,vsrep)
	ts2d = np.nan_to_num(ts2d)
	
	# Slepian tapers
	psi = dpss(p,nw,kk)

	partvar = np.ones((niter, len(fr)+1))*np.nan
	for it in range(niter):
		print('Iter %i'%it)
		shr = np.random.permutation(ts2d) # random permutation of each time series
	
		# Spectral estimation
		psimats = []
		for k in range(kk):
			psimat2 = np.transpose( repmat(psi[k,:],shr.shape[1],1) ) 
			psimat2 = np.multiply(psimat2,shr)
			psimats.append(psimat2)
		psimats=np.array(psimats)
		nevconf = np.fft.fft(psimats,n=npad,axis=1)
		nevconf = np.fft.fftshift(nevconf,axes=(1))
		nevconf = nevconf[:,nf:,:]

		# Calculate svd for each frequency
		for j in range(nfmin,nfmax) :
			U,S,V = np.linalg.svd(nevconf[:,j,:], full_matrices=False)
			partvar[it,j] = S[0]**2/(np.nansum(S[1:])**2)

	np.sort(partvar, axis=1)

	freq_sec = nw/(p*dt)
	ibs = (np.abs(fr-freq_sec)).argmin() ; ibs=range(ibs)
	ibns = range(ibs[-1]+1, len(fr))
	fray = 1./(p*dt)
	fbw = 2*nw*fray
	ifbw = int(round(fbw/(fr[2]-fr[1])))

	evalper = np.zeros((len(q),len(fr)))
	for i in range(len(q)):
		y2 = np.zeros(len(fr))
		y = partvar[q[i],:] ### right order indices?
		y1 = signal.medfilt(y,ifbw)
		y2[ibs] = np.mean(y[ibs])
		a = np.polyfit(fr[ibns],y1[ibns],10)
		y2[ibns] = np.polyval(a, fr[ibns])
		evalper[i,:] = y2
	
	return fr, evalper
Пример #23
0
 def test_basic(self):
     # Test against hardcoded data
     for k, v in dpss_data.items():
         win, ratios = windows.dpss(*k, return_ratios=True)
         assert_allclose(win, v[0], atol=1e-7, err_msg=k)
         assert_allclose(ratios, v[1], rtol=1e-5, atol=1e-7, err_msg=k)
Пример #24
0
def multitaper(P, D, dt, tshift, regul):
    """
    Output has to be filtered (Noise appears in high-frequency)!
    multitaper: takes Ved-Kathrins code and changes inputs to
    make it run like Helffrich algorithm, minus normalization and with
    questionable calculation of pre-event noise (have to double check this
    and compare it to the regular FFT based estimate without any tapers)

    INPUT:
        P - component containing source time function
        D - component containing converted wave
        dt - sampling interval
        tshift - time shift of primary arrival
        regul - regularization, either 'fqd' for frequency dependent
                or 'con' for constant

    Findings: when P arrival is not in the center of the window, the
    amplitudes are not unity at the beginning and decreasing from there on.
    Instead they peak at the time shift which corresponds to the middle index
    in the P time window.

    TB  = time bandwidth product (usually between 2 and 4)
    NT  = number of tapers to use, has to be <= 2*TB-1
    TB = 4; NT = 7; #choice of TB = 4, NT = 3 is supposed to be optimal
    t0 = -5; t1 = max(time); # This defines the beginning and end of the lag
    times for the receiver function

    changed by KS June 2016, added coherence and variance estimate; output
    RF in time domain (rf), RF in freq. domain (tmpp), and variance of RF
    (var_rf); can be used as input for multitaper_weighting.m
    the input "regul" defines which type of regularization is used,
    regul='fqd' defines frequency dependent regularisation from pre-event
    noise, regul='con' defines adding a constant value (here maximum of
    pre-event noise) as regularisation"""

    # wavelet always in the center of the window
    # Original from Ved's
    # win_len = tshift*2;
    # Modification to get P&L
    # win_len = length(P)*dt;
    # Modificaiton to get Helffrich
    win_len = 50

    Nwin = round(win_len / dt)

    # Fraction of overlap overlap between moving time windows. As your TB
    # increases, the frequency smearing gets worse, which means that the RFs
    # degrate at shorter and shorter lag times. Therefore, as you increase TB,
    # you should also increase Poverlap.
    Poverlap = 0.75

    # Length of waveforms;
    nh = len(P)

    # Create moving time windowed slepians
    starts = np.arange(0, nh - Nwin + 1, round((1 - Poverlap) * Nwin))

    # tapernumber, bandwith
    # is in general put to NT=3, and bandwidth to 2.5
    # TB=2.5;
    # #NT=2*TB-1; #4 tapers
    # NT=3;
    TB = 4
    # NT=2*TB-1; #4 tapers
    NT = 3

    # Construct Slepians
    Etmp, lambdas = dpss(Nwin, TB, Kmax=NT, return_ratios=True)
    E = np.zeros([len(starts) * NT, nh])
    n = 0

    NUM = np.zeros([NT, len(P)])
    DEN = np.zeros([NT, len(D)])
    DUM = np.zeros([NT, len(D)])

    ESTP = np.zeros([NT, len(P)])
    ESTD = np.zeros([NT, len(D)])

    # finding frequency dependent regularisation parameter DEN_noise
    # added: KS 26.06.2016
    Pn = np.zeros(np.shape(P))

    # Pn(3/dt:(tshift-5)/dt)=P(3/dt:(tshift-5)/dt)
    Pn[:round((tshift - 2) / dt)] = P[:round((tshift - 2) / dt)]
    # pre-event noise: starting 3s after trace start
    # stop 10s before theoretical start of P
    # wave to aviod including it

    DEN_noise = np.zeros([NT, len(P)])

    # Multitaper
    # SR: problem here is how the loop is done ... there's only a peak
    # at the pulse because the two windows of the num and den are moving
    # together. One should first comput the entire estimate of the wavelet
    # and the data for each valie of k, and then do the sum of products for
    # each k!!!
    for k in range(NT):
        for j in range(len(starts)):
            E[n, starts[j]:(starts[j] + Nwin)] = np.transpose(Etmp[k, :])

            tmp1 = np.fft.fft(np.multiply(E[n, :], P))
            tmp2 = np.fft.fft(np.multiply(E[n, :], D))

            NUM[k, :] = NUM[k, :] + np.multiply(lambdas[k] * tmp1.conj(), tmp2)
            DEN[k, :] = DEN[k, :] + np.multiply(lambdas[k] * tmp1.conj(), tmp1)

            ESTP[k, :] = ESTP[k, :] + lambdas[k] * tmp1
            ESTD[k, :] = ESTD[k, :] + lambdas[k] * tmp2

            # DUM only from D trace (converted wave component) used in
            # coherence estimate
            DUM[k, :] = DUM[k, :] + np.multiply(lambdas[k] * tmp2.conj(), tmp2)

            # pre-event noise
            # always stick to first time window
            tmp1n = np.fft.fft(np.multiply(E[n, :], Pn))
            DEN_noise[k, :] = DEN_noise[k, :] +\
                np.multiply(lambdas[k]*tmp1n.conj(), tmp1n)
            n = n + 1

    # max_imag_ep = max(abs(np.imag(np.fft.ifft(sum(ESTP)))))
    # max_imag_ed = max(abs(np.imag(np.fft.ifft(sum(ESTD)))))
    # ep = np.real(np.fft.ifft(sum(ESTP)));
    # ed = np.real(np.fft.ifft(sum(ESTD)));

    # Calculate optimal RF with frequency-dependend regularisation
    freqdep = regul == 'fqd'
    const = regul == 'con'

    if freqdep:
        tmpp = np.divide(
            np.sum(np.multiply(ESTP.conj(), ESTD), axis=0),
            np.sum(np.multiply(ESTP.conj(), ESTP), axis=0) +
            sum(DEN_noise)) * 1 / dt
        tmpp_l = np.divide(
            np.sum(np.multiply(ESTP.conj(), ESTP), axis=0),
            np.sum(np.multiply(ESTP.conj(), ESTP), axis=0) +
            sum(DEN_noise)) * 1 / dt

        N2 = np.floor(nh / 2) + 1
        for i in range(int(N2)):
            fac = np.cos(np.pi / 2 * i / N2)**2
            tmpp[i] = tmpp[i] * fac

    elif const:
        # ordinary regularisation with adding only a constant value
        eps = DEN_noise.real.max() + 1
        tmpp = np.divide(np.sum(np.multiply(ESTP.conj(), ESTD), axis=0),
                         np.sum(np.multiply(ESTP.conj(), ESTP) + eps,
                                axis=0)) * 1 / dt
        tmpp_l = np.divide(
            np.sum(np.multiply(ESTP.conj(), ESTD), axis=0),
            np.sum(np.multiply(ESTP.conj(), ESTP) + eps, axis=0)) * 1 / dt

    else:
        raise Exception(
            'Regularization not defined (your input: regul=', regul,
            """). Use either "fqd" for frequency-dependent
                        or "con" for constant value regularization.""")

    # RF without variance weighting
    tmp1 = np.real(np.fft.ifft(tmpp))
    tmp1_l = np.fft.ifft(tmpp_l).real

    # Interpolate to desired
    N = len(P)
    rf = tmp1[round(N - tshift / dt):N]
    rf = np.append(rf, tmp1[:N - round(tshift / dt)])
    # rf[round(tshift/dt):N] = tmp1[:N-round(tshift/dt)]

    lrf = tmp1_l[round(N - tshift / dt):N]
    lrf = np.append(lrf, tmp1_l[:round(N - tshift / dt)])
    # lrf[tshift/dt:N] = tmp1_l[:N-tshift/dt]

    ####
    # Coherence and Variance of RF
    # added: KS 26.06.2016
    # C_rf = np.divide(NUM, np.sqrt(np.multiply(DUM, DEN)))
    # var_rf = np.zeros(len(C_rf))
    # for ii in range(len(C_rf)):
    #     var_rf[ii] = ((1-abs(C_rf[ii])**2)/((NT-1)*abs(C_rf[ii])**2))*(abs(tmpp[ii])**2)
    var_rf = None
    return rf, lrf, var_rf, tmpp
Пример #25
0
    Estimate the power spectral density of the input signal.
    signal: n-dimensional array of real or complex values
    dpss: the Slepian matrix
    axis:   axis along which to apply the Slepian windows. Default is the last one.
    '''
    # conversion to positive-only index
    axis_p = (axis + signal.ndim) % signal.ndim
    sig_exp_shape = list(signal.shape[:axis]) + [1] + list(signal.shape[axis:])
    tap_exp_shape = [1] * axis_p + \
        list(dpss.shape) + [1] * (signal.ndim - 1 - axis_p)
    signal_tapered = signal.reshape(sig_exp_shape) * dpss.reshape(
        tap_exp_shape)
    return np.fft.fftshift(np.mean(np.absolute(
        np.fft.fft(signal_tapered, axis=axis_p + 1))**2,
                                   axis=axis_p),
                           axes=axis_p)


# ------------------------

if __name__ == '__main__':
    # a small test
    # Using traditional values used by Fritz, i.e. NW=4, Max_K = 2x NW-2 = 6
    mydpss = dpss(M=1024, NW=4, Kmax=6)
    sig = np.vectorize(complex)(np.random.rand(1024), np.random.rand(1024))
    print(pmtm(sig, mydpss))

    mydpss = dpss(M=128, NW=4, Kmax=6)
    sig = np.reshape(sig, (8, 128))
    print(pmtm(sig, mydpss, axis=1))
Пример #26
0
 def test_basic(self):
     # Test against hardcoded data
     for k, v in dpss_data.items():
         win, ratios = windows.dpss(*k, return_ratios=True)
         assert_allclose(win, v[0], atol=1e-7, err_msg=k)
         assert_allclose(ratios, v[1], rtol=1e-5, atol=1e-7, err_msg=k)
Пример #27
0
 def test_dpss(self):
     win1 = windows.get_window(('dpss', 3), 64, fftbins=False)
     win2 = windows.dpss(64, 3)
     assert_array_almost_equal(win1, win2, decimal=4)
Пример #28
0
alon_stimreals = extract_files_to_list(alon_recon, alon_stim)
alon_reconstructed_stimuli = extract_files_to_list(alon_recon, alon_recons)

alon_recon = alon_reconstructed_stimuli[0].T.values
alon_recon.resize(2400)
alon_real_stim = alon_stimreals[0].T
alon_stim_mean = alon_real_stim.mean(axis=1).values - 0.4
alon_stim_mean.resize(2400)
# set up coherence parameters and multitaper windows
window_len = 256
NW = 2.5
n_tapers = 4
overlap = 0.5

windows, eigvals = dpss(window_len, NW, n_tapers, return_ratios=True)

# do coherence between mean stimulus and reconstruction
mean_multitaper_df = pd.DataFrame()

for window, eigval in zip(windows, eigvals):
    freq, cohere = scipy.signal.coherence(alon_stim_mean, alon_recon, fs=1000, window=window)
    cohere = pd.DataFrame(cohere)
    cohere_scale = cohere * eigval
    mean_multitaper_df = pd.concat([mean_multitaper_df, cohere_scale],
                                      axis=1,
                                      ignore_index=True)
    
coherence_from_mean = mean_multitaper_df.mean(axis=1)

# do coherence between each stimulus and reconstruction and then take mean
Пример #29
0
# We can compare the window to `kaiser`, which was invented as an alternative
# that was easier to calculate [Re991e28c1f6b-3]_ (example adapted from
# `here <https://ccrma.stanford.edu/~jos/sasp/Kaiser_DPSS_Windows_Compared.html>`_):

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import windows, freqz
N = 51
fig, axes = plt.subplots(3, 2, figsize=(5, 7))
for ai, alpha in enumerate((1, 3, 5)):
    win_dpss = windows.dpss(N, alpha)
    beta = alpha*np.pi
    win_kaiser = windows.kaiser(N, beta)
    for win, c in ((win_dpss, 'k'), (win_kaiser, 'r')):
        win /= win.sum()
        axes[ai, 0].plot(win, color=c, lw=1.)
        axes[ai, 0].set(xlim=[0, N-1], title=r'$\alpha$ = %s' % alpha,
                        ylabel='Amplitude')
        w, h = freqz(win)
        axes[ai, 1].plot(w, 20 * np.log10(np.abs(h)), color=c, lw=1.)
        axes[ai, 1].set(xlim=[0, np.pi],
                        title=r'$\beta$ = %0.2f' % beta,
                        ylabel='Magnitude (dB)')
for ax in axes.ravel():
    ax.grid(True)
axes[2, 1].legend(['DPSS', 'Kaiser'])
fig.tight_layout()
plt.show()

# And here are examples of the first four windows, along with their
# concentration ratios:
def multitaper_spectrogram(data,
                           fs,
                           frequency_range=None,
                           time_bandwidth=5,
                           num_tapers=None,
                           window_params=None,
                           min_nfft=0,
                           detrend_opt='linear',
                           multiprocess=False,
                           cpus=False,
                           weighting='unity',
                           plot_on=True,
                           clim_scale=True,
                           verbose=True,
                           xyflip=False):
    """ Compute multitaper spectrogram of timeseries data
    Usage:
    mt_spectrogram, stimes, sfreqs = multitaper_spectrogram(data, fs, frequency_range=None, time_bandwidth=5,
                                                                   num_tapers=None, window_params=None, min_nfft=0,
                                                                   detrend_opt='linear', multiprocess=False, cpus=False,
                                                                    weighting='unity', plot_on=True, clim_scale=true, 
                                                                    verbose=True, xyflip=False):
        Arguments:
                data (1d np.array): time series data -- required
                fs (float): sampling frequency in Hz  -- required
                frequency_range (list): 1x2 list - [<min frequency>, <max frequency>] (default: [0 nyquist])
                time_bandwidth (float): time-half bandwidth product (window duration*half bandwidth of main lobe)
                                        (default: 5 Hz*s)
                num_tapers (int): number of DPSS tapers to use (default: [will be computed
                                  as floor(2*time_bandwidth - 1)])
                window_params (list): 1x2 list - [window size (seconds), step size (seconds)] (default: [5 1])
                detrend_opt (string): detrend data window ('linear' (default), 'constant', 'off')
                                      (Default: 'linear')
                min_nfft (int): minimum allowable NFFT size, adds zero padding for interpolation (closest 2^x)
                                (default: 0)
                multiprocess (bool): Use multiprocessing to compute multitaper spectrogram (default: False)
                cpus (int): Number of cpus to use if multiprocess = True (default: False). Note: if default is left
                            as False and multiprocess = True, the number of cpus used for multiprocessing will be
                            all available - 1.
                weighting (str): weighting of tapers ('unity' (default), 'eigen', 'adapt');
                plot_on (bool): plot results (default: True)
                clim_scale (bool): automatically scale the colormap on the plotted spectrogram (default: true)
                verbose (bool): display spectrogram properties (default: true)
                xyflip (bool): transpose the mt_spectrogram output (default: false)
        Returns:
                mt_spectrogram (TxF np array): spectral power matrix
                stimes (1xT np array): timepoints (s) in mt_spectrogram
                sfreqs (1xF np array)L frequency values (Hz) in mt_spectrogram

        Example:
        In this example we create some chirp data and run the multitaper spectrogram on it.
            import numpy as np  # import numpy
            from scipy.signal import chirp  # import chirp generation function
            # Set spectrogram params
            fs = 200  # Sampling Frequency
            frequency_range = [0, 25]  # Limit frequencies from 0 to 25 Hz
            time_bandwidth = 3  # Set time-half bandwidth
            num_tapers = 5  # Set number of tapers (optimal is time_bandwidth*2 - 1)
            window_params = [4, 1]  # Window size is 4s with step size of 1s
            min_nfft = 0  # No minimum nfft
            detrend_opt = 'constant'  # detrend each window by subtracting the average
            multiprocess = True  # use multiprocessing
            cpus = 3  # use 3 cores in multiprocessing
            weighting = 'unity'  # weight each taper at 1
            plot_on = True  # plot spectrogram
            clim_scale = False # don't auto-scale the colormap
            verbose = True  # print extra info
            xyflip = False  # do not transpose spect output matrix
            # Generate sample chirp data
            t = np.arange(1/fs, 600, 1/fs)  # Create 10 min time array from 1/fs to 600 stepping by 1/fs
            f_start = 1  # Set chirp freq range min (Hz)
            f_end = 20  # Set chirp freq range max (Hz)
            data = chirp(t, f_start, t[-1], f_end, 'logarithmic')
            # Compute the multitaper spectrogram
            spect, stimes, sfreqs = multitaper_spectrogram(data, fs, frequency_range, time_bandwidth, num_tapers,
                                                           window_params, min_nfft, detrend_opt, multiprocess,
                                                           cpus, weighting, plot_on, clim_scale, verbose, xyflip):

        This code is companion to the paper:
        "Sleep Neurophysiological Dynamics Through the Lens of Multitaper Spectral Analysis"
           Michael J. Prerau, Ritchie E. Brown, Matt T. Bianchi, Jeffrey M. Ellenbogen, Patrick L. Purdon
           December 7, 2016 : 60-92
           DOI: 10.1152/physiol.00062.2015
         which should be cited for academic use of this code.

         A full tutorial on the multitaper spectrogram can be found at:  #   http://www.sleepEEG.org/multitaper

        Copyright 2021 Michael J. Prerau Laboratory. - http://www.sleepEEG.org
        Authors: Michael J. Prerau, Ph.D., Thomas Possidente
        
        Last modified - 2/18/2021 Thomas Possidente
  __________________________________________________________________________________________________________________
    """

    #  Process user input
    [
        data, fs, frequency_range, time_bandwidth, num_tapers, winsize_samples,
        winstep_samples, window_start, num_windows, nfft, detrend_opt, plot_on,
        verbose
    ] = process_input(data, fs, frequency_range, time_bandwidth, num_tapers,
                      window_params, min_nfft, detrend_opt, plot_on, verbose)

    # Set up spectrogram parameters
    [window_idxs, stimes, sfreqs,
     freq_inds] = process_spectrogram_params(fs, nfft, frequency_range,
                                             window_start, winsize_samples)
    # Display spectrogram parameters
    if verbose:
        display_spectrogram_props(fs, time_bandwidth, num_tapers,
                                  [winsize_samples, winstep_samples],
                                  frequency_range, detrend_opt)

    # Split data into segments and preallocate
    data_segments = data[window_idxs]

    # COMPUTE THE MULTITAPER SPECTROGRAM
    #     STEP 1: Compute DPSS tapers based on desired spectral properties
    #     STEP 2: Multiply the data segment by the DPSS Tapers
    #     STEP 3: Compute the spectrum for each tapered segment
    #     STEP 4: Take the mean of the tapered spectra

    # Compute DPSS tapers (STEP 1)
    dpss_tapers, dpss_eigen = dpss(winsize_samples,
                                   time_bandwidth,
                                   num_tapers,
                                   return_ratios=True)
    dpss_eigen = np.reshape(dpss_eigen, (num_tapers, 1))

    # pre-compute weights
    if weighting == 'eigen':
        wt = dpss_eigen / num_tapers
    elif weighting == 'unity':
        wt = np.ones(num_tapers) / num_tapers
        wt = np.reshape(wt, (num_tapers, 1))  # reshape as column vector
    else:
        wt = 0

    tic = timeit.default_timer()  # start timer

    # set all but 1 arg of calc_mts_segment to constant (so we only have to supply one argument later)
    calc_mts_segment_plus_args = partial(calc_mts_segment,
                                         dpss_tapers=dpss_tapers,
                                         nfft=nfft,
                                         freq_inds=freq_inds,
                                         detrend_opt=detrend_opt,
                                         num_tapers=num_tapers,
                                         dpss_eigen=dpss_eigen,
                                         weighting=weighting,
                                         wt=wt)

    if multiprocess:  # use multiprocessing
        if not cpus:  # if cpus not specfied, use all but 1
            pool = Pool(cpu_count() - 1)
        else:  # else us specified number
            pool = Pool(cpus)

        # Compute multiprocess multitaper spect.
        mt_spectrogram = pool.map(calc_mts_segment_plus_args, data_segments)
        pool.close()
        pool.join()

    else:  # if no multiprocessing, compute normally
        mt_spectrogram = np.apply_along_axis(calc_mts_segment_plus_args, 1,
                                             data_segments)

    # Compute one-sided PSD spectrum
    mt_spectrogram = np.asarray(mt_spectrogram)
    mt_spectrogram = mt_spectrogram.T
    dc_select = np.where(sfreqs == 0)
    nyquist_select = np.where(sfreqs == fs / 2)
    select = np.setdiff1d(np.arange(0, len(sfreqs)),
                          [dc_select, nyquist_select])

    mt_spectrogram = np.vstack([
        mt_spectrogram[dc_select[0], :], 2 * mt_spectrogram[select, :],
        mt_spectrogram[nyquist_select[0], :]
    ]) / fs

    # Flip if requested
    if xyflip:
        mt_spectrogram = np.transpose(mt_spectrogram)

    # End timer and get elapsed compute time
    toc = timeit.default_timer()
    elapsed_time = toc - tic
    if verbose:
        print("\n Multitaper compute time: " + str(elapsed_time) + " seconds")

    # Plot multitaper spectrogram
    if plot_on:

        # Eliminate bad data from colormap scaling
        spect_data = mt_spectrogram
        clim = np.percentile(
            spect_data, [5, 95])  # Scale colormap from 5th percentile to 95th

        plt.figure(1, figsize=(10, 5))
        librosa.display.specshow(nanpow2db(mt_spectrogram),
                                 x_axis='time',
                                 y_axis='linear',
                                 x_coords=stimes,
                                 y_coords=sfreqs,
                                 shading='auto',
                                 cmap="jet")
        plt.colorbar(label='Power (dB)')
        plt.xlabel("Time (HH:MM:SS)")
        plt.ylabel("Frequency (Hz)")
        if clim_scale:
            plt.clim(clim)  # actually change colorbar scale
        plt.show()

    # Put outputs into better format for output
    #stimes = np.mat(stimes)
    #sfreqs = np.mat(sfreqs)

    if all(mt_spectrogram.flatten() == 0):
        print("\n Data was all zeros, no output")

    return mt_spectrogram, stimes, sfreqs
def multi_taper_fft(Win, spika, spiko):
    TT = spika.shape[1]
    N = Win
    Trials = spika.shape[0]
    TTa = 1 + np.floor(Win / 2)
    TTb = TT - np.floor(Win / 2)
    TTb = int(TTb)
    W = 2.5
    NW = np.floor(2 * ((Win / 1000) * W)) / 2
    tapers = np.array(windows.dpss(Win, NW, 4))
    # print("TTTq" , tap[0])
    KW = np.floor(2 * NW - 1)

    pad = 0
    fpass = np.asarray([0.001, 0.088])
    Fs = 1
    #
    nfft = np.power(2, nextpow2(N))
    df = Fs / nfft
    freqreal = np.arange(0, Fs - df + df, df)  #all possible frequencied
    # findx = [(freqreal >= fpass[0] ) and (freqreal <= fpass[1])]
    findx = np.where(np.logical_and(freqreal >= fpass[0],
                                    freqreal <= fpass[1]))
    findx = findx[0]
    # findx = np.where((freqreal >= fpass[0]) & (freqreal <= fpass[1]))
    f = freqreal[findx]
    for r in range(2):
        zcross_pow = zispika_pow = zispike_pow = zspike_count = zspika_count = np.empty(
            [Trials, nfft])
        if r == 0:
            tr_perm = np.arange(0, Trials)
        else:
            mid = np.floor(Trials / 8) + np.floor(np.random.rand() *
                                                  (3 * Trials / 4))
            tr_perm = np.append(np.arange(mid, Trials), np.arange(1, mid - 1))
        for tr in range(Trials):
            cross_pow = []
            ispika_pow = []
            ispike_pow = []
            spike_count = []
            aspike_count = []
            # spika_count = []
            TTa = 0

            Tstep = np.floor(Win / 4)
            TTb = Win
            while (TTb <= TT):
                # TTbu = int(TTb)+1
                aspiker = spika[tr, TTa:TTb]
                naspiker = aspiker - np.mean(aspiker)
                #TODO differnet numbers
                nspiker = spiko[tr_perm[tr], TTa:TTb]
                spiker = nspiker - np.mean(nspiker)

                for kt in range(int(KW)):
                    aspikero = np.multiply(naspiker, tapers[kt, :])
                    spikero = np.multiply(spiker, tapers[kt, :])

                    J1 = np.fft.fft(aspikero, nfft)
                    J2 = np.fft.fft(spikero, nfft)

                    if (len(ispika_pow) == 0):
                        ispika_pow = np.multiply(J1, np.conj(J1))
                        ispike_pow = np.multiply(J2, np.conj(J2))
                        cross_pow = np.multiply(J1, np.conj(J2))
                        spike_count = nspiker.sum()
                        aspike_count = aspiker.sum()
                    else:
                        ispika_pow = ispika_pow + np.multiply(J1, np.conj(J1))
                        ispike_pow = ispike_pow + np.multiply(J2, np.conj(J2))
                        cross_pow = cross_pow + np.multiply(J1, np.conj(J2))
                        spike_count = spike_count + nspiker.sum()
                        aspike_count = aspike_count + aspiker.sum()
                TTa = TTa + Tstep
                TTb = TTb + Tstep
            zcross_pow[tr] = cross_pow
            zispika_pow[tr] = ispika_pow
            zispike_pow[tr] = ispike_pow
            zspike_count[tr] = spike_count
            zspika_count[tr] = aspike_count

        if (r == 0):
            cohjack = []
            phajack = []
            spajack = []
            spijack = []
            for tr in range(Trials):
                cross_pow = np.delete(zcross_pow, tr, axis=0)
                ispike_pow = np.delete(zispike_pow, tr, axis=0)
                ispika_pow = np.delete(zispika_pow, tr, axis=0)
                aspike_count = np.delete(zspike_count, tr, axis=0)
                spike_count = np.delete(zspika_count, tr, axis=0)

                cross_pow = np.sum(cross_pow, axis=0)
                ispike_pow = np.sum(ispike_pow, axis=0)
                ispika_pow = np.sum(ispika_pow, axis=0)
                spike_count = np.sum(spike_count, axis=0)
                aspike_count = np.sum(aspike_count, axis=0)
                coh = np.divide(
                    cross_pow,
                    np.multiply(np.sqrt(ispike_pow),
                                np.sqrt(ispika_pow)))  #coh mokhtalete!
                coho = np.abs(coh[findx])
                phaso = np.angle(coh(findx))
                #TODO
                spika_pow = ispika_pow[findx] / aspike_count
                spike_pow = ispike_pow[findx] / spike_count
                ifcoher = 1000 * freqreal[findx]

                cohjack = np.append(cohjack, coho)
                phajack = np.append(phajack, coh)
                spajack = np.append(spajack, spika_pow)
                spijack = np.append(spijack, spike_pow)

            coho = np.mean(cohjack)
            scoho = np.std(cohjack) * np.sqrt(Trials - 1)
            pha = np.mean(phajack)
            phaso = np.angle(pha[findx])
            #TODO
            phabo = []

            for iz in range(len(phajack)):
                y = np.angle(phajack[iz, :])
                it = np.where((y[findx] - phaso) > np.pi)
                y[findx[it]] = y[findx[it]] - (2 * np.pi)
                it = np.where((y[findx] - phaso) < -np.pi)
                y[findx[it]] = y[findx[it]] + (2 * np.pi)
                phabo = np.append(phaso, y[findx])

            sphaso = np.std(phabo) * np.sqrt(Trials - 1)
            spika_pow = np.mean(spajack)
            sspika_pow = np.std(spajack) * np.sqrt(Trials - 1)
            spike_pow = np.mean(spijack)
            sspike_pow = np.std(spijack) * np.sqrt(Trials - 1)

        else:
            cross_pow = np.sum(zcross_pow)
            ispike_pow = np.sum(zispike_pow)
            ispika_pow = np.sum(zispika_pow)
            coh = np.divide(
                cross_pow, np.multiply(np.sqrt(ispike_pow),
                                       np.sqrt(ispika_pow)))
            rcoho = np.abs(coh[findx])
            rphaso = np.angle(coh[findx])  #TODO
Пример #32
0
def _dpss_wavelet(sfreq, freqs, n_cycles=7, time_bandwidth=4.0,
                  zero_mean=False):
    """Compute Wavelets for the given frequency range

    Parameters
    ----------
    sfreq : float
        Sampling Frequency.
    freqs : ndarray, shape (n_freqs,)
        The frequencies in Hz.
    n_cycles : float | ndarray, shape (n_freqs,)
        The number of cycles globally or for each frequency.
        Defaults to 7.
    time_bandwidth : float, (optional)
        Time x Bandwidth product.
        The number of good tapers (low-bias) is chosen automatically based on
        this to equal floor(time_bandwidth - 1).
        Default is 4.0, giving 3 good tapers.

    Returns
    -------
    Ws : list of array
        Wavelets time series
    """
    Ws = list()
    if time_bandwidth < 2.0:
        raise ValueError("time_bandwidth should be >= 2.0 for good tapers")
    n_taps = int(np.floor(time_bandwidth - 1))
    n_cycles = np.atleast_1d(n_cycles)

    if n_cycles.size != 1 and n_cycles.size != len(freqs):
        raise ValueError("n_cycles should be fixed or defined for "
                         "each frequency.")

    for m in range(n_taps):
        Wm = list()
        for k, f in enumerate(freqs):
            if len(n_cycles) != 1:
                this_n_cycles = n_cycles[k]
            else:
                this_n_cycles = n_cycles[0]

            t_win = this_n_cycles / float(f)
            t = np.arange(0., t_win, 1.0 / sfreq)
            # Making sure wavelets are centered before tapering
            oscillation = np.exp(2.0 * 1j * np.pi * f * (t - t_win / 2.))

            # Get dpss tapers
            tapers, conc = dpss(t.shape[0], time_bandwidth / 2., n_taps,
                return_ratios=True)

            Wk = oscillation * tapers[m]
            if zero_mean:  # to make it zero mean
                real_offset = Wk.mean()
                Wk -= real_offset
            Wk /= sqrt(0.5) * linalg.norm(Wk.ravel())

            Wm.append(Wk)

        Ws.append(Wm)

    return Ws
Пример #33
0
def pmtm(x, dt, nw=3, cl=0.95):
    """Returns Thomson’s multitaper power spectral density (PSD) estimate, pxx, of the input signal, x.
    Slightly modified from Peter Huybers's matlab code, pmtmPH.m
    Parameters
    ----------
    x : numpy array
        Time series to analyze
    dt : float
        Time step
    nw : float
        The time-halfbandwidth product
    cl : float
        Confidence interval to calculate and display
    Returns
    -------
    P : numpy array
        PSD estimate
    s : numpy array
        Associated frequencies
    ci : numpy array
        Associated confidence interval
    """
    from scipy.signal import windows

    nfft = np.shape(x)[0]

    nx = np.shape(x)[0]
    k = min(np.round(2. * nw), nx)
    k = int(max(k - 1, 1))
    s = np.arange(0, 1 / dt, 1 / (nfft * dt))

    # Compute the discrete prolate spheroidal sequences
    [E, V] = windows.dpss(nx, nw, k, return_ratios=True)
    E = E.T

    # Compute the windowed DFTs.
    Pk = np.abs(np.fft.fft(E * x[:, np.newaxis], nfft, axis=0))**2

    if k > 1:
        sig2 = np.dot(x[np.newaxis, :], x[:, np.newaxis])[0][0] / nx
        # initial spectrum estimate
        P = ((Pk[:, 0] + Pk[:, 1]) / 2)[:, np.newaxis]
        Ptemp = np.zeros((nfft, 1))
        P1 = np.zeros((nfft, 1))
        tol = .0005 * sig2 / nfft
        a = sig2 * (1 - V)

        while (np.sum(np.abs(P - P1) / nfft) > tol):
            b = np.repeat(P, k, axis=-1) / (P * V[np.newaxis, :] + np.ones(
                (nfft, 1)) * a[np.newaxis, :])
            wk = (b**2) * (np.ones((nfft, 1)) * V[np.newaxis, :])
            P1 = (np.sum(wk * Pk, axis=-1) / np.sum(wk, axis=-1))[:,
                                                                  np.newaxis]

            Ptemp = np.empty_like(P1)
            Ptemp[:] = P1
            P1 = np.empty_like(P)
            P1[:] = P
            P = np.empty_like(Ptemp)
            P[:] = Ptemp

        # Determine equivalent degrees of freedom, see Percival and Walden 1993.
        v = ((2 * np.sum(
            (b**2) * (np.ones((nfft, 1)) * V[np.newaxis, :]), axis=-1)**2) /
             np.sum(
                 (b**4) * (np.ones((nfft, 1)) * V[np.newaxis, :]**2), axis=-1))

    else:
        P = np.empty_like(Pk)
        P[:] = Pk
        v = 2 * np.ones((nfft, 1))

    select = (np.arange(0, (nfft + 1) / 2.)).astype('int')
    P = P[select].flatten()
    s = s[select].flatten()
    v = v[select].flatten()

    # Chi-squared 95% confidence interval
    # approximation from Chamber's et al 1983; see Percival and Walden p.256, 1993
    ci = np.empty((np.shape(v)[0], 2))
    ci[:, 0] = 1. / (1 - 2 / (9 * v) - 1.96 * np.sqrt(2 / (9 * v)))**3
    ci[:, 1] = 1. / (1 - 2 / (9 * v) + 1.96 * np.sqrt(2 / (9 * v)))**3

    return P, s, ci
Пример #34
0
def pmtm(data, NW = 4, Fs = None, NFFT = None, kind = 'chronux'):
    '''
    Compute the power spectrum via Multitapering.
    If the number of tapers == 1, it is a stft (short-time fourier transform)
    
    Parameters
    ----------
    data : np.ndarray, shape (n_samples, n_channels)
        Input data vector.
        
    NW : int / float, optional
        Time Half-Bandwidth Product. The default is 4.
        
    Fs : int / float, optional
        Sampling frequency. The default is 2*np.pi.
        
    NFFT : int, optional
        Length of the signal for the FFT analisys. The default value is
        max(256, 2**nextpow2(n_samples)).
        
    kind : str, optional
        Type of computation. It can be "milekovic" or "chronux".
        The default value is chronux.

    Returns
    -------
    Sk : np.ndarray, shape (n_windows, n_channels)
        Power spectrum computed via MTM.

    '''
    
    if kind not in ['milekovic','chronux']:
        raise Exception('ERROR: kinds can only be "milekovic" or "chronux". You inputed "{}"!'.format(kind))
        
    # Number of channels
    if data.ndim == 1:
        data = np.expand_dims(data, axis=1)
    else:
        data = transpose(data, 'column')
    
    # Data length
    N = data.shape[0]
    n_channels = data.shape[1]
    
    if Fs == None:
        Fs = 2*np.pi
    
    # set the NFFT
    if NFFT==None:
        NFFT = max(256, 2**nextpow2(N))
    
    w = pmtm_params(Fs, NFFT)
    
    # Compute tapers
    if kind in ['chronux']:
        if NW == 1:
            tapers = np.expand_dims(np.hamming(N),1) * np.sqrt(Fs)
        else:
            tapers = dpss(N, NW, Kmax=2*NW-1) * np.sqrt(Fs)
    elif kind in ['milekovic']:
        if NW == 1:
            tapers = np.expand_dims(np.hamming(N)/np.linalg.norm(np.hamming(N)),1)
        else:
            tapers = dpss(N, NW, Kmax=2*NW-1)
    tapers = transpose(tapers,'column')
    n_tapers = tapers.shape[1]
    
    # Add channel indices to tapers
    tapers = np.tile(np.expand_dims(tapers,2),(1,1,n_channels))
    # Add taper indices to data
    data = np.tile(np.expand_dims(data,1),(1,n_tapers,1))
    
    data_proj = data*tapers
    
    if kind in ['chronux']:
        Sk_complex = (np.fft.fft(data_proj.T, NFFT)/Fs).T
    elif kind in ['milekovic']:
        Sk_complex = (np.fft.fft(data_proj.T, NFFT)).T
    
    # Sk = np.mean(abs(Sk_complex), axis = 1)
    
    # Sk = np.empty((NFFT, n_channels))
    # Sk[:] = np.NaN
    
    # for channel in range(n_channels):
    #     # Compute the FFT
    #     Sk_complex = np.fft.fft(np.multiply(tapers.transpose(), data[:,channel]), NFFT)/Fs
    #     # Compute the whole power spectrum [Power]
    #     # Sk[:,channel] = np.mean(abs(Sk_complex)**2, axis = 0)
    #     Sk[:,channel] = np.mean(abs(Sk_complex), axis = 0)

    return Sk_complex, w, NFFT