From 72d6f331fd73802f3d9530992e618f668e01e96e Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Mon, 6 Dec 2021 11:27:23 -0500 Subject: [PATCH 01/13] Creating Final versions --- src/A_XDF_merge_sets.m | 8 ++++--- src/A_bdf_merge_sets.m | 36 ++++++++++++++--------------- src/A_bdf_non_paradigm_merge_sets.m | 12 +++++----- src/C_manual_check.m | 6 +++-- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/A_XDF_merge_sets.m b/src/A_XDF_merge_sets.m index e28a615..3a93c00 100644 --- a/src/A_XDF_merge_sets.m +++ b/src/A_XDF_merge_sets.m @@ -1,5 +1,8 @@ -% Testing the scr code 6/21/2021 -% ----------------------stopped working at 12376 +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 +% Merging script to create .set file from MoBI particpant. +% Base file is .XDF not .BDF needs extra EEGLAB plugin +% ---------------------- subject_list = {'12851'};%{'12856' '12857' '12859' '12871' '12872' '12892'};%'12022' '12023' '12031' '12081' '12094' '12188' '12255' '12335' '12339' '12362' '12364' '12372' '12376' '12390' '12398' '12407' '12408' '12451' '12454' '12457' '12458' '12459' '12468' '12478' '12498' '12510' '12517' '12532' '12564' '12631' '12633' '12634' '12636' '12665' '12670' '12696' '12719' '12724' '12751' '12763' '12769' '12776' '12790' '12806' '12814' '12823' '12830' '12847' '12851' '12855' '12856' '12857' '12859' '12871' '12872' '12892' }; %all the IDs for the indivual particpants filename = 'Resting_State'; % if your bdf file has a name besides the ID of the participant (e.g. oddball_paradigm) home_path = '\\data.einsteinmed.org\users\Filip Ana Douwe\Resting state data\MoBI\'; %place data is (something like 'C:\data\') @@ -11,7 +14,6 @@ data_path = [home_path subject_list{s} '\']; disp([data_path filename '.xdf']) - EEG = pop_loadxdf([data_path filename '.xdf'] , 'streamtype', 'EEG', 'exclude_markerstreams', {}); temp = EEG.data; EEG.data = temp([2:65],:); % This should work for a 64 cap diff --git a/src/A_bdf_merge_sets.m b/src/A_bdf_merge_sets.m index aaf0d6d..eae8746 100644 --- a/src/A_bdf_merge_sets.m +++ b/src/A_bdf_merge_sets.m @@ -1,8 +1,8 @@ -% Testing the scr code 6/21/2021 -%% extra controls -subject_list = {'10297' '10331' '10385' '10497' '10553' '10590' '10640' '10867' '10906' '12004' '12006' '12139' '12177' '12188' '12197' '12203' '12206' '12230' '12272' '12415' '12449' '12474' '12482' '12516' '12534' '12549' '12588' '12632' '12735' '12746' '12755' '12770' '12852' '12870'}; -%subject_list = {'10033' '10130' '10131' '10257' '10281' '10293' '10360' '10369' '10385' '10394' '10438' '10446' '10463' '10476' '10526' '10545' '10561' '10562' '10581' '10585' '10616' '10748' '10780' '10784' '10822' '10858' '10906' '10915' '10929' '10935' '12005' '12006' '12007' '12010' '12215' '12328' '12360' '12413' '12512' '12648' '12651' '12707' '12727' '12739' '12750' '12815' '12898' '12899'};% ------------------------------------------------ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 +% Merging script to create .set file +subject_list = {'10297' '10331' '10385' '10497' '10553' '10590' '10640' '10867' '10906' '12004' '12006' '12139' '12177' '12188' '12197' '12203' '12206' '12230' '12272' '12415' '12449' '12474' '12482' '12516' '12534' '12549' '12588' '12632' '12735' '12746' '12755' '12770' '12852' '12870' '10033' '10130' '10131' '10257' '10281' '10293' '10360' '10369' '10385' '10394' '10438' '10446' '10463' '10476' '10526' '10545' '10561' '10562' '10581' '10585' '10616' '10748' '10780' '10784' '10822' '10858' '10906' '10915' '10929' '10935' '12005' '12006' '12007' '12010' '12215' '12328' '12360' '12413' '12512' '12648' '12651' '12707' '12727' '12739' '12750' '12815' '12898' '12899'};% ------------------------------------------------ %subject_list = {'1106' '1108' '1132' '1134' '1154' '1160' '1173' '1174' '1179' '1190' '1838' '1839' '1874' '11013' '11051' '11056' '11098' '11106' '11198' '11220' '11244' '11293' '11325' '11354' '11369' '11375' '11515' '11560' '11580' '11667' '11721' '11723' '11750' '11852' '11896' '11898' '11913' '11927' '11958' '11965'}; %all the IDs for the indivual particpants filename = 'restingstate'; % if your bdf file has a name besides the ID of the participant (e.g. oddball_paradigm) home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; %place data is (something like 'C:\data\') @@ -14,21 +14,19 @@ data_path = [home_path subject_list{s} '\']; disp([data_path subject_list{s} '_' filename '.bdf']) - %if blocks == 1 - %if participants have only 1 block, load only this one file - EEG = pop_biosig([data_path subject_list{s} '_' filename '.bdf']); - - - % else - % for bdf_bl = 1:blocks - % %if participants have more than one block, load the blocks in a row - % %your files need to have the same name, except for a increasing number at the end (e.g. id#_file_1.bdf id#_file_2) - % EEG = pop_biosig([data_path subject_list{s} '_' filename '_' num2str(bdf_bl) '.bdf']); - % [ALLEEG, ~] = eeg_store(ALLEEG, EEG, CURRENTSET); - % end - % %since there are more than 1 files, they need to be merged to one big .set file. - % EEG = pop_mergeset( ALLEEG, 1:blocks, 0); - % end + if blocks == 1 + %if participants have only 1 block, load only this one file + EEG = pop_biosig([data_path subject_list{s} '_' filename '.bdf']); + else + for bdf_bl = 1:blocks + %if participants have more than one block, load the blocks in a row + %your files need to have the same name, except for a increasing number at the end (e.g. id#_file_1.bdf id#_file_2) + EEG = pop_biosig([data_path subject_list{s} '_' filename '_' num2str(bdf_bl) '.bdf']); + [ALLEEG, ~] = eeg_store(ALLEEG, EEG, CURRENTSET); + end + %since there are more than 1 files, they need to be merged to one big .set file. + EEG = pop_mergeset( ALLEEG, 1:blocks, 0); + end [ALLEEG EEG CURRENTSET] = pop_newset(ALLEEG, EEG, 0,'setname', [subject_list{s} ' restingstate paradigm'],'gui','off'); %adds a name to the internal .set file %save the bdf as a .set file EEG = pop_saveset( EEG, 'filename',[subject_list{s} '.set'],'filepath',data_path); diff --git a/src/A_bdf_non_paradigm_merge_sets.m b/src/A_bdf_non_paradigm_merge_sets.m index 103d9cb..1e713d7 100644 --- a/src/A_bdf_non_paradigm_merge_sets.m +++ b/src/A_bdf_non_paradigm_merge_sets.m @@ -1,11 +1,11 @@ -% Testing the scr code 6/21/2021 +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 +% Merging script to create .set file for files that were collected without +% using paradigm (particpant was told to close eyes or stare at the center +% of a black screen) % ------------------------------------------------ -%% extra controls clear variables -%_closed.bdf -%_open.bdf -subject_list = {'10399' '12002' '12122'}; -%subject_list = {'10158' '10165' '10384' '10407' '10451' '10467' '10501' '10534' '10615' '10620' '10639' '10844' '10956'}; +subject_list = {'10158' '10165' '10384' '10407' '10451' '10467' '10501' '10534' '10615' '10620' '10639' '10844' '10956' '10399' '12002' '12122'}; %subject_list = {'1101' '1164' '1808' '1852' '1855' '11014' '11094' '11151' '11170' '11275' '11349' '11516' '11558' '11583' '11647' '11729' '11735' '11768' '11783' '11820' '11912'}; filename = 'restingstate'; % if your bdf file has a name besides the ID of the participant (e.g. oddball_paradigm) home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; %place data is (something like 'C:\data\') diff --git a/src/C_manual_check.m b/src/C_manual_check.m index 5fe84af..7fb01e8 100644 --- a/src/C_manual_check.m +++ b/src/C_manual_check.m @@ -1,4 +1,8 @@ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 % Load the raw data of each participant to see if they have bad channels +% Deleting remaining bad channels by eye + seeing if there is something +% of note going on with the raw data of each person clear variables %% ASD %subject_list = {'1101' '1164' '1808' '1852' '1855' '11014' '11094' '11151' '11170' '11275' '11349' '11516' '11558' '11583' '11647' '11729' '11735' '11768' '11783' '11820' '11912' '1106' '1108' '1132' '1134' '1154' '1160' '1173' '1174' '1179' '1190' '1838' '1839' '1874' '11013' '11056' '11098' '11106' '11198' '11244' '11293' '11325' '11354' '11369' '11375' '11515' '11560' '11580' '11667' '11721' '11723' '11750' '11852' '11896' '11898' '11913' '11927' '11958' '11965'}; %all the IDs for the indivual particpants @@ -8,8 +12,6 @@ %home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Control\'; %% extra controls subject_list = {'10297' '10331' '10385' '10399' '10497' '10553' '10590' '10640' '10867' '10906' '12002' '12004' '12006' '12122' '12139' '12177' '12188' '12197' '12203' '12206' '12230' '12272' '12415' '12449' '12474' '12482' '12516' '12534' '12549' '12588' '12632' '12735' '12746' '12755' '12770' '12852' '12870'}; -% did these again because need extra channels deleted -% subject_list = {'12139' '10399'}; home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; %% MoBI % subject_list = {'12022' '12023' '12031' '12081' '12094' '12188' '12255' '12335' '12339' '12362' '12364' '12372' '12376' '12390' '12398' '12407' '12408' '12451' '12454' '12457' '12458' '12459' '12468' '12478' '12498' '12510' '12517' '12532' '12564' '12631' '12633' '12634' '12636' '12665' '12670' '12696' '12719' '12724' '12751' '12763' '12769' '12776' '12790' '12806' '12814' '12823' '12830' '12847' '12851' '12855' '12856' '12857' '12859' '12871' '12872' '12892'}; From 70811d62f65d1e866c31a8816f127cd36d8584e1 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Mon, 6 Dec 2021 11:27:56 -0500 Subject: [PATCH 02/13] Adding deletion of bad data burst --- src/B_preprocess1.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/B_preprocess1.m b/src/B_preprocess1.m index 6e99a05..ca5edda 100644 --- a/src/B_preprocess1.m +++ b/src/B_preprocess1.m @@ -1,10 +1,12 @@ -% Restingstate pipeline 8/24/2021 DH AF PS +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 % fixing channel names for people with 160 config file with only 64 channels % downsample % exclude externals % 1hz and 50hz filter % channel info % exclude channels +% excluding bad burst of data (added 12/6/2021, everything ran before does not use this) % ------------------------------------------------ clear variables eeglab @@ -24,6 +26,7 @@ home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; end deleted_channels=zeros(length(subject_list),2); + deleted_data=zeros(length(subject_list),2); wrongconfig_type2 = zeros(1,length(subject_list)); % Loop through all subjects for s=1:length(subject_list) @@ -77,12 +80,21 @@ end EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_info.set'],'filepath', data_path); old_n_chan = EEG.nbchan; - EEG = clean_artifacts(EEG, 'FlatlineCriterion',5,'ChannelCriterion',0.8,'LineNoiseCriterion',4,'Highpass','off','BurstCriterion','off','WindowCriterion','off','BurstRejection','on','Distance','Euclidian'); + old_samples=EEG.pnts; + %old way, only channel rejection - used for Aging and ASD: + %EEG = clean_artifacts(EEG, 'FlatlineCriterion',5,'ChannelCriterion',0.8,'LineNoiseCriterion',4,'Highpass','off','BurstCriterion','off','WindowCriterion','off','BurstRejection','on','Distance','Euclidian'); + %new way, also bad data (bursts) rejection: + % the only thing to double check is if it will still reject eye + % components in ICA or if these are pre-deleted now (which they shouldn't) + EEG = pop_clean_rawdata(EEG, 'FlatlineCriterion',5,'ChannelCriterion',0.8,'LineNoiseCriterion',4,'Highpass','off','BurstCriterion',20,'WindowCriterion',0.25,'BurstRejection','on','Distance','Euclidian','WindowCriterionTolerances',[-Inf 7] ); new_n_chan = EEG.nbchan; + new_samples=EEG.pnts; deleted_channels(s,:) = [string(subject_list{s}), old_n_chan-new_n_chan] ; + deleted_data(s,:) = [string(subject_list{s}), new_n_chan/old_samples*100] ; EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_exchn.set'],'filepath', data_path); end %saving matrixes for quality control save([home_path 'wrongconfig_type2'], 'wrongconfig_type2'); - save([home_path '_deleted_channels'], 'deleted_channels') + save([home_path '_deleted_channels'], 'deleted_channels'); + save([home_path '_deleted_data'] , 'deleted_data'); end From 3451151a4dc70fea764571cc894625f890ee1885 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Mon, 6 Dec 2021 12:28:08 -0500 Subject: [PATCH 03/13] updating final version --- src/D_preprocces2.m | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/D_preprocces2.m b/src/D_preprocces2.m index 1d2a89f..ebb1c78 100644 --- a/src/D_preprocces2.m +++ b/src/D_preprocces2.m @@ -1,22 +1,21 @@ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 % this script fixes events and makes sure that everyone has the same events -% there are 2 people with the wrong triggers (63539 & 63538 (wrong?) & 63488) -% there are 2 people without a trigger but we have the logfile with the time -% there are several people with 255 as an extra trigger -%clear variables -%eeglab +% this is needed because 1) some people have bad data that included events +% deleted. 2) if data was collected without paradigm, there was no trigger + +clear variables +eeglab Group = 'Control'; % 'Control' 'ASD' 'Aging' switch Group case 'Control' - % home_path = '\\data.einsteinmed.org\users\Filip Ana Douwe\Resting state data\Control\'; - % %% aged matched controls - %subject_list = {'10033' '10130' '10131' '10158' '10165' '10257' '10281' '10293' '10360' '10369' '10384' '10394' '10407' '10438' '10446' '10451' '10463' '10467' '10476' '10501' '10526' '10534' '10545' '10561' '10562' '10581' '10585' '10616' '10615' '10620' '10639' '10748' '10780' '10784' '10822' '10858' '10906' '10915' '10929' '10935' '10844' '10956' '12005' '12007' '12010' '12215' '12328' '12360' '12413' '12512' '12648' '12651' '12707' '12727' '12739' '12750' '12815' '12898' '12899'};% ------------------------------------------------ + %% aged matched controls + %subject_list = {'10033' '10130' '10131' '10158' '10165' '10257' '10281' '10293' '10360' '10369' '10384' '10394' + home_path = '\\data.einsteinmed.org\users\Filip Ana Douwe\Resting state data\Control\';'10407' '10438' '10446' '10451' '10463' '10467' '10476' '10501' '10526' '10534' '10545' '10561' '10562' '10581' '10585' '10616' '10615' '10620' '10639' '10748' '10780' '10784' '10822' '10858' '10906' '10915' '10929' '10935' '10844' '10956' '12005' '12007' '12010' '12215' '12328' '12360' '12413' '12512' '12648' '12651' '12707' '12727' '12739' '12750' '12815' '12898' '12899'};% ------------------------------------------------ %% extra controls subject_list = {'10297' '10331' '10385' '10399' '10497' '10553' '10590' '10640' '10867' '10906' '12002' '12004' '12006' '12122' '12139' '12177' '12188' '12197' '12203' '12206' '12230' '12272' '12415' '12474' '12482' '12516' '12534' '12549' '12588' '12632' '12735' '12746' '12755' '12770' '12852' '12870'}; home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; - % did these again because need extra channels deleted - % subject_list = {'12139' '10399'}; - % home_path = 'C:\Users\dohorsth\Desktop\Testing restingstate\Remaining_controls\'; participant_info = num2cell(zeros(length(subject_list),9)); case 'ASD' @@ -114,4 +113,4 @@ end participant_info(s,:)= [subject_list(s), trigger_info, trigger_225, length(EEG.etc.clean_channel_mask), EEG.nbchan, 100-(EEG.nbchan/length(EEG.etc.clean_channel_mask)*100), EEG.xmax,final_triggers]; end -save([home_path 'participant_info_160chn'], 'participant_info'); \ No newline at end of file +save([home_path 'participant_info'], 'participant_info'); \ No newline at end of file From 6e5667633ae1a151dfe1ae6f2c2c16b42f8513b8 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Mon, 6 Dec 2021 12:29:28 -0500 Subject: [PATCH 04/13] fixing PCA to also look at bridged channels excluding extra cleaning --- src/E_preprocces3.m | 170 +++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 80 deletions(-) diff --git a/src/E_preprocces3.m b/src/E_preprocces3.m index 5df5374..370f502 100644 --- a/src/E_preprocces3.m +++ b/src/E_preprocces3.m @@ -1,3 +1,12 @@ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 +% this script allows for re-reference (which we skip) +% does an average reference +% does ICA (using pop_runica) setting a PCA, of all chans minus 1. This is +% not great. So it's changed to pca = rank(EEG.data), which also takes care of bridged channels) +% does IC lable (to organize the ICA components and prints them per participant +% used to do an extra cleaning that is not needed anymore and excluded (12/6/2021) + clear variables eeglab Group = { 'Control'}; % @@ -58,85 +67,86 @@ EEG = eeg_checkset( EEG ); EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_ref.set'],'filepath', data_path); - % %because the ICA data + overall data is short seem noisy we clean extra for this group - % if strcmp(Group{g}, 'Aging') - % orig_length=EEG.xmax; - % EEG = pop_rejcont(EEG, 'elecrange',[1:EEG.nbchan] ,'freqlimit',[20 40] ,'threshold',8 ,'epochlength',0.5,'contiguous',4,'addlength',0.25,'taper','hamming'); - % clean_length=EEG.xmax; - % deleted_data_before(s,:)=[subject_list(s), 100-(clean_length/orig_length)*100]; - % end - % %Independent Component Analysis - % EEG = eeg_checkset( EEG ); - % pca = EEG.nbchan-1; %the PCA part of the ICA needs stops the rank-deficiency - % EEG = pop_runica(EEG, 'extended',1,'interupt','on','pca',pca); %using runica function, with the PCA part - % EEG = eeg_checkset( EEG ); - % EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_ica.set'],'filepath', data_path); - % %organizing components - % clear bad_components brain_ic muscle_ic eye_ic hearth_ic line_noise_ic channel_ic other_ic - % EEG = iclabel(EEG); %does ICLable function - % ICA_components = EEG.etc.ic_classification.ICLabel.classifications ; %creates a new matrix with ICA components - % %Only the eyecomponent will be deleted, thus only components 3 will be put into the 8 component - % ICA_components(:,8) = ICA_components(:,3); %row 1 = Brain row 2 = muscle row 3= eye row 4 = Heart Row 5 = Line Noise row 6 = channel noise row 7 = other, combining this makes sure that the component also gets deleted if its a combination of all. - % bad_components = find(ICA_components(:,8)>0.80 & ICA_components(:,1)<0.10); %if the new row is over 80% of the component and the component has less the 5% brain - % %Still labeling all the other components so they get saved in the end - % brain_ic = length(find(ICA_components(:,1)>0.80)); - % muscle_ic = length(find(ICA_components(:,2)>0.80 & ICA_components(:,1)<0.05)); - % eye_ic = length(find(ICA_components(:,3)>0.80 & ICA_components(:,1)<0.05)); - % hearth_ic = length(find(ICA_components(:,4)>0.80 & ICA_components(:,1)<0.05)); - % line_noise_ic = length(find(ICA_components(:,5)>0.80 & ICA_components(:,1)<0.05)); - % channel_ic = length(find(ICA_components(:,6)>0.80 & ICA_components(:,1)<0.05)); - % other_ic = length(find(ICA_components(:,7)>0.80 & ICA_components(:,1)<0.05)); - % %Plotting all eye componentes and all remaining components - % if isempty(bad_components)~= 1 %script would stop if people lack bad components - % if ceil(sqrt(length(bad_components))) == 1 - % pop_topoplot(EEG, 0, [bad_components bad_components] ,subject_list{s} ,0,'electrodes','on'); - % else - % pop_topoplot(EEG, 0, [bad_components] ,subject_list{s},[ceil(sqrt(length(bad_components))) ceil(sqrt(length(bad_components)))] ,0,'electrodes','on'); - % end - % title(subject_list{s}); - % print([figure_path subject_list{s} '_Bad_ICs_topos'], '-dpng' ,'-r300'); - % EEG = pop_subcomp( EEG, [bad_components], 0); %excluding the bad components - % close all - % else %instead of only plotting bad components it will plot all components - % title(subject_list{s}); text( 0.2,0.5, 'there are no eye-components found') - % print([figure_path subject_list{s} '_Bad_ICs_topos'], '-dpng' ,'-r300'); - % end - % title(subject_list{s}); - % pop_topoplot(EEG, 0, 1:size(EEG.icaweights,1) ,subject_list{s},[ceil(sqrt(size(EEG.icaweights,1))) ceil(sqrt(size(EEG.icaweights,1)))] ,0,'electrodes','on'); - % print([figure_path subject_list{s} '_remaining_ICs_topos'], '-dpng' ,'-r300'); - % close all - % %putting both figures in 1 plot saving it, deleting the other 2. - % figure('units','normalized','outerposition',[0 0 1 1]) - % if EEG.nbchan<65 - % subplot(1,5,1); - % else - % subplot(1,10,1); - % end - % imshow([figure_path subject_list{s} '_Bad_ICs_topos.png']); - % title('Deleted components') - % if EEG.nbchan<65 - % subplot(1,5,2:5); - % else - % subplot(1,10,2:10); - % end - % imshow([figure_path subject_list{s} '_remaining_ICs_topos.png']); - % title('Remaining components') - % print([figure_path subject_list{s} '_ICs_topos'], '-dpng' ,'-r300'); - % %deleting two original files - % delete([figure_path subject_list{s} '_Bad_ICs_topos.png']) - % delete([figure_path subject_list{s} '_remaining_ICs_topos.png']) - % close all - % EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_excom.set'],'filepath', data_path);%save - % %% extra cleaning - % orig_length=EEG.xmax; - % EEG = pop_rejcont(EEG, 'elecrange',[1:EEG.nbchan] ,'freqlimit',[20 40] ,'threshold',8 ,'epochlength',0.5,'contiguous',4,'addlength',0.25,'taper','hamming'); - % clean_length=EEG.xmax; - % EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_clean.set'],'filepath', data_path);%save - % %% saving structures - % deleted_data(s,:)=[subject_list(s), 100-(clean_length/orig_length)*100]; - % subj_comps=[subject_list(s), num2cell(brain_ic), num2cell(muscle_ic), num2cell(eye_ic), num2cell(hearth_ic), num2cell(line_noise_ic), num2cell(channel_ic), num2cell(other_ic)]; - % components(s,:)=[subj_comps]; + %because the ICA data + overall data is short seem noisy we clean extra for this group + if strcmp(Group{g}, 'Aging') + orig_length=EEG.xmax; + EEG = pop_rejcont(EEG, 'elecrange',[1:EEG.nbchan] ,'freqlimit',[20 40] ,'threshold',8 ,'epochlength',0.5,'contiguous',4,'addlength',0.25,'taper','hamming'); + clean_length=EEG.xmax; + deleted_data_before(s,:)=[subject_list(s), 100-(clean_length/orig_length)*100]; + end + %Independent Component Analysis + EEG = eeg_checkset( EEG ); + %pca = EEG.nbchan-1; %the PCA part of the ICA needs stops the rank-deficiency % pre 12/6/2021 + pca = rank(EEG.data); %this takes care of avg ref and bridge channels + EEG = pop_runica(EEG, 'extended',1,'interupt','on','pca',pca); %using runica function, with the PCA part + EEG = eeg_checkset( EEG ); + EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_ica.set'],'filepath', data_path); + %organizing components + clear bad_components brain_ic muscle_ic eye_ic hearth_ic line_noise_ic channel_ic other_ic + EEG = iclabel(EEG); %does ICLable function + ICA_components = EEG.etc.ic_classification.ICLabel.classifications ; %creates a new matrix with ICA components + %Only the eyecomponent will be deleted, thus only components 3 will be put into the 8 component + ICA_components(:,8) = ICA_components(:,3); %row 1 = Brain row 2 = muscle row 3= eye row 4 = Heart Row 5 = Line Noise row 6 = channel noise row 7 = other, combining this makes sure that the component also gets deleted if its a combination of all. + bad_components = find(ICA_components(:,8)>0.80 & ICA_components(:,1)<0.10); %if the new row is over 80% of the component and the component has less the 5% brain + %Still labeling all the other components so they get saved in the end + brain_ic = length(find(ICA_components(:,1)>0.80)); + muscle_ic = length(find(ICA_components(:,2)>0.80 & ICA_components(:,1)<0.05)); + eye_ic = length(find(ICA_components(:,3)>0.80 & ICA_components(:,1)<0.05)); + hearth_ic = length(find(ICA_components(:,4)>0.80 & ICA_components(:,1)<0.05)); + line_noise_ic = length(find(ICA_components(:,5)>0.80 & ICA_components(:,1)<0.05)); + channel_ic = length(find(ICA_components(:,6)>0.80 & ICA_components(:,1)<0.05)); + other_ic = length(find(ICA_components(:,7)>0.80 & ICA_components(:,1)<0.05)); + %Plotting all eye componentes and all remaining components + if isempty(bad_components)~= 1 %script would stop if people lack bad components + if ceil(sqrt(length(bad_components))) == 1 + pop_topoplot(EEG, 0, [bad_components bad_components] ,subject_list{s} ,0,'electrodes','on'); + else + pop_topoplot(EEG, 0, [bad_components] ,subject_list{s},[ceil(sqrt(length(bad_components))) ceil(sqrt(length(bad_components)))] ,0,'electrodes','on'); + end + title(subject_list{s}); + print([figure_path subject_list{s} '_Bad_ICs_topos'], '-dpng' ,'-r300'); + EEG = pop_subcomp( EEG, [bad_components], 0); %excluding the bad components + close all + else %instead of only plotting bad components it will plot all components + title(subject_list{s}); text( 0.2,0.5, 'there are no eye-components found') + print([figure_path subject_list{s} '_Bad_ICs_topos'], '-dpng' ,'-r300'); + end + title(subject_list{s}); + pop_topoplot(EEG, 0, 1:size(EEG.icaweights,1) ,subject_list{s},[ceil(sqrt(size(EEG.icaweights,1))) ceil(sqrt(size(EEG.icaweights,1)))] ,0,'electrodes','on'); + print([figure_path subject_list{s} '_remaining_ICs_topos'], '-dpng' ,'-r300'); + close all + %putting both figures in 1 plot saving it, deleting the other 2. + figure('units','normalized','outerposition',[0 0 1 1]) + if EEG.nbchan<65 + subplot(1,5,1); + else + subplot(1,10,1); + end + imshow([figure_path subject_list{s} '_Bad_ICs_topos.png']); + title('Deleted components') + if EEG.nbchan<65 + subplot(1,5,2:5); + else + subplot(1,10,2:10); + end + imshow([figure_path subject_list{s} '_remaining_ICs_topos.png']); + title('Remaining components') + print([figure_path subject_list{s} '_ICs_topos'], '-dpng' ,'-r300'); + %deleting two original files + delete([figure_path subject_list{s} '_Bad_ICs_topos.png']) + delete([figure_path subject_list{s} '_remaining_ICs_topos.png']) + close all + EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_excom.set'],'filepath', data_path);%save + %% extra cleaning %was uses before 12/6/2021 for all projects, not needed after update to cleaning function + %orig_length=EEG.xmax; + %EEG = pop_rejcont(EEG, 'elecrange',[1:EEG.nbchan] ,'freqlimit',[20 40] ,'threshold',8 ,'epochlength',0.5,'contiguous',4,'addlength',0.25,'taper','hamming'); + %clean_length=EEG.xmax; + %EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_clean.set'],'filepath', data_path);%save + %% saving structures + deleted_data(s,:)=[subject_list(s), 100-(clean_length/orig_length)*100]; + subj_comps=[subject_list(s), num2cell(brain_ic), num2cell(muscle_ic), num2cell(eye_ic), num2cell(hearth_ic), num2cell(line_noise_ic), num2cell(channel_ic), num2cell(other_ic)]; + components(s,:)=[subj_comps]; end - % save([home_path 'components'], 'components'); - % save([home_path 'deleted_data'], 'deleted_data'); + save([home_path 'components'], 'components'); + save([home_path 'deleted_data'], 'deleted_data'); end \ No newline at end of file From e037b4be07bd30b86adf1171c98e0a41a2a52f9a Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 12:10:36 -0500 Subject: [PATCH 05/13] Minor update, still working on better PCA solution --- src/E_preprocces3.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/E_preprocces3.m b/src/E_preprocces3.m index 370f502..be0d495 100644 --- a/src/E_preprocces3.m +++ b/src/E_preprocces3.m @@ -61,7 +61,6 @@ end end EEG = eeg_checkset( EEG ); - %another re-ref to the averages as suggested for the ICA EEG = pop_reref( EEG, []); EEG = eeg_checkset( EEG ); @@ -76,8 +75,7 @@ end %Independent Component Analysis EEG = eeg_checkset( EEG ); - %pca = EEG.nbchan-1; %the PCA part of the ICA needs stops the rank-deficiency % pre 12/6/2021 - pca = rank(EEG.data); %this takes care of avg ref and bridge channels + pca = EEG.nbchan-1; %the PCA part of the ICA needs stops the rank-deficiency % pre 12/6/2021 , is not accurate but so far the best we can do. Does not take bridging in account, but neither would the normal ICA function, which misses the avg ref sometimes EEG = pop_runica(EEG, 'extended',1,'interupt','on','pca',pca); %using runica function, with the PCA part EEG = eeg_checkset( EEG ); EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_ica.set'],'filepath', data_path); From bed139b269350d545d2cfdc9ba76bc95b93fefc6 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 12:25:29 -0500 Subject: [PATCH 06/13] Final version, adding correct 160ch location file --- src/B_preprocess1.m | 4 +- src/Functions and files/BioSemi160.sfp | 160 ++++++++++++++++++ .../Cap160_fromBESAWebpage.sfp | 160 ------------------ 3 files changed, 162 insertions(+), 162 deletions(-) create mode 100644 src/Functions and files/BioSemi160.sfp delete mode 100644 src/Functions and files/Cap160_fromBESAWebpage.sfp diff --git a/src/B_preprocess1.m b/src/B_preprocess1.m index ca5edda..3fb623a 100644 --- a/src/B_preprocess1.m +++ b/src/B_preprocess1.m @@ -73,9 +73,9 @@ EEG=pop_chanedit(EEG, 'lookup',[home_path 'standard-10-5-cap385.elp']); %make sure you put here the location of this file for your computer elseif EEG.nbchan >159 && EEG.nbchan < 191 %160chan cap if isempty(EEG.chanlocs) && EEG.nbchan==160 - EEG = pop_editset(EEG, 'chanlocs', [home_path 'Cap160_fromBESAWebpage.sfp']); %need to first load any sort of sfp file with the correct channels (the locations will be overwritten to the correct ones later) + EEG = pop_editset(EEG, 'chanlocs', [home_path 'BioSemi160.sfp']); %need to first load any sort of sfp file with the correct channels (the locations will be overwritten to the correct ones later) else - EEG=pop_chanedit(EEG, 'lookup',[home_path 'Cap160_fromBESAWebpage.sfp']); %make sure you put here the location of this file for your computer + EEG=pop_chanedit(EEG, 'lookup',[home_path 'BioSemi160.sfp']); %make sure you put here the location of this file for your computer end end EEG = pop_saveset( EEG, 'filename',[subject_list{s} '_info.set'],'filepath', data_path); diff --git a/src/Functions and files/BioSemi160.sfp b/src/Functions and files/BioSemi160.sfp new file mode 100644 index 0000000..4259805 --- /dev/null +++ b/src/Functions and files/BioSemi160.sfp @@ -0,0 +1,160 @@ +A1 -0.502754 0.8054 13.771154 +A2 -0.617222 -0.845358 13.691172 +A3 -0.413762 -2.538903 13.400333 +A4 -0.794483 -3.914441 12.591419 +A5 -2.581631 -4.917483 11.333055 +A6 -3.976824 -4.13799 11.367427 +A7 -4.328254 -4.975547 10.022306 +A8 -4.167741 -6.027877 8.675461 +A9 -4.122758 -6.562291 7.141714 +A10 -4.053922 -6.638124 5.414099 +A11 -4.004518 -6.88965 3.686868 +A12 -4.004008 -6.814477 2.27632 +A13 -2.336266 -7.532495 2.391116 +A14 -2.289511 -7.554111 4.107889 +A15 -2.486818 -7.441142 5.684131 +A16 -2.716149 -7.16056 7.379928 +A17 -2.501672 -6.77028 8.840742 +A18 -2.838245 -5.850064 10.227766 +A19 -0.817015 -5.009861 11.61382 +A20 -0.877064 -6.276156 10.149178 +A21 -0.774615 -7.045224 8.788757 +A22 -0.843595 -7.492155 7.341002 +A23 -0.788669 -7.756282 5.84167 +A24 -0.633 -7.906188 4.217722 +A25 -0.539449 -7.696934 2.745833 +A26 1.411704 -7.518026 2.712192 +A27 1.467303 -7.630053 4.293546 +A28 1.540047 -7.512056 5.974052 +A29 1.464743 -7.26593 7.58164 +A30 1.350972 -6.70992 9.155167 +A31 1.603084 -5.788867 10.492352 +A32 0.830359 -4.967549 11.611216 +B1 1.234688 0.41797 13.571928 +B2 1.097837 -2.367943 13.344413 +B3 2.848343 -4.131602 11.659273 +B4 3.564411 -4.943066 10.479069 +B5 3.136812 -5.999265 9.286202 +B6 3.341979 -6.589682 7.490771 +B7 3.267119 -6.839255 5.826064 +B8 3.345951 -6.915217 4.130775 +B9 3.138346 -7.017379 2.746778 +B10 4.534298 -5.762781 2.407105 +B11 4.662545 -5.77419 3.900719 +B12 4.790223 -5.649368 5.63703 +B13 4.894629 -5.343014 7.212188 +B14 4.624264 -4.857327 9.032638 +B15 5.781981 -3.259056 8.76741 +B16 5.865303 -3.681406 7.324529 +B17 5.908831 -3.897394 5.478621 +B18 5.797982 -3.829159 3.624327 +B19 6.447035 -1.808043 5.191696 +B20 6.544879 -1.591121 6.975742 +B21 6.374064 -1.468749 8.725749 +B22 4.995219 -3.439905 10.587717 +B23 4.261848 -3.078809 11.767095 +B24 2.849668 -2.732797 12.553963 +B25 2.347426 -0.923371 13.281146 +B26 4.004111 -0.976955 12.507186 +B27 5.167688 -1.264712 11.572498 +B28 5.901933 -1.749307 10.363184 +B29 6.149274 0.614968 10.098549 +B30 6.575709 0.431066 8.582668 +B31 6.749609 0.332677 6.898214 +B32 6.650632 0.153404 5.12625 +C1 0.419 2.230349 13.453223 +C2 2.331177 2.477349 12.80527 +C3 2.709413 0.825925 13.081543 +C4 4.352988 0.751995 12.256689 +C5 3.719488 2.580419 12.044016 +C6 4.978938 2.477536 11.047123 +C7 5.390928 0.675448 11.34504 +C8 5.692895 2.816695 9.702723 +C9 6.296057 2.482619 8.249118 +C10 6.471895 2.484539 6.61971 +C11 6.42416 2.20943 5.04721 +C12 6.11117 4.393553 4.769128 +C13 6.027902 4.364223 6.650479 +C14 5.708961 4.392154 8.102036 +C15 4.80292 6.482067 8.164326 +C16 5.242889 6.598596 6.529839 +C17 5.442825 6.526638 4.661341 +C18 4.208536 8.657319 5.098587 +C19 4.019742 8.405043 6.740083 +C20 3.584544 7.912247 8.287128 +C21 3.665833 6.483461 9.574667 +C22 4.91289 4.787962 9.472591 +C23 4.048941 4.157384 10.925952 +C24 2.711047 4.043592 11.829623 +C25 0.910379 3.783766 12.666347 +C26 1.402295 5.171946 11.677878 +C27 3.146376 5.607183 10.768569 +C28 1.471218 6.636084 10.751596 +C29 2.085348 7.811945 9.621976 +C30 1.99813 8.966757 8.407221 +C31 2.260513 9.640131 7.02741 +C32 2.470505 10.059955 5.342251 +D1 -1.122185 2.150037 13.3845 +D2 -0.171495 4.332767 12.588458 +D3 -0.11356 5.644121 11.783951 +D4 0.008818 7.216861 10.647781 +D5 0.101173 8.324787 9.699611 +D6 0.081216 9.432189 8.443997 +D7 0.204712 10.197851 7.116387 +D8 0.466529 10.643255 5.353137 +D9 -1.83885 10.435769 5.506522 +D10 -1.92739 10.110077 6.895044 +D11 -1.905761 9.170542 8.489321 +D12 -1.974364 7.913888 9.764143 +D13 -1.71831 6.780612 10.688291 +D14 -1.76599 5.278965 11.678548 +D15 -1.733138 3.804813 12.513411 +D16 -2.902267 2.301258 12.609297 +D17 -3.333626 4.202143 11.52576 +D18 -3.32249 5.725945 10.658754 +D19 -3.894969 6.970862 9.307215 +D20 -3.645965 8.345124 8.290927 +D21 -4.031914 8.848404 6.780191 +D22 -4.196475 9.179604 5.222496 +D23 -5.622087 7.080086 4.847104 +D24 -5.355935 7.119614 6.450259 +D25 -5.050061 6.791399 8.069906 +D26 -5.099512 5.149289 9.397481 +D27 -4.533155 4.419368 10.571564 +D28 -4.220738 2.57788 11.816829 +D29 -5.443813 2.644768 10.685936 +D30 -5.994438 4.745372 7.733331 +D31 -6.27796 5.028131 6.149115 +D32 -6.414901 5.038615 4.376985 +E1 -2.043674 0.229905 13.341433 +E2 -3.687079 0.774699 12.621338 +E3 -4.889678 0.707573 11.889888 +E4 -5.990575 0.798257 10.749903 +E5 -6.027906 3.150417 9.23749 +E6 -6.54129 2.894518 7.859041 +E7 -6.713089 3.032598 6.307032 +E8 -6.75176 2.833468 4.549716 +E9 -7.009897 0.686693 4.568756 +E10 -6.991449 0.838978 6.485619 +E11 -6.886427 0.717867 7.942509 +E12 -6.60244 0.884684 9.394568 +E13 -6.484184 -1.426451 9.65339 +E14 -6.842502 -1.213112 7.980154 +E15 -6.903442 -1.454128 6.401833 +E16 -6.927963 -1.496512 4.680427 +E17 -6.214846 -3.353613 3.348228 +E18 -6.436149 -3.197281 4.947453 +E19 -6.405939 -3.302026 6.715731 +E20 -6.271636 -3.090984 8.237268 +E21 -5.847262 -1.12754 10.991976 +E22 -4.743727 -1.131663 12.063151 +E23 -3.356676 -0.764803 12.846946 +E24 -2.101008 -2.067382 13.14271 +E25 -3.750053 -2.706646 12.221036 +E26 -5.211255 -2.788586 11.191066 +E27 -5.86568 -3.290534 9.627591 +E28 -5.383517 -4.802917 8.372959 +E29 -5.440988 -5.16067 6.892123 +E30 -5.402358 -5.344799 5.200267 +E31 -5.334689 -5.304032 3.448208 +E32 -5.189906 -5.537484 1.921001 \ No newline at end of file diff --git a/src/Functions and files/Cap160_fromBESAWebpage.sfp b/src/Functions and files/Cap160_fromBESAWebpage.sfp deleted file mode 100644 index dd64749..0000000 --- a/src/Functions and files/Cap160_fromBESAWebpage.sfp +++ /dev/null @@ -1,160 +0,0 @@ -A1 0 0 92 -A2 0 -18 90 -A3 0 -36 85 -A4 0 -52 76 -A5 -21 -63 64 -A6 -39 -54 64 -A7 -46 -63 50 -A8 -43 -75 33 -A9 -46 -79 15 -A10 -46 -80 -3 -A11 -45 -78 -22 -A12 -42 -72 -39 -A13 -22 -81 -39 -A14 -23 -87 -22 -A15 -24 -89 -3 -A16 -24 -88 15 -A17 -22 -83 33 -A18 -24 -74 50 -A19 0 -66 64 -A20 0 -78 50 -A21 0 -86 33 -A22 0 -91 15 -A23 0 -92 -3 -A24 0 -90 -22 -A25 0 -84 -39 -A26 22 -81 -39 -A27 23 -87 -22 -A28 24 -89 -3 -A29 24 -88 15 -A30 22 -83 33 -A31 24 -74 50 -A32 21 -63 64 -B1 18 -6 90 -B2 18 -31 85 -B3 39 -54 64 -B4 46 -63 50 -B5 43 -75 33 -B6 46 -79 15 -B7 46 -80 -3 -B8 45 -78 -22 -B9 42 -72 -39 -B10 59 -59 -39 -B11 63 -63 -22 -B12 65 -65 -3 -B13 64 -64 15 -B14 61 -61 33 -B15 75 -43 33 -B16 79 -46 15 -B17 80 -46 -3 -B18 78 -45 -22 -B19 89 -24 -3 -B20 88 -24 15 -B21 83 -22 33 -B22 63 -46 50 -B23 54 -39 64 -B24 37 -37 76 -B25 31 -18 85 -B26 48 -20 76 -B27 63 -21 64 -B28 74 -24 50 -B29 78 0 50 -B30 86 0 33 -B31 91 0 15 -b32 92 0 -3 -C1 11 15 90 -C2 31 18 85 -C3 36 0 85 -C4 52 0 76 -C5 48 20 76 -C6 63 21 64 -C7 66 0 64 -C8 74 24 50 -C9 83 22 33 -C10 88 24 15 -C11 89 24 -3 -C12 80 46 -3 -C13 79 46 15 -C14 75 43 33 -C15 61 61 33 -C16 64 64 15 -C17 65 65 -3 -C18 46 80 -3 -C19 46 79 15 -C20 43 75 33 -C21 46 63 50 -C22 63 46 50 -C23 54 39 64 -C24 37 37 76 -C25 18 31 85 -C26 20 48 76 -C27 39 54 64 -C28 21 63 64 -C29 24 74 50 -C30 22 83 33 -C31 24 88 15 -C32 24 89 -3 -D1 -11 15 90 -D2 0 36 85 -D3 0 52 76 -D4 0 66 64 -D5 0 78 50 -D6 0 86 33 -D7 0 91 15 -D8 0 92 -3 -D9 -24 89 -3 -D10 -24 88 15 -D11 -22 83 33 -D12 -24 74 50 -D13 -21 63 64 -D14 -20 48 76 -D15 -18 31 85 -D16 -31 18 85 -D17 -37 37 76 -D18 -39 54 64 -D19 -46 63 50 -D20 -43 75 33 -D21 -46 79 15 -D22 -46 80 -3 -D23 -65 65 -3 -D24 -64 64 15 -D25 -61 61 33 -D26 -63 46 50 -D27 -54 39 64 -D28 -48 20 76 -D29 -63 21 64 -D30 -75 43 33 -D31 -79 46 15 -D32 -80 46 -3 -E1 -18 -6 90 -E2 -36 0 85 -E3 -52 0 76 -E4 -66 0 64 -E5 -74 24 50 -E6 -83 22 33 -E7 -88 24 15 -E8 -89 24 -3 -E9 -92 0 -3 -E10 -91 0 15 -E11 -86 0 33 -E12 -78 0 50 -E13 -74 -24 50 -E14 -83 -22 33 -E15 -88 -24 15 -E16 -89 -24 -3 -E17 -78 -45 -22 -E18 -80 -46 -3 -E19 -79 -46 15 -E20 -75 -43 33 -E21 -63 -21 64 -E22 -48 -20 76 -E23 -31 -18 85 -E24 -18 -31 85 -E25 -37 -37 76 -E26 -54 -39 64 -E27 -63 -46 50 -E28 -61 -61 33 -E29 -64 -64 15 -E30 -65 -65 -3 -E31 -63 -63 -22 -E32 -59 -59 -39 \ No newline at end of file From 9bc318bb5f95fdfcae6ef8b81d349ef7e11735a9 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 12:46:18 -0500 Subject: [PATCH 07/13] final version --- src/F_preprocces4.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/F_preprocces4.m b/src/F_preprocces4.m index 70525cc..6a62203 100644 --- a/src/F_preprocces4.m +++ b/src/F_preprocces4.m @@ -1,7 +1,9 @@ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 % this scripts interpolates channels using the _info.set file and the _clean.set file. It % creates a matrix with all the previously deleted channels. If a % particpant has 160 channels, their data gets interpolated to 64 channels -% Created by Douwe Horsthuis last update on 8/24/202 +% Created by Douwe Horsthuis clear variables eeglab close all @@ -36,14 +38,16 @@ EEG = pop_loadset('filename', [subject_list{s} '_clean.set'], 'filepath', data_path); %loads latest pre-proc file labels_good = {EEG.chanlocs.labels}.'; %saves all the channels that are in the _clean file EEG_temp = pop_loadset('filename', '64.set', 'filepath', home_path); + %need to interpolate first so that we are sure everyone has their full 160ch EEG = pop_interp(EEG, EEGinter.chanlocs, 'spherical'); for b=1:EEG.nbchan if strcmp(EEG.chanlocs(b).labels,'b32') EEG.chanlocs(b).labels = 'B32'; %the channel location file used to have a typo (b32 instead of B32) end end - oldFolder = cd; + oldFolder = cd; %this is where the function should be cd(function_folder) + % using the transform_n_channels function to change 160ch data into 64 channel EEG = transform_n_channels(EEG,EEG_temp.chanlocs,64,'keep'); %this deletes the channel location, so we add it back EEG = pop_editset(EEG, 'chanlocs', [home_path 'BioSemi64.sfp']); %need to first load any sort of sfp file with the correct channels (the locations will be overwritten to the correct ones later) From 36f5d8116eaa6743a603e386401b8c4a0313babd Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 12:50:23 -0500 Subject: [PATCH 08/13] final version --- src/{G_preprocces5.m => G_preprocces5(old).m} | 6 ++++++ 1 file changed, 6 insertions(+) rename src/{G_preprocces5.m => G_preprocces5(old).m} (96%) diff --git a/src/G_preprocces5.m b/src/G_preprocces5(old).m similarity index 96% rename from src/G_preprocces5.m rename to src/G_preprocces5(old).m index e56eff7..ac02241 100644 --- a/src/G_preprocces5.m +++ b/src/G_preprocces5(old).m @@ -1,3 +1,9 @@ +% Restingstate pipepline (2021) +% Final version of SRC code 12/6/2021 +% because in the pre 12/6/2021, we decided to delete bad parts of the +% continues data after the D_preproccess2 script (where it adds missing triggers) +% we needed to run this script. +% The new scripts do this cleaning as a part of deleting channels and thus we DO NOT need to run it clear variables eeglab From e2b3690f2af18da7298950adae8e99b227c12705 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 12:56:04 -0500 Subject: [PATCH 09/13] final version --- src/{G_preprocces5(old).m => G_preprocces5.m} | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) rename src/{G_preprocces5(old).m => G_preprocces5.m} (97%) diff --git a/src/G_preprocces5(old).m b/src/G_preprocces5.m similarity index 97% rename from src/G_preprocces5(old).m rename to src/G_preprocces5.m index ac02241..589377c 100644 --- a/src/G_preprocces5(old).m +++ b/src/G_preprocces5.m @@ -1,9 +1,11 @@ % Restingstate pipepline (2021) % Final version of SRC code 12/6/2021 -% because in the pre 12/6/2021, we decided to delete bad parts of the +% creates separate Eyes open and Eyes closed files +% because in the pre 12/6/2021 scripts, we decided to delete bad parts of the % continues data after the D_preproccess2 script (where it adds missing triggers) -% we needed to run this script. -% The new scripts do this cleaning as a part of deleting channels and thus we DO NOT need to run it +% we needed to re-add triggers. +% The new scripts do this cleaning as a part of deleting channels and thus +% we should not see any missing triggers. But it cannot harm to double check clear variables eeglab From d8de46e19e1aad4d5ceac6b4007349ee7e2ceb71 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 13:09:31 -0500 Subject: [PATCH 10/13] final version --- src/H_PSD_pwelch.m | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/H_PSD_pwelch.m b/src/H_PSD_pwelch.m index 796dff6..33a616f 100644 --- a/src/H_PSD_pwelch.m +++ b/src/H_PSD_pwelch.m @@ -1,7 +1,9 @@ -%this script needs work. -% 1) It should load the EO and EC data -% 2) combine all the channels that that should be grouped and average them -% 3) compute the power on these +% Restingstate pipepline (2021) +% SRC code 12/6/2021 - not final version +% this script loads separatly the EO and EC data +% calculates the Power Spectrum Density for pre-selected channels +% does a log transform and saves all participant results +% script is writen by Filip and edited by Douwe clear variables eeglab @@ -34,30 +36,26 @@ trigger50_51_same = []; trigger_times=num2cell(zeros(length(subject_list),5)); end - path_1 = ['C:\Users\dohorsth\Desktop\Testing restingstate\' group{group_count} '\']; + path_1 = ['\\data.einsteinmed.org\users\Filip Ana Douwe\Resting state data\' group{group_count} '\']; for subject_list_count = 1:length(subject_list) path = [path_1 subject_list{subject_list_count} '\']; - EEG = pop_loadset('filename',[subject_list{subject_list_count} '_EO.set'],'filepath', path ); - EEG = pop_loadset('filename',[subject_list{subject_list_count} '_EC.set'],'filepath', path ); - %% separate EO from EC - + EEG_EO = pop_loadset('filename',[subject_list{subject_list_count} '_EO.set'],'filepath', path ); + EEG_EC = pop_loadset('filename',[subject_list{subject_list_count} '_EC.set'],'filepath', path ); %% grouping data of different channels - data_ch1_ch2_ch3= [EEG.data(1,:);EEG.data(3,:)]; %select here the channels you want to include - data_ch1_ch2_ch3=mean(data_ch1_ch2_ch3); % here it turns it into an average - - + %data_ch1_ch2_ch3= [EEG.data(1,:);EEG.data(3,:)]; %select here the channels you want to include + %data_ch1_ch2_ch3=mean(data_ch1_ch2_ch3); % here it turns it into an average %% Compute Power - CPz = 32; + CPz = 32; %to change this to different channels look in EEG.chanlocs what number goes with what channel Pz = 31; Cz = 48; - [P_EO_CPz freqs] = pwelch(data_EO(CPz,:),len,[],nfft,Fs); %does not produce an image with outputs - P_EO_Pz = pwelch(data_EO(Pz,:),len,[],nfft,Fs); %does not produce an image with outputs - P_EO_Cz = pwelch(data_EO(Cz,:),len,[],nfft,Fs); %does not produce an image with outputs - P_EC_CPz = pwelch(data_EC(CPz,:),len,[],nfft,Fs); %does not produce an image with outputs - P_EC_Pz = pwelch(data_EC(Pz,:),len,[],nfft,Fs); %does not produce an image with outputs - P_EC_Cz = pwelch(data_EC(Cz,:),len,[],nfft,Fs); %does not produce an image with outputs + [P_EO_CPz freqs] = pwelch(EEG_EO.data(CPz,:),len,[],nfft,Fs); %does not produce an image with outputs + P_EO_Pz = pwelch(EEG_EO.data(Pz,:),len,[],nfft,Fs); %does not produce an image with outputs + P_EO_Cz = pwelch(EEG_EO.data(Cz,:),len,[],nfft,Fs); %does not produce an image with outputs + P_EC_CPz = pwelch(EEG_EC.data(CPz,:),len,[],nfft,Fs); %does not produce an image with outputs + P_EC_Pz = pwelch(EEG_EC.data(Pz,:),len,[],nfft,Fs); %does not produce an image with outputs + P_EC_Cz = pwelch(EEG_EC.data(Cz,:),len,[],nfft,Fs); %does not produce an image with outputs PSD_EO_CPzlog(:,subject_list_count) = 10*log10(P_EO_CPz); PSD_EO_Pzlog(:,subject_list_count) = 10*log10(P_EO_Pz); @@ -69,3 +67,4 @@ end end +save([path_1 'PSD_results'],'freqs', 'PSD_EO_CPzlog', 'SD_EO_Pzlog', 'PSD_EO_Czlog', 'PSD_EC_CPzlog', 'PSD_EC_Pzlog', 'PSD_EC_Czlog'); \ No newline at end of file From 5fdf42b811d77a2c8bf97d057cb396b464aee74e Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 13:11:27 -0500 Subject: [PATCH 11/13] final version --- src/I_Microstates_groups.m | 4 +++- src/J_Microstates_all.m | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/I_Microstates_groups.m b/src/I_Microstates_groups.m index 41bf582..6cb00f1 100644 --- a/src/I_Microstates_groups.m +++ b/src/I_Microstates_groups.m @@ -1,4 +1,6 @@ -%this script follows the code as descibed in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. +% Restingstate pipepline (2021) +% SRC code 12/6/2021 - final version +% this script follows the code as descibed in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. % this script only focuses on the group part % so that you can decide how many microstates % you want to choose without getting into single subjects diff --git a/src/J_Microstates_all.m b/src/J_Microstates_all.m index 51962db..38118a2 100644 --- a/src/J_Microstates_all.m +++ b/src/J_Microstates_all.m @@ -1,4 +1,6 @@ -%this script follows the code as descibed in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. +% Restingstate pipepline (2021) +% SRC code 12/6/2021 - final version +% this script follows the code as descibed in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. % adapted for our pipeline on 8/27/2021 by Douwe clear variables From 0b5a5417616d2d7be11f75c498faee7f54507068 Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 13:17:57 -0500 Subject: [PATCH 12/13] final version --- src/B_preprocess1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/B_preprocess1.m b/src/B_preprocess1.m index 3fb623a..eb1db8e 100644 --- a/src/B_preprocess1.m +++ b/src/B_preprocess1.m @@ -86,7 +86,7 @@ %new way, also bad data (bursts) rejection: % the only thing to double check is if it will still reject eye % components in ICA or if these are pre-deleted now (which they shouldn't) - EEG = pop_clean_rawdata(EEG, 'FlatlineCriterion',5,'ChannelCriterion',0.8,'LineNoiseCriterion',4,'Highpass','off','BurstCriterion',20,'WindowCriterion',0.25,'BurstRejection','on','Distance','Euclidian','WindowCriterionTolerances',[-Inf 7] ); + EEG = pop_clean_rawdata(EEG, 'FlatlineCriterion',5,'ChannelCriterion',0.8,'LineNoiseCriterion',4,'Highpass','off','WindowCriterion',0.25,'BurstRejection','on','Distance','Euclidian','WindowCriterionTolerances',[-Inf 7] ); new_n_chan = EEG.nbchan; new_samples=EEG.pnts; deleted_channels(s,:) = [string(subject_list{s}), old_n_chan-new_n_chan] ; From a96773637aff0dc7ebb8c1b1860b85cb761fb6ce Mon Sep 17 00:00:00 2001 From: douwehorsthuis Date: Tue, 7 Dec 2021 13:32:41 -0500 Subject: [PATCH 13/13] update readme --- README.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fbd0027..6a87b13 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,9 @@ This is still a work in progress. This Repo will contain the full pipeline to an - [Pre processing](#pre-processing) 3. [Power Frequency Analysis](#power-frequency-analysis) 3. [Microstates](#microstates) - - [I_Mictrostates_groups](#i_mictrostates_groups) - - [I_Mictrostates_all](#i_mictrostates_all) + - [I_Mictrostates_groups](#i-mictrostates-groups) + - [I_Mictrostates_all](#i-mictrostates-all) +3. [Extra functions](#extra-functions) 3. [License](#license) 3. [Contact](#contact) 3. [Acknowledgement](#acknowledgement) @@ -88,25 +89,26 @@ One of the issues we encountered was that some participants had their data colle The data is down-sampled from 512Hz to 256 Hz. Externals are all deleted since not everyone has externals. So we cannot use them as a reference. We apply a 1Hz (filter order 1690) and 50Hz (filter order 136) filter. -We add channel info to all the channel. For this we use the following 3 files: standard-10-5-cap385, Cap160_fromBESAWebpage, BioSemi64. The first 2 are from BESA and have the correct layout. The 3rd is needed for the MoBI data. You can find these in the Functions and files folder (inside the src folder). -Lastly this script uses eeglab's clean_artifacts function deletes the bad channels. Channels will get deleted by the standard noise criteria, if they are flat over 4 seconds and the function checks if channels are overly correlated with each other. **double check this last statement** +We add channel info to all the channel. For this we use the following 3 files: standard-10-5-cap385, BioSemi160, BioSemi64. The first 2 are from BESA and have the correct layout. The 3rd is needed for the MoBI data. You can find these in the Functions and files folder (inside the src folder). +Lastly this script uses eeglab's clean_artifacts function deletes the bad channels. Channels will get deleted by the standard noise criteria, if they are flat over 5 seconds and the function checks if channels are overly correlated with each other. The function also deletes continues data if there is bad data. It breaks the data in 0.5 second steps. Data is bad if it off by 5 std dev. Which is a "A quite conservative" and default value according to the function. #### C_manual_check This script plots all the data in EEGlab as continues data and allows you to delete channels manually. #### D_preprocces2 -This script will double check and fix any potential trigger issue we encountered. It saves a Matrix with the information for each individual participant. **This script can be skipped** It is only useful for documenting triggers. We added the [pop_rejcont](https://github.com/wojzaremba/active-delays/blob/master/external_tools/eeglab11_0_4_3b/functions/popfunc/pop_rejcont.m) in the next script and this deletes triggers sometimes, so we need to double check triggers again (see [G_preprocces5](#g_preprocces5)). +This script will double check and fix any potential trigger issue we encountered. It saves a Matrix with the information for each individual participant. **This script can be skipped** It is only useful for documenting triggers. We added the ~~ [pop_rejcont](https://github.com/wojzaremba/active-delays/blob/master/external_tools/eeglab11_0_4_3b/functions/popfunc/pop_rejcont.m) in the next script and this deletes triggers sometimes~~, so we need to double check triggers again (see [G_preprocces5](#g_preprocces5)). +Since off the 12/6/2021 update this is not the case. The clean_artifacts takes care of noisy continues data. But it might be good to run either script since they are quick. If you want to save time, skip this one. #### E_preprocces3 This script will do an average reference. This is followed by an [Independent Component Analysis](https://eeglab.org/tutorials/06_RejectArtifacts/RunICA.html). We use the pca option to prevent rank-deficiencies. -After his we delete only eye components by using [IClabel](https://github.com/sccn/ICLabel). IClabel will only delete the component if it has more than 80% eye data and less then 10% brain data. We arrived at this criteria after comparing (for a different dataset) how many components we (Ana, Douwe and Filip) would delete manually and what threshold would get the closesed to that. -After that we use [pop_rejcont](https://github.com/wojzaremba/active-delays/blob/master/external_tools/eeglab11_0_4_3b/functions/popfunc/pop_rejcont.m). This function epochs the data temporatly and deletes the epochs that are noisy. We set this to a threshold of 8, because this would delete between 0-20% of the data. We save a matlab structure with how much data of each participant get's deleted. +After his we delete only eye components by using [IClabel](https://github.com/sccn/ICLabel). IClabel will only delete the component if it has more than 80% eye data and less then 10% brain data. We arrived at this criteria after comparing (for a different dataset) how many components we (Ana, Douwe and Filip) would delete manually and what threshold would get the closest to that. +After that we use [pop_rejcont](https://github.com/wojzaremba/active-delays/blob/master/external_tools/eeglab11_0_4_3b/functions/popfunc/pop_rejcont.m). This function epochs the data temporally and deletes the epochs that are noisy. We set this to a threshold of 8, because this would delete between 0-20% of the data. We save a matlab structure with how much data of each participant get's deleted. **note** for the Aging group, we use the [pop_rejcont](https://github.com/wojzaremba/active-delays/blob/master/external_tools/eeglab11_0_4_3b/functions/popfunc/pop_rejcont.m) function also right before the ICA. This is because the data was too noisy for more than 50% of the participants to find eye components. #### F_preprocces4 -This script loads a file with all the original channels, deletes the externals and uses these file locations to interpolate the channels of the corresponding's subjects data. +This script loads a file with all the original channels, deletes the externals and uses these file locations to interpolate the channels of the corresponding subject's data. In the case of 160 channel data, it uses the [transform_n_channels](https://github.com/CognitiveNeuroLab/Interpolating_160ch_to_64ch_eeglab) function to interpolate the remaining channels not to the original 160, but to 64 channel data so that it is the same as all the other data. For this to work Matlab needs to know the location of 2 things, the trannsform_n_channel.m file and the EEG files called 64.set and 64.fdt. #### G_preprocces5 @@ -115,13 +117,13 @@ In this script, we first make sure that the triggers are still in the right plac ### Power Frequency Analysis -After that we use the the [pwelch function of Matlab](https://www.mathworks.com/help/signal/ref/pwelch.html) and a log tranformation of the results to get the power frequency results. +After that we use the the [pwelch function of Matlab](https://www.mathworks.com/help/signal/ref/pwelch.html) and a log transformation of the results to get the power frequency results. -# add here what channels we use, for now it's just indivual but we will change this to groups and averages of those groups +for now we are only using pre-selected channels. But it's possible to take averages and or instead do this for every channel. ### Microstates -this script follows the code as descibed in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. [See their guide in bioRxiv for more information.](https://www.biorxiv.org/content/10.1101/289850v1) +this script follows the code as described in Poulsen, A. T., Pedroni, A., Langer, N., & Hansen, L. K. (2018). Microstate EEGlab toolbox: An introductory guide. [See their guide in bioRxiv for more information.](https://www.biorxiv.org/content/10.1101/289850v1) #### I_Mictrostates_groups In the We first focuses on the group level. Since we use both eyes open and eyes closed data, we want to check how many microstates are suggested for both, so we can choose the best (same) amount for both. In the case of patient/control group we would need to compare all 4 the suggestions. Running the whole script would take a lot of time that wasn't needed. @@ -130,7 +132,9 @@ In the We first focuses on the group level. Since we use both eyes open and eyes The second script will backfit the mictrostates on the individual EEGs (since now you know how many microstates you want). Giving both plots per subject and adds data to the EEG structure to do stats on. - +#### Extra functions + +Because this script uses both 160 and 64 channel collected with biosemi caps we needed to get the to a same format. To do this we are using the transform_n_channels function [documented here](https://github.com/CognitiveNeuroLab/Interpolating-channels-between-different-cap-sizes). In this case it turns all the 160 channel data into 64 channels. But it will keep the original channels that are closed to the location of the corresponding 64ch cap. ## License