|
67 | 67 | % param.xFreqOption = boolean flag to perform cross-frequency analysis
|
68 | 68 | % param.xFreqBin = Frequency bin size for n x n PAC analysis (Default = 5 Hz)
|
69 | 69 | % param.xFreqLow = cell: low frequency band for x-freq (Theta, Alpha, Beta, SW)
|
| 70 | +% param.nShuffle = # shuffles to calculate Z-value for total PAC - does not due for nxn or time PAC, very computationally expensive. (default = 200) |
70 | 71 | % param.morlWidth = width/number of cycles of the morlet wavelet filter, default = 7
|
71 | 72 | % param.winLength = time binning for phase-amplitude analysis (s). Dictates min low freq (=1/winLength), so default = 0.5s results in min freq. of 2Hz
|
72 | 73 | % param.winOverlap = Amount to overlap time bins (default = 0.2s)
|
|
157 | 158 | if ~isfield(param,'xFreqBin'); param.xFreqBin = 5; end % [Hz]
|
158 | 159 | if ~isfield(param,'xFreqLow'); param.xFreqLow = 'Theta'; end
|
159 | 160 | if ~isfield(param,'morlWidth'); param.morlWidth = 7; end
|
| 161 | +if ~isfield(param,'nShuffle'); param.nShuffle = 200; end |
160 | 162 | if ~isfield(param,'winLength'); param.winLength = 0.5; end % [s]
|
161 | 163 | if ~isfield(param,'winOverlap'); param.winOverlap = 0.2; end % [s]
|
162 | 164 | if ~isfield(param,'importStimOption'); param.importStimOption = 0; end
|
|
853 | 855 |
|
854 | 856 |
|
855 | 857 | %% Cross-Frequency Phase-Amplitude Coupling (PAC)
|
| 858 | +% Adapted from Canolty et al 2006 and Onslow et al 2011 |
856 | 859 | if param.xFreqOption
|
857 |
| - % Below is an adaptation/simplification of code written by Author: Angela Onslow, May 2010 |
858 |
| - fprintf(['calculating phase-amplitude coupling for file ' dataFileName '... ']); |
859 |
| - |
860 |
| - %% Total PAC Analysis for n x n matrix: |
861 | 860 | % Assign a temp LFP tSeries (it will be trimmed later)
|
862 | 861 | tSeries = data.LFP.tSeries;
|
863 | 862 | nSample = length(data.LFP.tSeries);
|
864 |
| - nShuffle = 200; % Add to UI? |
865 | 863 |
|
| 864 | + %% Total PAC Analysis for n x n matrix: |
866 | 865 | if isfield(param, 'spectLim1') && isfield(param, 'spectLim2')
|
867 | 866 |
|
| 867 | + fprintf(['calculating n x n phase-amplitude coupling (file ' dataFileName ')... ']); |
| 868 | + |
868 | 869 | % Initialize data structures:
|
869 | 870 | if ~isfield(data.LFP,'xFreq'); data.LFP.xFreq = struct; end
|
870 | 871 |
|
|
876 | 877 | nFreq = length(data.LFP.xFreq.morlFreq);
|
877 | 878 |
|
878 | 879 | % Initialize phase, amplitude, and PAC arrays
|
879 |
| - data.LFP.xFreq.modPhase = zeros(nSample, nFreq); |
880 |
| - data.LFP.xFreq.pacAmp = zeros(nSample, nFreq); |
881 |
| - data.LFP.xFreq.pacMI = zeros(nFreq, nFreq); |
| 880 | + data.LFP.xFreq.phsPAC = zeros(nSample, nFreq); |
| 881 | + data.LFP.xFreq.ampPAC = zeros(nSample, nFreq); |
| 882 | + data.LFP.xFreq.pacMI = zeros(nFreq, nFreq); |
882 | 883 |
|
883 | 884 | % Determine phase and amplitude via Morlet wavelet:
|
884 | 885 | for i = 1 : nFreq
|
885 |
| - data.LFP.xFreq.modPhase(:, i) = morletPhase(data.LFP.xFreq.morlFreq(i), tSeries, param.Fs, param.morlWidth); |
886 |
| - data.LFP.xFreq.pacAmp(:, i) = morletAmp(data.LFP.xFreq.morlFreq(i), tSeries, param.Fs, param.morlWidth); |
| 886 | + data.LFP.xFreq.phsPAC(:,i) = morletPhase(data.LFP.xFreq.morlFreq(i), tSeries, param.Fs, param.morlWidth); |
| 887 | + data.LFP.xFreq.ampPAC(:,i) = morletAmp(data.LFP.xFreq.morlFreq(i), tSeries, param.Fs, param.morlWidth); |
887 | 888 | end
|
888 | 889 |
|
889 | 890 | % Calculate PAC modulation index (MI):
|
890 |
| - for i = 1 : nFreq |
891 |
| - for j = 1 : nFreq |
892 |
| - data.LFP.xFreq = calcPACMI(data.LFP.xFreq.modPhase(:,j), data.LFP.xFreq.pacAmp(:,i), nSample, param.Fs, nShuffle); |
893 |
| - end |
894 |
| - end |
| 891 | + data.LFP.xFreq = calcPACMI(data.LFP.xFreq, param.Fs, 0); % nShuffle > 1 gets very computationally expensive! |
| 892 | + |
| 893 | + % Order structure: |
| 894 | + data.LFP.xFreq = orderStruct(data.LFP.xFreq); |
| 895 | + |
| 896 | + fprintf('done\n'); |
895 | 897 | end
|
896 | 898 |
|
897 | 899 | %% Total PAC Analysis for each higher frequency band:
|
898 | 900 | % Calculate modulating phase (lower frequency) via Morlet wavelet:
|
899 | 901 | if isfield(data, param.xFreqLow)
|
| 902 | + fprintf(['calculating Z-corrected phase-amplitude coupling for frequency bands of interest (file ' dataFileName ')... ']); |
| 903 | + |
900 | 904 | morlFreqP = data.(param.xFreqLow).lim1 + floor((data.(param.xFreqLow).lim2 - data.(param.xFreqLow).lim1)/2);
|
901 |
| - modPhase = morletPhase(morlFreqP, tSeries, param.Fs, param.morlWidth); |
| 905 | + phsPAC = morletPhase(morlFreqP, tSeries, param.Fs, param.morlWidth); |
902 | 906 |
|
903 | 907 | % Determine available higher phase-modulated frequency(ies) available:
|
904 | 908 | nHi = 0;
|
|
920 | 924 | end
|
921 | 925 |
|
922 | 926 | if nHi > 0
|
923 |
| - |
924 |
| - % Initialize higher frequency arrays: |
925 |
| - morlFreqA = zeros(1, nHi); |
926 |
| - pacAmp = zeros(nSample, nHi); |
927 |
| - |
928 | 927 | for i = 1:nHi
|
929 |
| - |
930 | 928 | if ~isfield(data.(xFreqHi{i}),'xFreq'); data.(xFreqHi{i}).xFreq = struct; end
|
931 | 929 |
|
932 | 930 | % Calculate amplitude of higher frequency(ies) via Morlet wavelet:
|
933 |
| - morlFreqA(i) = data.(xFreqHi{i}).lim1 + floor((data.(xFreqHi{i}).lim2 - data.(xFreqHi{i}).lim1)/2); |
934 |
| - pacAmp(:,i) = morletAmp(morlFreqA(i), tSeries, param.Fs, param.morlWidth); |
935 |
| - |
936 |
| - % Calculate total PAC measure: |
937 |
| - data.(xFreqHi{i}).xFreq = calcPACMI(modPhase, pacAmp(:,i), nSample, Fs, nShuffle); |
| 931 | + morlFreqA = data.(xFreqHi{i}).lim1 + floor((data.(xFreqHi{i}).lim2 - data.(xFreqHi{i}).lim1)/2); |
| 932 | + ampPAC = morletAmp(morlFreqA, tSeries, param.Fs, param.morlWidth); |
938 | 933 |
|
939 | 934 | % Update data structure:
|
940 | 935 | data.(xFreqHi{i}).xFreq.xFreqLow = param.xFreqLow;
|
941 | 936 | data.(xFreqHi{i}).xFreq.xFreqHi = xFreqHi{i};
|
942 | 937 | data.(xFreqHi{i}).xFreq.morlFreqP = morlFreqP;
|
943 |
| - data.(xFreqHi{i}).xFreq.morlFreqA = morlFreqA(i); |
944 |
| - data.(xFreqHi{i}).xFreq.modPhase = modPhase; |
945 |
| - data.(xFreqHi{i}).xFreq.pacAmp = pacAmp(:,i); |
| 938 | + data.(xFreqHi{i}).xFreq.morlFreqA = morlFreqA; |
| 939 | + data.(xFreqHi{i}).xFreq.phsPAC = phsPAC; |
| 940 | + data.(xFreqHi{i}).xFreq.ampPAC = ampPAC; |
| 941 | + |
| 942 | + % Calculate total PAC measure: |
| 943 | + data.(xFreqHi{i}).xFreq = calcPACMI(data.(xFreqHi{i}).xFreq, param.Fs, param.nShuffle); |
946 | 944 | end
|
947 | 945 |
|
948 | 946 | %% Time PAC Analysis
|
949 | 947 | % Truncate signals to get integer number of time windows
|
950 | 948 | nSampWn = ceil(param.winLength * param.Fs);
|
951 | 949 | nSampOl = ceil(param.winOverlap * param.Fs);
|
952 | 950 | remSample = mod(nSample, nSampWn);
|
953 |
| - modPhase = modPhase(1 : nSample - remSample); |
954 |
| - pacAmp = pacAmp(1 : nSample - remSample, :); |
| 951 | + phsPAC = phsPAC(1 : nSample - remSample); |
| 952 | + ampPAC = ampPAC(1 : nSample - remSample, :); |
955 | 953 |
|
956 | 954 | % Update nSample
|
957 |
| - nSample = length(modPhase); |
| 955 | + nSample = length(phsPAC); |
958 | 956 | idx = bsxfun(@plus, (1:nSampWn)', 1+(0:(fix((nSample - nSampOl)/(nSampWn - nSampOl)) - 1))*(nSampWn - nSampOl)) - 1;
|
959 | 957 | nWin = size(idx,2);
|
960 | 958 |
|
961 | 959 | % Determine average time of windows:
|
962 | 960 | timingWin = zeros(nWin, 1);
|
963 |
| - for j = 1:size(idx, 2) |
964 |
| - timingWin(j) = mean(data.LFP.timing(idx(:, j))); |
| 961 | + for k = 1:size(idx, 2) |
| 962 | + timingWin(k) = mean(data.LFP.timing(idx(:, k))); |
965 | 963 | end
|
966 |
| - |
| 964 | + |
967 | 965 | % Calculate windowed time-series PAC:
|
968 |
| - pacMIWin = zeros(nWin, 1); |
| 966 | + pacMIWin = zeros(nWin, 1); |
| 967 | + pacMIWin_Len = zeros(nWin, 1); |
| 968 | + pacMIWin_Phase = zeros(nWin, 1); |
| 969 | + |
969 | 970 | for i = 1:nHi
|
970 |
| - for j = 1:size(idx, 2) |
| 971 | + for k = 1:size(idx, 2) |
| 972 | + |
| 973 | + z = ampPAC(idx(:,k), i) .* exp(1i * phsPAC(idx(:,k))); % Create composite signal |
| 974 | + pacMIWin(k) = mean(z); % Compute the mean length of composite signal |
| 975 | + pacMIWin_Len(k) = abs(pacMIWin(k)); |
| 976 | + pacMIWin_Phase(k) = angle(pacMIWin(k)); |
971 | 977 |
|
972 |
| - z = pacAmp(idx(:,j), i) .* exp(1i * modPhase(idx(:,j))); % Create composite signal |
973 |
| - pacRaw = mean(z); % Compute the mean length of composite signal |
974 |
| - pacMIWin(j) = abs(pacRaw); |
975 |
| - |
976 |
| - % Update data structure: |
977 |
| - data.(xFreqHi{i}).xFreq.pacMIWin = pacMIWin; |
978 |
| - data.(xFreqHi{i}).xFreq.timingWin = timingWin; |
979 | 978 | end
|
| 979 | + |
| 980 | + % Update data structure: |
| 981 | + data.(xFreqHi{i}).xFreq.pacMIWin = pacMIWin; |
| 982 | + data.(xFreqHi{i}).xFreq.pacMIWin_Len = pacMIWin_Len; |
| 983 | + data.(xFreqHi{i}).xFreq.pacMIWin_Phase = pacMIWin_Phase; |
| 984 | + data.(xFreqHi{i}).xFreq.timingWin = timingWin; |
| 985 | + |
| 986 | + % Linear interpolation of pacMIWin_Len to data samplingInt for later correlations |
| 987 | + data.(xFreqHi{i}).xFreq.timingI = data.LFP.timing(1:nSample); |
| 988 | + data.(xFreqHi{i}).xFreq.pacMIWin_LenI = interp1(timingWin, pacMIWin_Len, data.(xFreqHi{i}).xFreq.timingI); |
| 989 | + |
| 990 | + % Order structure: |
| 991 | + data.(xFreqHi{i}).xFreq = orderStruct(data.(xFreqHi{i}).xFreq); |
980 | 992 | end
|
981 | 993 | end
|
982 | 994 | end
|
|
0 commit comments