Ejemplo n.º 1
0
def phase_plane_animation(session,tr,areas,fa=10,fb=45,epoch=None,\
    skip=1,saveas=None,hook=None,FPS=30,stabilize=True,extension='.pdf',markersize=1.5,figtitle=None):
    '''
    phase_plane_animation(session,tr)
    '''
    warn('Also plots "bad" channels')
    areacolors = [OCHRE,AZURE,RUST]
    print session, tr
    # save current figure so we can return to it
    ff=gcf()
    ax=gca()
    # get time base
    times = get_trial_times_ms(session,'M1',tr,epoch)[::skip]
    # retrieve filtered array data
    data = {}
    for a in areas:
        print 'loading area',a 
        x = get_all_analytic_lfp(session,a,tr,epoch,fa,fb,onlygood=True)[:,::skip]
        data[a]=x.T
    # compute phase velocities for stabilization
    alldata = concatenate(data.values(),1)
    phasedt = rewrap(diff(angle(alldata),1,0))
    phasev  = median(phasedt,axis=1)
    phaseshift = append(0,cumsum(phasev))
    # compute stabilization differently, using median phase
    phaseshift = angle(mean(alldata,axis=1))
    # PREPARE FIGURE
    if figtitle==None:
        figtitle = 'Analytic Signal %s-%sHz\n%s trial %s'%(fa,fb,session,tr)
    if not saveas is None:
        saveas += '_%s_%s_%s_%s'%(session,tr,fa,fb)
    figure('Phase Plane')
    a2 = cla()
    M = 10
    for a in areas:
        M = max(M,int(ceil(np.max(abs(data[a]))/10.))*10)
    complex_axis(M)
    title(figtitle+' t=%dms'%times[0])
    # prepare output directory if we're going to save this    
    if not saveas is None:
        savedir = './'+saveas
        ensuredir(savedir)
    # initialize points
    scat={}
    for i,a in en(areas):
        scat[a] = scatter(*c2p(data[a][0]),s=markersize**2,color=areacolors[i],label=a)
    nice_legend()
    # perform animation
    st = now()
    for i,t in en|times:
        stabilizer = exp(-1j*phaseshift[i]) if stabilize else 1
        for a in areas:
            scat[a].set_offsets(c2p(stabilizer*data[a][i]).T)
        title(figtitle+' t=%sms'%t)
        draw()
        if not saveas is None:
            savefig(savedir+'/'+saveas+'_%s.%s'%(t,extension))
        if not hook is None: hook(t)
        st=waitfor(st+1000/FPS)
    if not ff is None: figure(ff.number)
Ejemplo n.º 2
0
def array_kuramoto_pgd_standard_deviation(frame):
    '''
    A related directionality index ignores vector amplitude.
    '''
    warn('expects first two dimensions x,y of 2d array data')
    pg = array_phase_gradient(frame)
    return np.abs(np.mean(pg/np.abs(pg),axis=(0,1)))
Ejemplo n.º 3
0
def array_synchrony_pgd(frame):
    '''
    The phase gradient directionality measure from Rubinto et al 2009 is
    abs(mean(pg))/mean(abs(pg))
    '''
    warn('expects first two dimensions x,y of 2d array data')
    pg = array_phase_gradient(frame)
    return np.abs(np.mean(pg,axis=(0,1)))/np.mean(np.abs(pg),axis=(0,1))
Ejemplo n.º 4
0
def array_synchrony_pgd_standard_deviation(frame):
    '''
    The phase gradient directionality measure from Rubinto et al 2009 is
    abs(mean(pg))/mean(abs(pg))
    '''
    warn('expects first two dimensions x,y of 2d array data')
    R = array_synchrony_pgd(frame)
    return np.sqrt(-2*np.log(R))
Ejemplo n.º 5
0
def population_synchrony(population):
    '''
    Averages over all but the last dimension of the data
    '''
    warn('first dimension is channels')
    dimension = len(population.shape)
    averageover = tuple(range(dimension-1))
    return np.abs(np.mean(population,axis=averageover))/np.mean(np.abs(population),axis=averageover)
