def coherence(X, window=128, overlap=0.75, fmin=None, fmax=None, fs=None): """Compute coherence.""" n_chan = X.shape[0] overlap = int(overlap * window) ij = [] if fs is None: fs = window for i in range(n_chan): for j in range(i + 1, n_chan): ij.append((i, j)) Cxy, Phase, freqs = mlab.cohere_pairs(X.T, ij, NFFT=window, Fs=fs, noverlap=overlap) if fmin is None: fmin = freqs[0] if fmax is None: fmax = freqs[-1] index_f = (freqs >= fmin) & (freqs <= fmax) freqs = freqs[index_f] # reshape coherence coh = numpy.zeros((n_chan, n_chan, len(freqs))) for i in range(n_chan): coh[i, i] = 1 for j in range(i + 1, n_chan): coh[i, j] = coh[j, i] = Cxy[(i, j)][index_f] return coh
def coherence(X, nfft=256, fs=2, noverlap=0): """Compute coherence.""" n_chan = X.shape[0] ij = [] for i in range(n_chan): for j in range(i + 1, n_chan): ij.append((i, j)) Cxy, Phase, freqs = mlab.cohere_pairs(X, ij, NFFT=nfft, Fs=fs, noverlap=noverlap) coh = numpy.zeros((n_chan, n_chan, len(freqs))) for i in range(n_chan): coh[i, i] = 1 for j in range(i + 1, n_chan): coh[i, j] = coh[j, i] = Cxy[(i, j)] return coh
def calculate_coherence(signalArray, sampFq, tFrame=10, tSlide='None', tAxis='default', fqBands='default', PhaseRan=True, nRand=1): """ Calculates signal coherence between all electrode pairs, over defined frequency bands - signalArray: np.array, ecog signals array (n electrodes x t timepoints) - sampFq: float, sampling frequency - tFrame: int, time bin in seconds for calculating coherence - tSlide: int or 'None', sliding window for moving coherence time bin - tAxis: np.array or 'default', time axis corresponding to signalArray time points - fqBands: dict eg fqBands['alpha'] = (8, 13) or 'default' to use pre-defined bands (in electrodeinfo.fqBands) - PhaseRan: bool. Perform phase randomization if True - nRand: number of phase randomizations to perform """ nElectrodes = len(signalArray) if tSlide == 'None': tSlide = tFrame # Split up recording into time chuncks over which to calculate coherence tFrame = float(tFrame) tSlide = float(tSlide) # Select [:-1] in tAxis_split so that final time point has width >tFrame rather than <tFrame (cannot compute coherence if have too few time points) if tAxis == 'default': tDuration = np.floor(len(signalArray[0]) / float(sampFq)) tAxis = np.linspace(0, tDuration, len(signalArray[0])) tMax = tDuration - tFrame + tSlide tAxis_split = np.arange(0, tMax, tSlide)[:-1] tAxis_split_inds = tAxis_split[:-1] else: tDuration = np.floor(tAxis[-1] - tAxis[0]) tMax = tDuration - tFrame + tSlide tAxis_split = np.arange(tAxis[0], (tAxis[-1] - tFrame + tSlide), tSlide)[:-1] tAxis_split_inds = np.arange(0, tMax, tSlide)[:-1] nTimepoints = len(tAxis_split) print('Recording duration: %0.0f sec (%0.2f mins)' % (tDuration, (tDuration / 60.0))) print('Frame duration: %0.0f sec (%0.2f mins)' % (tFrame, (tFrame / 60.0))) print('Sliding window: %0.0f sec (%0.2f mins)' % (tSlide, (tSlide / 60.0))) print('Number of frames: %d\n' % (nTimepoints)) # Define frequency bands if fqBands == 'default': fqBands = electrodeinfo.fq_bands() bands = fqBands.keys() # Initialize output matrices: Coherence = collections.OrderedDict() Phase = collections.OrderedDict() for band in bands: Coherence[band] = np.zeros((nElectrodes, nElectrodes, nTimepoints)) for band in bands: Phase[band] = np.zeros((nElectrodes, nElectrodes, nTimepoints)) # Define pairs over which to calculate coherences (list of tuples) ijPairs = [] for i in range(nElectrodes): for j in range(i + 1, nElectrodes): ijPairs.append((i, j)) # Calculate coherence for those pairs # Loop through time index array: for nn, tt in enumerate(tAxis_split_inds[:-1]): if nn == 0: print('Loop ' + str(nn + 1) + ' out of ' + str(nTimepoints)) elif nn % 250 == 0 and nn >= 250: print('Loop ' + str(nn + 1) + ' out of ' + str(nTimepoints)) elif nn == (nTimepoints - 1): print('Loop ' + str(nn + 1) + ' out of ' + str(nTimepoints)) tStart = tt + tAxis[0] tEnd = tAxis_split_inds[nn + 1] + tAxis[0] ttInds = np.where((tAxis >= tStart) & (tAxis < tEnd))[0] # Only perform coherence calculation if have > 1 second of data if len(ttInds) > int(sampFq): if (ttInds[-1] + 1) <= len(tAxis): signalChunk = signalArray[0:nElectrodes, ttInds[0]:(ttInds[-1] + 1)] else: signalChunk = signalArray[0:nElectrodes, ttInds[0]:] signalChunk = np.float32(signalChunk) Cxy, phase, fqs = mlab.cohere_pairs(signalChunk.T, ijPairs, Fs=sampFq, NFFT=int(sampFq / 2)) # Create numpy array of keys and values: ijCxyKeys = np.array(Cxy.keys()) if PhaseRan == True: Coherence_surr = collections.OrderedDict( ) # Create the empty dictionary for X in bands: Coherence_surr[X] = np.zeros( (nElectrodes, nElectrodes, nTimepoints)) # Perform randomization several times (added: 25 July 2017) Cxy_surr_all = np.zeros( (np.array(Cxy.values()).shape[0], np.array(Cxy.values()).shape[1], nRand)) for nr in range(nRand): signalChunk_surr = phaseran(signalChunk.T) Cxy_surr, P0, F = mlab.cohere_pairs(signalChunk_surr.T, ijPairs, Fs=sampFq, NFFT=int(sampFq / 2)) Cxy_surr_all[:, :, nr] = np.array(Cxy_surr.values()) Cxy_surr_mean = np.mean(Cxy_surr_all, axis=-1) ijCxyValues = np.array(np.squeeze( Cxy.values())) - Cxy_surr_mean else: ijCxyValues = np.array(np.squeeze(Cxy.values())) ijphaseKeys = np.array(phase.keys()) ijphaseValues = np.array(np.squeeze(phase.values())) # Extract frequency indices and calculate mean coherence over those bands: Indices = collections.OrderedDict() for X in bands: Indices[X] = list( np.where((fqs >= fqBands[X][0]) & (fqs <= fqBands[X][1]))[0]) if len(np.shape(np.squeeze(ijCxyValues))) == 2: MeansCoh = {} MeansPhase = {} for X in bands: MeansCoh[X] = np.mean(np.squeeze(ijCxyValues)[:, Indices[X]], axis=1) MeansPhase[X] = np.mean( np.squeeze(ijphaseValues)[:, Indices[X]], axis=1) elif len(np.shape(np.squeeze(ijCxyValues))) == 3: MeansCoh = {} MeansPhase = {} for X in bands: MeansCoh[X] = np.mean(ijCxyValues[:, Indices[X]], axis=2) MeansPhase[X] = np.mean(ijphaseValues[:, Indices[X]], axis=2) # Fill coherence matrices: diagIndices = range(nElectrodes) for X in bands: # Set diagonals = 1 Coherence[X][diagIndices, diagIndices, nn] = 1 for pp, pair in enumerate(ijCxyKeys): Coherence[X][pair[0], pair[1], nn] = MeansCoh[X][pp] Coherence[X][pair[1], pair[0], nn] = MeansCoh[X][pp] # Fill phase matrices: diagIndices = range(nElectrodes) for X in bands: # Set diagonals = 1 Phase[X][diagIndices, diagIndices, nn] = 1 for pp, pair in enumerate(ijphaseKeys): Phase[X][pair[0], pair[1], nn] = MeansPhase[X][pp] Phase[X][pair[1], pair[0], nn] = MeansPhase[X][pp] # If no data for that timepoint: elif len(ttInds) == 0: # Fill coherence matrices: diagIndices = range(nElectrodes) for X in bands: # Set diagonals = 1 Coherence[X][diagIndices, diagIndices, nn] = np.nan for pp, pair in enumerate(ijCxyKeys): Coherence[X][pair[0], pair[1], nn] = np.nan Coherence[X][pair[1], pair[0], nn] = np.nan # Fill phase matrices: diagIndices = range(nElectrodes) for X in bands: # Set diagonals = 1 Phase[X][diagIndices, diagIndices, nn] = np.nan for pp, pair in enumerate(ijphaseKeys): Phase[X][pair[0], pair[1], nn] = np.nan Phase[X][pair[1], pair[0], nn] = np.nan # Remove Nans and infs: for X in bands: Coherence[X] = np.nan_to_num(Coherence[X]) Phase[X] = np.nan_to_num(Phase[X]) print('Done\n') return { 'Coherence': Coherence, 'Phase': Phase, 'deltaT': tFrame, 'tAxis': tAxis_split }