Exemple #1
0
def calcPhasePow(freqs,dat,samplerate,axis=-1,width=5,verbose=False,to_return='both'):
    """Calculate phase and power over time with a Morlet wavelet.

    You can optionally pass in downsample, which is the samplerate to
    decimate to following the power/phase calculation. 

    As always, it is best to pass in extra signal (a buffer) on either
    side of the signal of interest because power calculations and
    decimation have edge effects."""

    if to_return != 'both' and to_return != 'pow' and to_return != 'phase':
        raise ValueError("to_return must be \'pow\', \'phase\', or \'both\' to specify whether power, phase, or both are returned. Invalid value: %s " % to_return)
    
    # reshape the data to 2D with time on the 2nd dimension
    origshape = dat.shape
    eegdat = reshapeTo2D(dat,axis)

    # allocate
    phaseAll = []
    powerAll = []

    # loop over freqs
    freqs = N.asarray(freqs)
    if len(freqs.shape)==0:
	freqs = N.array([freqs])
    if verbose:
	sys.stdout.write('Calculating wavelet phase/power...\n')
	sys.stdout.write('Freqs (%g to %g): ' % (N.min(freqs),N.max(freqs)))
    for f,freq in enumerate(freqs):
	if verbose:
	    sys.stdout.write('%g ' % (freq))
	    sys.stdout.flush()
	# get the phase and power for that freq
	phase,power = phasePow2d(freq,eegdat,samplerate,width)
        
        # reshape back do original data shape
	if to_return == 'phase' or to_return == 'both':
	    phase = reshapeFrom2D(phase,axis,origshape)
	if to_return == 'pow' or to_return == 'both':
	    power = reshapeFrom2D(power,axis,origshape)

	# see if allocate
	if len(phaseAll) == 0 and len(powerAll) == 0:
	    if to_return == 'phase' or to_return == 'both':
		phaseAll = N.empty(N.concatenate(([len(freqs)],phase.shape)),
				   dtype=phase.dtype)
	    if to_return == 'pow' or to_return == 'both':
		powerAll = N.empty(N.concatenate(([len(freqs)],power.shape)),
				   dtype=power.dtype)
        # insert into all
	if to_return == 'phase' or to_return == 'both':
	    phaseAll[f] = phase
	if to_return == 'pow' or to_return == 'both':
	    powerAll[f] = power

    if verbose:
	sys.stdout.write('\n')

    if to_return == 'pow':
        return powerAll
    elif to_return == 'phase':
        return phaseAll
    elif to_return == 'both':
        return phaseAll,powerAll