Ejemplo n.º 6
0
def array_phasegradient_upper(frame):
    '''
    The average gradient magnitude can be inflated if there is noise
    but provides an upper bound on spatial frequency ( lower bound on
    wavelength ).
    '''
    warn('expects first two dimensions x,y of 2d array data')
    pg = array_phase_gradient(frame)
    return np.mean(np.abs(pg),axis=(0,1))/(ELECTRODE_SPACING*2*pi)
Ejemplo n.º 7
0
def array_speed_lower(frame):
    '''expects first two dimensions x,y of 2d array data
    returns speed for plane waves in mm/s
    '''
    pg = array_phasegradient_upper(frame) #cycles / mm
    df = np.median(np.ravel(rewrap(np.diff(np.angle(frame),1,2)))) #radians/sample
    warn('ASSUMING FS=1000ms HERE!!!')
    f  = df*1000.0 # radians / s
    g  = f /(2*pi) # cycles / s
    return g/pg # mm /s
Ejemplo n.º 8
0
def fftppc_multitaper(snippits,Fs=1000,k=4):
    # some precision trouble
    # use quad precition
    # PPC doesn't care about scale so also rescale?
    #snippits = array(snippits,dtype=__PPC_FP_TYPE__)
    M,window = shape(snippits)
    if M<=window: warn('WARNING SAMPLES SEEM TRANSPOSED?')
    ff,raw,phase = fftppc_biased_multitaper(snippits,Fs,k)
    unbiased = (raw*k*M-1)/(M-1)
    return ff, unbiased, phase
Ejemplo n.º 9
0
def array_wavelength_pgd_threshold(frame,thresh=0.5):
    '''
    The magnitude of the average gradient provides a very accurate estimate
    of wavelength even in the presence of noise. However, it will
    understimate the phase gradient if the wave structure is not perfectly
    planar

    returns mm/cycle
    '''
    warn('expects first two dimensions x,y of 2d array data')
    return 1/array_phasegradient_pgd_threshold(frame,thresh)
Ejemplo n.º 10
0
def array_wavelength_upper(frame):
    '''
    phase gradients are in units of radians per electrode
    we would like units of mm per cycle
    there are 2pi radians per cycle
    there are 0.4mm per electrode
    phase gradient / 2 pi is in units of cycles per electrode
    electrode spacing / (phase gradient / 2 pi)
    '''
    warn('this code will break if ELECTRODE_SPACING changes or is inconsistant across datasets')
    warn('using something other than mean may make this less sensitive to outliers and noise')
    return 1/array_phasegradient_lower(frame)
Ejemplo n.º 11
0
def array_phasegradient_lower(frame):
    '''
    The magnitude of the average gradient provides a very accurate estimate
    of wavelength even in the presence of noise. However, it will
    understimate the phase gradient if the wave structure is not perfectly
    planar

    Returns cycles/mm
    i.e.
    radians/electrode / (mm/electrode) / (2*pi radians/cycle)
    '''
    warn('expects first two dimensions x,y of 2d array data')
    pg = array_phase_gradient(frame)
    return np.abs(np.mean(pg,axis=(0,1)))/(ELECTRODE_SPACING*2*pi)
Ejemplo n.º 12
0
def array_wavelength_lower_pgd_threshold(frame,thresh=0.5):
    '''
    The average phase gradient magnitude can tolerate non-planar waves, but
    is particularly sensitive to noise. It may be appropriate to combine
    this method with spatial smoothing to denoise the data, if it is safe
    to assume a minimum spatial scale for the underlying wave dynamics.

    returns mm/cycle
    '''
    warn('expects first two dimensions x,y of 2d array data')
    pg  = array_phase_gradient(frame)
    use = array_synchrony_pgd(frame)>=thresh
    pg[:,:,~use] = np.NaN
    return 1/np.mean(abs(pg),axis=(0,1))/(ELECTRODE_SPACING*2*pi)
Ejemplo n.º 13
0
def fftppc_biased(snippits,Fs=1000,taper=None):
    # some precision trouble
    # use quad precition
    # PPC doesn't care about scale so also rescale?
    snippits = array(snippits,dtype=__PPC_FP_TYPE__)
    snippits = snippits/std(snippits)
    M,window = shape(snippits)
    if not taper is None:
        snippits = snippits*taper;
    if M<=window: warn('WARNING SAMPLES SEEM TRANSPOSED?')
    fs       = fft(snippits)
    average  = mean(fs/abs(fs),0)
    raw      = abs(average)**2
    phases   = angle(average)
    freqs    = fftfreq(window,1./Fs)
    return freqs[:(window+1)/2], raw[:(window+1)/2], phases[:(window+1)/2]
