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
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