├── Cohen2008_xfreq.pdf ├── README.md └── cohen_xfreqMeth_script.m /Cohen2008_xfreq.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikexcohen/transientCFC/main/Cohen2008_xfreq.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # transientCFC 2 | Assessing transient cross-frequency coupling 3 | 4 | This is the code accompanying the aforementioned paper. 5 | 6 | https://www.sciencedirect.com/science/article/abs/pii/S0165027007005237?via%3Dihub 7 | -------------------------------------------------------------------------------- /cohen_xfreqMeth_script.m: -------------------------------------------------------------------------------- 1 | % Code for analyzing transient cross-frequency coupling EEG data. 2 | % Note that you must load in the data yourself. The script assumes you have 3 | % one channel of data in a vector (called 'data'). Note that this script 4 | % relies on functions from two toolboxes: (1) 'eegfilt' from the EEGLAB 5 | % toolbox (free to download); (2) Matlab's filter toolbox. It's possible to 6 | % do your own filtering, but make sure you use a good one with zero 7 | % phase-shift. 8 | % 9 | % Feel free to email Mike Cohen (mikexcohen@gmail.com) with any questions. 10 | % If you use this script or these methods, please cite the following 11 | % article: Cohen, MX (2008) Assessing transient cross-frequency coupling in 12 | % EEG data. J Neurosci Methods. March 15; 168(2):494-9. PubMed ID: 18061683 13 | 14 | 15 | 16 | %% -- initializations -- %% 17 | % list frequencies in Hz 18 | freqs=20:4:150; 19 | 20 | % time decimation (in samples, not time units) 21 | decfactor=10; 22 | 23 | % sampling rate in Hz 24 | srate=1000; 25 | 26 | % size of time window for analysis. I used 400 ms, but see the paper for 27 | % a discussion of how to choose this time window 28 | analwindow=400; 29 | 30 | % initialize phase coherence and other matrices 31 | pc=zeros(length(freqs),length(data)/decfactor); 32 | fluxfreq=pc; 33 | fluxfreqPos=1; fs=9999; 34 | clear i 35 | 36 | 37 | %% analyze data... loop through frequencies and then through time. 38 | % Note that it might be a good idea to break up the time series into small 39 | % chunks of a few (I used 4) seconds before running this loop. 40 | for fi=1:length(freqs) 41 | 42 | % get upper freq power time series 43 | upperfreq=abs(hilbert(eegfilt(data,srate,freqs(fi)-2.5,freqs(fi)+2.5))).^2; 44 | 45 | p=1; 46 | % loop through time 47 | for tx=1:decfactor:length(data) 48 | 49 | % get a little bit of data... 50 | tempTS=upperfreq(tx:tx+analwindow); 51 | last=fs(fluxfreqPos); % remember the last fluxfrequency 52 | 53 | % first, find max frequency component of upper powerTS 54 | powTSfft=abs(fft(tempTS)); powTSfft=powTSfft(1:round(length(powTSfft)/2)); 55 | fs=linspace(0,srate/2,length(powTSfft)); 56 | nyquist=srate/(analwindow/2); % nyquist of small snippet 57 | [junk,fluxfreqPos]=max(powTSfft(find(fs>nyquist & fs<40))); 58 | fs=fs(find(fs>nyquist & fs<40)); 59 | fluxfreq(fi,p)=squeeze(fluxfreq(fi,p)) + fs(fluxfreqPos); 60 | 61 | % get phase times series of flux... timesaver if same as last 62 | if fs(fluxfreqPos)~=last 63 | fluxphaseall=angle(hilbert(eegfilt(data,srate,fs(fluxfreqPos)-1.5,fs(fluxfreqPos)+1.5))); 64 | end 65 | fluxphase=fluxphaseall(tx:tx+analwindow); 66 | 67 | 68 | % calculate PhaseCoherence 69 | powerTSphase=angle(hilbert(zscore(tempTS)))'; 70 | pc(fi,p)=squeeze(pc(fi,p)) + mean( exp(i*(powerTSphase-fluxphase)) ); 71 | 72 | 73 | % bootstrap for significance at each point 74 | f=fft(tempTS); 75 | for b=1:200 % 200 iterations 76 | 77 | % there are several methods for bootstrapping. Three 78 | % alternatives are presented here, but others could be 79 | % acceptable as well. Make sure two of the three methods are 80 | % commented out, otherwise you'll run all of them! 81 | 82 | % Method 1: create surrogate dataset by shuffling phases while 83 | % preserving power structure. 84 | A=abs(f); 85 | zphs=cos(angle(f))+i*sin(angle(f)); 86 | phasec=angle(hilbert(real(ifft(A.*zphs(randperm(length(zphs))))))); 87 | 88 | 89 | % Method 2: break up phase time series once and reorder 90 | stime=randperm(length(powerTSphase)-50); 91 | stime=stime(1)+25; 92 | phasec=[ powerTSphase(stime:end) powerTSphase(1:stime-1) ]; 93 | 94 | 95 | % Method 3: Randomize phase time series (fastest method, and 96 | % perhaps the best null hypothesis) 97 | phasec=powerTSphase(randperm(length(powerTSphase))); 98 | 99 | 100 | % compute boot-strapped PC 101 | bpc(b)=abs(mean(exp(i*(phasec-fluxphase)))); 102 | end 103 | 104 | % p-value is the percent of bootstrapped values larger than the 105 | % observed phase coherence 106 | pvals(fi,p)=length(find(abs(pc(fi,p))