|
| 1 | +% |
| 2 | +% Modified on 2024/04/11 to process thrive dataset flanker data |
| 3 | +% |
| 4 | +% This script was created by George Buzzell for the NDC Lab EEG Training |
| 5 | +% Workshop on 02/22. This script uses parts of the "set up" structure from |
| 6 | +% the MADE preprocessing pipeline (Debnath, Buzzell, et. al., 2020) |
| 7 | + |
| 8 | +clear % clear matlab workspace |
| 9 | +clc % clear matlab command window |
| 10 | + |
| 11 | +%% Setting up other things |
| 12 | + |
| 13 | +%Location of MADE and ADJUSTED-ADJUST scripts |
| 14 | +% addpath(genpath([main_dir filesep 'MADE-EEG-preprocessing-pipeline']));% enter the path of the EEGLAB folder in this line |
| 15 | +addpath(genpath('/home/data/NDClab/tools/lab-devOps/scripts/MADE_pipeline_standard/eeg_preprocessing'));% enter the path of the folder in this line |
| 16 | + |
| 17 | +addpath(genpath('/home/data/NDClab/analyses/thrive-theta-ddm/code/matlab/')) |
| 18 | + |
| 19 | +%Location of "EEG |
| 20 | +% addpath(genpath([main_dir filesep 'eeglab13_4_4b']));% enter the path of the EEGLAB folder in this line |
| 21 | +addpath(genpath('/home/data/NDClab/tools/lab-devOps/scripts/MADE_pipeline_standard/eeglab13_4_4b'));% enter the path of the EEGLAB folder in this line |
| 22 | + |
| 23 | +%remove path to octave functions inside matlab to prevent errors when |
| 24 | +% rmpath([main_dir filesep 'eeglab13_4_4b' filesep 'functions' filesep 'octavefunc' filesep 'signal']) |
| 25 | +rmpath(['/home/data/NDClab/tools/lab-devOps/scripts/MADE_pipeline_standard/eeglab13_4_4b' filesep 'functions' filesep 'octavefunc' filesep 'signal']) |
| 26 | + |
| 27 | +%% setup; run this section before any other section below |
| 28 | + |
| 29 | +%location of analysis folder |
| 30 | +% analysis_dir = '/Users/fzaki001/thrive-theta-ddm'; |
| 31 | +analysis_dir = '/home/data/NDClab/analyses/thrive-theta-ddm'; |
| 32 | + |
| 33 | +%location of dataset folder |
| 34 | +% dataset_dir = '/Users/fzaki001/thrive-theta-ddm'; |
| 35 | +dataset_dir = '/home/data/NDClab/datasets/thrive-dataset'; |
| 36 | +% summary_csv_path = '/Users/fzaki001/thrive-theta-ddm/derivatives/behavior/summary.csv'; |
| 37 | +summary_csv_path = '/home/data/NDClab/analyses/thrive-theta-ddm/derivatives/behavior/summary.csv'; |
| 38 | + |
| 39 | +% Setting up other things |
| 40 | + |
| 41 | +% 1. Enter the path of the folder that has the data to be analyzed |
| 42 | +data_location = [dataset_dir filesep 'derivatives' filesep 'preprocessed']; |
| 43 | + |
| 44 | +% 2. Enter the path of the folder where you want to save the postprocessing outputs |
| 45 | +output_location = [analysis_dir filesep 'derivatives' filesep 'preprocessed/erp_check']; |
| 46 | + |
| 47 | +% 3. this is the correct channel location file BUT INCORRECT PATH! |
| 48 | +% channel_locations = loadbvef('/Users/fzaki001/Downloads/thrive/code/CACS-128-X7-FIXED-64only.bvef'); |
| 49 | +channel_locations = loadbvef('/home/data/NDClab/tools/lab-devOps/scripts/MADE_pipeline_standard/eeg_preprocessing/chan_locs_files/electrode_locs_files/CACS-128-X7-FIXED-64only.bvef'); |
| 50 | + |
| 51 | +% %specify parameters of data to process |
| 52 | + |
| 53 | +%modifying above, to account for files named differently |
| 54 | +%specify parameters of data to process |
| 55 | +task = 'all'; |
| 56 | +procStage = 'processed_data'; |
| 57 | +visitDirName = 's1_r1'; %visit folder does not list "e1" |
| 58 | +visitFileName = 's1_r1_e1'; %file names include "e1" designation |
| 59 | + |
| 60 | +% Read files to analyses |
| 61 | +datafile_info=dir([data_location filesep 'sub-*' filesep visitDirName filesep 'eeg' filesep 'sub-*_' task '_eeg_*' procStage '_' visitFileName '.set']); |
| 62 | +datafile_info=datafile_info(~ismember({datafile_info.name},{'.', '..', '.DS_Store'})); |
| 63 | +datafile_names={datafile_info.name}; |
| 64 | +datafile_paths={datafile_info.folder}; |
| 65 | +[filepath,name,ext] = fileparts(char(datafile_names{1})); |
| 66 | + |
| 67 | +% Check whether EEGLAB and all necessary plugins are in Matlab path. |
| 68 | +if exist('eeglab','file')==0 |
| 69 | + error(['Please make sure EEGLAB is on your Matlab path. Please see EEGLAB' ... |
| 70 | + 'wiki page for download and instalation instructions']); |
| 71 | +end |
| 72 | + |
| 73 | +% Create output folders to save data |
| 74 | +if exist(output_location, 'dir') == 0 |
| 75 | + mkdir(output_location) |
| 76 | +end |
| 77 | + |
| 78 | +for site = 1:64 |
| 79 | + trodes{site} = num2str(site) |
| 80 | +end |
| 81 | +Montage_64=ExtractMontage('/home/data/NDClab/analyses/thrive-theta-ddm/code/preprocessing-eeg/64ch_bv_montage_csd.csd', trodes'); |
| 82 | +% MapMontage(Montage_64); |
| 83 | +[G, H] = GetGH(Montage_64); |
| 84 | + |
| 85 | +%% Count trials |
| 86 | +% switch to output directory |
| 87 | +cd(output_location); |
| 88 | + |
| 89 | +% %create variable names for count trials output and write to disk |
| 90 | +% outputHeader = {'id, s_resp_incon_error, s_resp_incon_corr, ns_resp_incon_error, ns_resp_incon_corr'}; |
| 91 | +% dlmwrite(strcat('thrive_trialCounts_respOnly', date, '.csv'), outputHeader, 'delimiter', '', '-append'); |
| 92 | + |
| 93 | +diary(sprintf('erp_log_%s.log', datestr(now, 'mm-dd-yyyy_HH_MM_SS'))) |
| 94 | + |
| 95 | +%% pull resp-locked erp mat file |
| 96 | + |
| 97 | +%read in behavioral data for participants |
| 98 | +behavior_info = readtable(summary_csv_path); |
| 99 | + |
| 100 | +%specify min number of trials per condition (if file contains less than |
| 101 | +%this number for ANY condition, then they will be skipped for ALL conditions |
| 102 | +minTrials = 6; |
| 103 | + |
| 104 | +%specify min accuracy per condition (if file contains less than |
| 105 | +%this number for ANY condition, then they will be skipped for ALL conditions |
| 106 | +acc_cutoff = .6; |
| 107 | + |
| 108 | +%initialize participant counter variable (used for indexing into large mat |
| 109 | +%file that data is saved into) |
| 110 | +pIdx = 1; |
| 111 | + |
| 112 | +%initialize matrices to hold erp data and corresponding sub ids |
| 113 | +erpDat_data = []; |
| 114 | +erpDat_subIds = []; |
| 115 | + |
| 116 | +% loop through each participant in the study |
| 117 | +for subject = 1:length(datafile_names) |
| 118 | + |
| 119 | + %initialize numTrials for this participant/file |
| 120 | + numTrials = []; |
| 121 | + |
| 122 | + % extract participant number |
| 123 | + subNumText = datafile_names{subject}(5:11); |
| 124 | + |
| 125 | + %find row in behavior file corresponding to this participant |
| 126 | + behavior_id_match_idxs = find(behavior_info{:,'sub'} == str2num(subNumText)); |
| 127 | + |
| 128 | + %if participant has low accuracy in either condition, skip that |
| 129 | + %participant for ALL conditions |
| 130 | + % if (behavior_info{behavior_id_match_idxs,'acc_nonsoc'} < acc_cutoff || behavior_info{behavior_id_match_idxs,'acc_soc'} < acc_cutoff) |
| 131 | + % continue |
| 132 | + % end |
| 133 | + % |
| 134 | + % if (behavior_info{behavior_id_match_idxs,'x6_or_more_err_nonsoc'} < 6 || behavior_info{behavior_id_match_idxs,'x6_or_more_err_soc'} < 6) |
| 135 | + % continue |
| 136 | + % end |
| 137 | + %load the original data set |
| 138 | + EEG = pop_loadset( 'filename', datafile_names{subject}, 'filepath', datafile_paths{subject}); |
| 139 | + EEG = eeg_checkset( EEG ); |
| 140 | + |
| 141 | + %remove all the non-stim-locking markers (should have done already...) |
| 142 | + EEG = pop_selectevent( EEG, 'latency','-.1 <= .1','deleteevents','on'); |
| 143 | + EEG = eeg_checkset( EEG ); |
| 144 | + |
| 145 | + for ne = 1:length(EEG.epoch) |
| 146 | + myEEG = single(EEG.data(:, :, ne)); |
| 147 | + MyResults = CSD(myEEG, G, H); % compute CSD for <channels-by-samples> 2-D epoch |
| 148 | + data(:, :, ne) = MyResults; |
| 149 | + end |
| 150 | + EEG.data = data |
| 151 | + |
| 152 | + data(:,:,:) = NaN; |
| 153 | + |
| 154 | + % NOTE % |
| 155 | + %the logic of checking conditions and then looping over conditions |
| 156 | + %below is fairly hard-coded and could be be substantially improved to |
| 157 | + %allow for easier reuse when number of conditions or number of |
| 158 | + %variables per condition changes. |
| 159 | + % |
| 160 | + %before pulling trials of interest, for any conditions, check to make |
| 161 | + %sure this file/participant has more than minTrials for EACH condition. |
| 162 | + %If the file/participant is below minTrials for even one of the |
| 163 | + %conditions that will be pulled, then the file/participant is skipped |
| 164 | + %entirely and no condition data at all will be pulled for this specific |
| 165 | + %file (but the participant can still have data pulled for another one |
| 166 | + %of their files from another visit). |
| 167 | + % |
| 168 | + %count trials for each condition of interest and store in numTrials vector |
| 169 | + numTrials(1) = length(find( (strcmp({EEG.event.observation}, "s")) & (strcmp({EEG.event.eventType}, "resp")) & (strcmp({EEG.event.congruency}, "i")) & ([EEG.event.accuracy] == 0) & ([EEG.event.responded] == 1) & ([EEG.event.validRt] == 1) )); |
| 170 | + numTrials(2) = length(find( (strcmp({EEG.event.observation}, "s")) & (strcmp({EEG.event.eventType}, "resp")) & (strcmp({EEG.event.congruency}, "i")) & ([EEG.event.accuracy] == 1) & ([EEG.event.responded] == 1) & ([EEG.event.validRt] == 1) )); |
| 171 | + numTrials(3) = length(find( (strcmp({EEG.event.observation}, "ns")) & (strcmp({EEG.event.eventType}, "resp")) & (strcmp({EEG.event.congruency}, "i")) & ([EEG.event.accuracy] == 0) & ([EEG.event.responded] == 1) & ([EEG.event.validRt] == 1) )); |
| 172 | + numTrials(4) = length(find( (strcmp({EEG.event.observation}, "ns")) & (strcmp({EEG.event.eventType}, "resp")) & (strcmp({EEG.event.congruency}, "i")) & ([EEG.event.accuracy] == 1) & ([EEG.event.responded] == 1) & ([EEG.event.validRt] == 1) )); |
| 173 | + |
| 174 | + %logical test if the number of trials for each condition (numTrials vector) |
| 175 | + %are NOTE all >= minTrials. If statement is true, then participant/file |
| 176 | + %is skipped and for loop over files continues to next file |
| 177 | + if ~(sum(numTrials >= minTrials) == length(numTrials)) |
| 178 | + continue |
| 179 | + end |
| 180 | + |
| 181 | + % loop through conditions of interest for this file (combo of event types) |
| 182 | + % |
| 183 | + % specify number of conditions using a seperate conditionNums var, so |
| 184 | + % that it can be referenced below when iterating idx counters (to only |
| 185 | + %iterate when c == length(conditionNums); |
| 186 | + conditionNums = 1:4; |
| 187 | + % |
| 188 | + for c = conditionNums |
| 189 | + |
| 190 | + if (c==1) % social error |
| 191 | + observation = 's'; |
| 192 | + eventType = 'resp'; |
| 193 | + congruency = 'i'; |
| 194 | + accuracy = 0; |
| 195 | + responded = 1; |
| 196 | + validRt = 1; |
| 197 | + elseif (c==2) % social correct |
| 198 | + observation = 's'; |
| 199 | + eventType = 'resp'; |
| 200 | + congruency = 'i'; |
| 201 | + accuracy = 1; |
| 202 | + responded = 1; |
| 203 | + validRt = 1; |
| 204 | + elseif (c==3) % nonsocial error |
| 205 | + observation = 'ns'; |
| 206 | + eventType = 'resp'; |
| 207 | + congruency = 'i'; |
| 208 | + accuracy = 0; |
| 209 | + responded = 1; |
| 210 | + validRt = 1; |
| 211 | + elseif (c==4) % nonsocial correct |
| 212 | + observation = 'ns'; |
| 213 | + eventType = 'resp'; |
| 214 | + congruency = 'i'; |
| 215 | + accuracy = 1; |
| 216 | + responded = 1; |
| 217 | + validRt = 1; |
| 218 | + end |
| 219 | + |
| 220 | + %select combintion of event types of interest based on vars above |
| 221 | + EEG1 = pop_selectevent( EEG, 'latency','-1<=1','observation',observation,'eventType',eventType,'congruency',congruency,'accuracy',accuracy,'responded',responded,'validRt',validRt,'deleteevents','on','deleteepochs','on','invertepochs','off'); |
| 222 | + EEG1 = eeg_checkset( EEG1 ); |
| 223 | + |
| 224 | + % Average across epoch dimension |
| 225 | + % this all Channel ERP only needs to be computed once |
| 226 | + % per condition |
| 227 | + meanEpochs = mean(EEG1.data, 3); |
| 228 | + |
| 229 | + %store data for this condition in array |
| 230 | + erpDat_data(pIdx,c,:,:)= meanEpochs; |
| 231 | + |
| 232 | + %store participant number for corresponding row in erpdat |
| 233 | + erpDat_subIds{pIdx,1} = datafile_names{subject}(5:11); |
| 234 | + |
| 235 | + %iterate idx counter IMPORTANT: ONLY ITERATE COUNTER WHEN |
| 236 | + %ON LAST CONDITION |
| 237 | + if c == length(conditionNums)%if this is the last condition of condition loop |
| 238 | + pIdx = pIdx + 1; |
| 239 | + end |
| 240 | + %end loop through conditions |
| 241 | + end |
| 242 | + %end loop through participants |
| 243 | +end |
| 244 | + |
| 245 | +%save the erps and subject list |
| 246 | +save('thrive_Resp_erps_csd_min_6t_60acc.mat','erpDat_data', 'erpDat_subIds') |
0 commit comments