Ejemplo n.º 14
0
def pairwise_phase_consistancy(signal,times,window=50,Fs=1000,k=4,multitaper=True,biased=False,delta=100,taper=None):
    '''
    signal: 1D real valued signal
    times:  Times of events relative to signal
    window: Time around event to examine
    Fs:     sample rate for computing freqs
    k:      number of tapers
    Also accepts lists of signals / times
    returns (freqs, ppc, phase), lfp_segments

    '''
    if multitaper:
        print("Warning: multitaper can introduce a bias into PPC that depends on the number of tapers!")
        print("For a fixed number of tapers, the bias is constant, but be careful")

    if not taper is None and multitaper:
        print("A windowing taper was specified, but multitaper mode was also selected? The taper argument is for providing a windowing function when not using multitaper estimation")
        assert 0
    if type(taper) is types.FunctionType:
        taper = taper(window*2+1)
    if biased: warn('skipping bias correction entirely')
    assert window>0
    if len(shape(signal))==1:
        usetimes = discard_spikes_closer_than_delta(signal,times,delta)
        snippits = array([nodc(signal[t-window:t+window+1]) for t in usetimes])
    elif len(shape(signal))==2:
        warn('assuming first dimension is trials / repititions')
        signals,alltimes = signal,times
        snippits = []
        for signal,times in zip(signals,alltimes):
            N = len(signal)
            times = array(times)
            times = times[times>=window]
            times = times[times<N-window]
            t_o = -inf
            for t in times:
                if t-t_o>delta:
                    t_o = t
                    snippits.append(nodc(signal[t-window:t+window+1]))
    else: assert 0
    if biased:
        if multitaper: return fftppc_biased_multitaper(snippits,Fs,k),snippits
        else:          return fftppc_biased(snippits,Fs,taper=taper),snippits
    else:
        if multitaper: return fftppc_multitaper(snippits,Fs,k),snippits
        else:          return fftppc(snippits,Fs,taper=taper),snippits
    assert 0
Ejemplo n.º 15
0
def phase_randomized_bias_correction(signal,times,window=50,Fs=1000,nrand=100):
    '''
    Estimates degrees of freedom using phase randomization.
    experimental.

    algebra could be dramaticalyl simplified, but keeping all explicit
    for clarity for now
    '''
    warn('AS FAR AS WE KNOW THIS DOESNT REALLY WORK')
    ff,bias = estimate_bias_in_uncorrected_ppc(signal,times,window,Fs,nrand)
    K = 1.0-bias
    M = K/(1-K)
    print('estimated degrees of freedom:',M)
    print('nominal degrees of freedom=',len(times))
    ff,raw = uncorrectedppc(signal,times,window,Fs)
    unbiased = (raw*M-1)/(M-1)
    return ff, unbiased
Ejemplo n.º 16
0
def fftppc_biased_multitaper(snippits,Fs=1000,k=4):
    # some precision trouble
    # use quad precition
    # PPC doesn't care about scale so also rescale?
    #nippits = array(snippits,dtype=__PPC_FP_TYPE__)
    #snippits = snippits/std(snippits)
    M,window = shape(snippits)
    print(M,window)
    if M<=window: warn('WARNING SAMPLES SEEM TRANSPOSED?')
    #print('BROKE FOR MATLAB CHECK REMOVE +1 on K KEEP ALL TAPERS')
    #tapers   = dpss(window,NW=0.499*(k+1),k=(k+1))[0][:,:-1]
    tapers   = dpss(window,NW=0.499*k,k=k)[0]
    results  = []
    unit  = lambda x:x/abs(x)
    average = [mean(unit(fft(snippits*taper)),0) for taper in tapers.T]
    raw     = mean([abs(x)**2 for x in average],0)
    phases  = angle(mean([exp(2j*pi*angle(x)) for x in average],0))
    freqs = fftfreq(window,1./Fs)
    return freqs[:(window+1)/2], raw[:(window+1)/2], phases[:(window+1)/2]