Exemple #2
0
def phase_pow_multi2(freqs, dat, samplerate, widths=5, to_return='both',
                    time_axis=-1, freq_axis=0, **kwargs):
    """
    Calculate phase and power with wavelets across multiple events.

    Calls the morlet_multi() and fconv_multi() functions to convolve
    dat with Morlet wavelets.  Phase and power over time across all
    events are calculated from the results. Time/samples should
    include a buffer before onsets and after offsets of the events of
    interest to avoid edge effects.

    Parameters
    ----------
    freqs : {int, float, array_like of ints or floats}
        The frequencies of the Morlet wavelets.
    dat : {array_like}
        The data to determine the phase and power of. Time/samples must be
        last dimension and should include a buffer to avoid edge effects.
    samplerate : {float}
        The sample rate of the signal (e.g., 200 Hz).
    widths : {int, float, array_like of ints or floats}
        The width(s) of the wavelets in cycles. See docstring of
        morlet_multi() for details.
    to_return : {'both','power','phase'}, optional
        Specify whether to return power, phase, or both.
    time_axis : {int},optional
        Index of the time/samples dimension in dat.
        Should be in {-1,0,len(dat.shape)}
    freq_axis : {int},optional
        Index of the frequency dimension in the returned array(s).
        Should be in {0, time_axis, time_axis+1,len(dat.shape)}.
    **kwargs : {**kwargs},optional
        Additional key word arguments to be passed on to morlet_multi().
    
    Returns
    -------
    Array(s) of phase and/or power values as specified in to_return. The
    returned array(s) has/have one more dimension than dat. The added
    dimension is for the frequencies and is inserted at freq_axis.
    """
    if to_return != 'both' and to_return != 'power' and to_return != 'phase':
        raise ValueError("to_return must be \'power\', \'phase\', or \'both\' to "+
                         "specify whether power, phase, or both are to be "+
                         "returned. Invalid value: %s " % to_return)

    # generate array of wavelets:
    fft_wavelets,reg_wavelets,fft_ind = morlet_multi2(freqs,widths,samplerate,
                                                     **kwargs)
    # make sure we have at least as many data samples as wavelet samples
    if ((fft_wavelets.shape[1] > dat.shape[time_axis]) or
        ((len(reg_wavelets)>0) and
        (N.max([len(i) for i in reg_wavelets]) >  dat.shape[time_axis]))):
        raise ValueError("The number of data samples is insufficient compared "+
                         "to the number of wavelet samples. Try increasing "+
                         "data samples by using a (longer) buffer.\n data "+
                         "samples: "+str(dat.shape[time_axis])+"\nwavelet "+
                         "samples: "+str(fft_wavelets.shape[1]))
    
    # reshape the data to 2D with time on the 2nd dimension
    origshape = dat.shape
    eegdat = reshapeTo2D(dat,time_axis)

    # calculate wavelet coefficients:
    #wavCoef = N.empty((eegdat.shape[time_axis-1]*len(freqs),
    #                   eegdat.shape[time_axis]),dtype=N.complex128)
    wavCoef = N.empty((eegdat.shape[time_axis-1]*len(freqs),
                       eegdat.shape[time_axis]),dtype=N.complex)
    if fft_wavelets.shape[1] > 0:
        fconv_ind = N.repeat(fft_ind,eegdat.shape[time_axis-1])
        wavCoef[fconv_ind] = fconv_multi(fft_wavelets,eegdat,mode='same')

    #reg_wavCoef = N.empty((eegdat.shape[time_axis-1]*N.sum(~fft_ind),
    #                       eegdat.shape[time_axis]),dtype=N.complex128)
    reg_wavCoef = N.empty((eegdat.shape[time_axis-1]*N.sum(~fft_ind),
                           eegdat.shape[time_axis]),dtype=N.complex)
    conv_ind = N.repeat(~fft_ind,eegdat.shape[time_axis-1])
    i=0
    for reg in xrange(len(reg_wavelets)):
        for ev,evDat in enumerate(dat):
            #print len(reg_wavelets), reg
            reg_wavCoef[i] = N.convolve(reg_wavelets[reg],evDat,'same')
            i += 1
    wavCoef[conv_ind] = reg_wavCoef
    
    # Determine shape for ouput arrays with added frequency dimension:
    newshape = list(origshape)
    # freqs must be first for reshapeFrom2D to work
    # XXX
    newshape.insert(freq_axis,len(freqs))
    newshape = tuple(newshape)
    
    if to_return == 'power' or to_return == 'both':
        # calculate power:
        power = N.power(N.abs(wavCoef),2)
        # reshape to new shape:
        power = reshapeFrom2D(power,time_axis,newshape)

    if to_return == 'phase' or to_return == 'both':
        # normalize the phase estimates to length one taking care of
        # instances where they are zero:
        norm_factor = N.abs(wavCoef)
        ind = norm_factor == 0
        norm_factor[ind] = 1.
        wavCoef = wavCoef/norm_factor
        wavCoef[ind] = 0
        # calculate phase:
        phase = N.angle(wavCoef)
        # reshape to new shape
        phase = reshapeFrom2D(phase,time_axis,newshape)

    if to_return == 'power':
        return power
    elif to_return == 'phase':
        return phase
    elif to_return == 'both':
        return phase,power