Ejemplo n.º 17
0
def pack_array_data(data,arrayMap):
    '''
    Accepts a collection of signals from array channels, as well as
    an array map containing indecies (1-indexed for backwards compatibility
    with matlab) into that list of channel data.

    This will interpolate missing channels as an average of nearest
    neighbors.

    :param data: NChannel x Ntimes array
    :param arrayMap: array map, 1-indexed, 0 for missing electrodes
    :return: returns LxKxNtimes 3D array of the interpolated channel data
    '''
    # first, trim off any empty rows or columns from the arrayMap
    arrayMap = trim_array(arrayMap)
    # prepare array into which to pack data
    L,K    = arrayMap.shape
    NCH,N  = data.shape
    packed = np.zeros((L,K,N),dtype=data.dtype)
    J = data.shape[0]
    M = np.sum(arrayMap>0)
    if J!=M:
        warn('bad: data dimension differs from number of array electrodes')
        warn('data %s %s array'%(J,M))
        warn('this may just be because some array channels are removed')
    for i,row in enumerate(arrayMap):
        for j,ch in enumerate(row):
            # need to convert channel to channel index
            if ch<=0:
                # we will need to interpolate from nearest neighbors
                ip = []
                if i>0  : ip.append(arrayMap[i-1,j])
                if j>0  : ip.append(arrayMap[i,j-1])
                if i+1<L: ip.append(arrayMap[i+1,j])
                if j+1<K: ip.append(arrayMap[i,j+1])
                ip = [ch for ch in ip if ch>0]
                assert len(ip)>0
                for chii in ip:
                    packed[i,j,:] += data[chii-1,:]
                packed[i,j,:] *= 1.0/len(ip)
            else:
                assert ch>0
                packed[i,j,:] = data[ch-1,:]
    return packed
Ejemplo n.º 18
0
def phase_plane_animation_arraygrid(session,tr,fa=10,fb=45,\
    epoch=None,skip=1,saveas=None,hook=None,FPS=30,stabilize=True,markersize=1.5):
    '''
    phase_plane_animation(session,tr)
    '''
    warn('Also plots "bad" channels')
    print session, tr
    # save current figure so we can return to it
    ff=gcf()
    ax=gca()
    # get time base
    times = get_trial_times_ms(session,'M1',tr,epoch)[::skip]
    # retrieve filtered array data
    data = {}
    for a in areas:
        print 'loading area',a 
        x = get_all_analytic_lfp(session,a,tr,epoch,fa,fb,onlygood=True)[:,::skip]
        data[a]=x.T
    # locate all pairs
    pairs = {}
    for a in areas:
        pairs[a] = get_all_pairs_ordered_as_channel_indecies(session,a)
    # compute phase velocities for stabilization
    alldata = concatenate(data.values(),1)
    phasedt = rewrap(diff(angle(alldata),1,0))
    phasev  = median(phasedt,axis=1)
    phaseshift = append(0,cumsum(phasev))
    # compute stabilization differently, using median phase
    #phaseshift = angle(mean(alldata,axis=1))
    # PREPARE FIGURE
    figtitle = 'Analytic Signal %s-%sHz\n%s trial %s'%(fa,fb,session,tr)
    if not saveas is None:
        saveas += '_%s_%s_%s_%s'%(session,tr,fa,fb)
    figure('Phase Plane')
    a2 = cla()
    # DETERMINE NICE SQUARE AXIS BOUNDS
    M = 10
    for a in areas:
        M = max(M,int(ceil(np.max(abs(data[a]))/10.))*10)
    complex_axis(M)
    title(figtitle+' t=%dms'%times[0])
    # prepare output directory if we're going to save this    
    if not saveas is None:
        savedir = './'+saveas
        ensuredir(savedir)
    # prepare stuff for blitting
    aa = gca()
    canvas = aa.figure.canvas
    background = canvas.copy_from_bbox(aa.bbox)
    def updateline(time):
        print '!!! t=',time
        canvas.restore_region(background)
        aa.draw_artist(line)
        aa.figure.canvas.blit(ax.bbox)
    # initialize points
    scat={}
    grid={}
    for i,a in en(areas):
        points = c2p(data[a][0])
        c = darkhues(9)[i*3+2]
        scat[a] = scatter(*points,s=markersize**2,color=c,label=a)
        lines = []
        for ix1,ix2 in pairs[a]:
            p1=points[:,ix1]
            p2=points[:,ix2]
            line = plot([p1[0],p2[0]],[p1[1],p2[1]],color=c,lw=0.4)[0]
            lines.append((line,ix1,ix2))
        grid[a]=lines
    nice_legend()
    # perform animation
    st = now()
    for i,t in en|times:
        stabilizer = exp(-1j*phaseshift[i]) if stabilize else 1
        # update via blitting instead of draw
        canvas.restore_region(background)
        for a in areas:
            points = c2p(stabilizer*data[a][i])
            scat[a].set_offsets(points.T)
            for line,ix1,ix2 in grid[a]:
                p1=points[:,ix1]
                p2=points[:,ix2]
                line.set_data([p1[0],p2[0]],[p1[1],p2[1]])
                aa.draw_artist(line)
        title(figtitle+' t=%sms'%t)
        # update via blitting instead of draw
        aa.figure.canvas.blit(ax.bbox)
        # draw()
        if not saveas is None:
            savefig(savedir+'/'+saveas+'_%s.png'%t)
        if not hook is None: hook(t)
        st=waitfor(st+1000/FPS)
    if not ff is None: figure(ff.number)
Ejemplo n.º 19
0
def ppc_phase_randomize_chance_level_sample(
    signal,times,window=50,Fs=1000,k=4,multitaper=True,
    biased=False,delta=100,taper=None):
    '''
    signal: 1D real valued signal
    times:  Times of events relative to signal
    window: Time around event to examine
    Fs:     sample rate for computing freqs
    k:      number of tapers
    Also accepts lists of signals / times

    Uses phase randomization to sample from the null hypothesis distribution.
    Returns the actual PPC samples rather than any summary statistics.
    You can do what you want with the distribution returned.
    '''
    if multitaper:
        print("Warning: multitaper can introduce a bias into PPC that depends on the number of tapers!")
        print("For a fixed number of tapers, the bias is constant, but be careful")

    if not taper is None and multitaper:
        print("A windowing taper was specified, but multitaper mode was also selected.")
        print("The taper argument is for providing a windowing function when not using multitaper estimation.")
        assert 0
    if type(taper) is types.FunctionType:
        taper = taper(window*2+1)
    if biased: warn('skipping bias correction entirely')
    assert window>0

    # need to compute PPC from phase randomized samples
    # We can't phase randomize the snippits because there may be some
    # correlation between them, we have to randomize the underlying LFP

    if len(shape(signal))==1:
        # only a single trial provided
        usetimes = discard_spikes_closer_than_delta(signal,times,delta)
        signal = phase_randomize(signal)
        snippits = array([nodc(signal[t-window:t+window+1]) for t in usetimes])
    elif len(shape(signal))==2:
        warn('assuming first dimension is trials / repititions')
        signals,alltimes = signal,times
        snippits = []
        for signal,times in zip(signals,alltimes):
            signal = phase_randomize(signal)
            N = len(signal)
            times = array(times)
            times = times[times>=window]
            times = times[times<N-window]
            t_o = -inf
            for t in times:
                if t-t_o>delta:
                    t_o = t
                    snippits.append(nodc(signal[t-window:t+window+1]))
    else: assert 0

    if biased:
        if multitaper: return fftppc_biased_multitaper(snippits,Fs,k),snippits
        else:          return fftppc_biased(snippits,Fs,taper=taper),snippits
    else:
        if multitaper: return fftppc_multitaper(snippits,Fs,k),snippits
        else:          return fftppc(snippits,Fs,taper=taper),snippits
    assert 0
Ejemplo n.º 20
0
def array_synchrony_standard_deviation(frames):
    warn('using this with interpolated channels will inflate synchrony')
    warn('this assumes first 2 dimensions are array axis')
    R = array_synchrony(frames)
    return np.sqrt(-2*np.log(R))
Ejemplo n.º 21
0
def array_synchrony(frames):
    warn('using this with interpolated channels will inflate synchrony')
    warn('this assumes first 2 dimensions are array axis')
    return np.abs(np.mean(frames,axis=(0,1)))/np.mean(np.abs(frames),axis=(0,1))
Ejemplo n.º 22
0
def array_average_amplitude(frame):
    warn('using this with interpolated channels will bias amplitude')
    warn('this assumes first 2 dimensions are array axis')
    return np.mean(np.abs(frame),axis=(0,1))