a6_automatic_artifact_correction.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. function a6_automatic_artifact_correction(id, rootpath)
  2. if ismac % run if function is not pre-compiled
  3. id = '21'; % test for example subject
  4. currentFile = mfilename('fullpath');
  5. [pathstr,~,~] = fileparts(currentFile);
  6. cd(fullfile(pathstr,'..', '..'))
  7. rootpath = pwd;
  8. end
  9. % inputs
  10. pn.eeg_BIDS = fullfile(rootpath, 'data', 'inputs', 'rawdata', 'eeg_BIDS');
  11. pn.channel_locations = fullfile(rootpath, 'data', 'inputs', 'rawdata', 'channel_locations');
  12. pn.events = fullfile(rootpath, 'data', 'inputs', 'rawdata', 'events');
  13. pn.tools = fullfile(rootpath, 'tools');
  14. % outputs
  15. pn.eeg_ft = fullfile(rootpath, 'data', 'outputs', 'eeg');
  16. pn.history = fullfile(rootpath, 'data', 'outputs', 'history');
  17. if ismac % run if function is not pre-compiled
  18. addpath(fullfile(pn.tools, 'fieldtrip')); ft_defaults;
  19. addpath(fullfile(pn.tools, 'helpers'));
  20. end
  21. % N = 33
  22. IDs = tdfread(fullfile(pn.eeg_BIDS, 'participants.tsv'));
  23. IDs = cellstr(IDs.participant_id);
  24. id = str2num(id);
  25. display(['processing ID ' num2str(IDs{id})]);
  26. %% load data
  27. load(fullfile(pn.eeg_ft, [IDs{id}, '_task-xxxx_eeg_seg.mat']),'data_eeg', 'events');
  28. % remove M2 (collinear with M1 due to avg. mastoid REF: mean(M1,M2)=0)
  29. cfg_preproc = [];
  30. cfg_preproc.channel = {'all', '-M2'};
  31. data_eeg = ft_preprocessing(cfg_preproc, data_eeg);
  32. data_ica = load(fullfile(pn.eeg_ft, [IDs{id}, '_task-xxxx_eeg_ica.mat']),'data');
  33. data = data_eeg; clear data_eeg;
  34. data.elec = data_ica.data.elec;
  35. data.chanlocs = data_ica.data.chanlocs; clear data_ica;
  36. %% ------------------ ARTIFACT DETECTION - PREPARATION ----------------- %%
  37. % load config
  38. load(fullfile(pn.history, [IDs{id}, '_task-xxxx_config.mat']),'config');
  39. config.elec = data.elec;
  40. %% ICA (from weights)
  41. % ica config
  42. cfg.method = 'runica';
  43. cfg.channel = {'all'}; % additional channels should be excluded already...
  44. cfg.trials = 'all';
  45. cfg.numcomponent = 'all';
  46. cfg.demean = 'yes';
  47. cfg.runica.extended = 1;
  48. % ICA solution
  49. cfg.unmixing = config.ica1.unmixing;
  50. cfg.topolabel = config.ica1.topolabel;
  51. % components
  52. comp = ft_componentanalysis(cfg,data);
  53. % clear cfg
  54. clear cfg data
  55. %% remove components
  56. % get IC labels
  57. iclabels = config.ica1.iclabels.manual;
  58. % cfg for rejecting components (reject: blinks, eye movements,
  59. % ecg, ref); JQK: added artifacts and emg
  60. cfg.component = sortrows([iclabels.bli(:); iclabels.mov(:); iclabels.hrt(:); iclabels.ref(:); iclabels.art(:); iclabels.emg(:)])';
  61. cfg.demean = 'yes';
  62. % reject components
  63. data = ft_rejectcomponent(cfg,comp);
  64. % clear cfg
  65. clear cfg comp
  66. %% remove eye & reference channels
  67. cfg.channel = {'all','-IO1','-IO2','-M1','-VEOG','-HEOG'};
  68. cfg.demean = 'yes';
  69. % remove channels
  70. tmpdat = ft_preprocessing(cfg,data);
  71. % clear cfg & data variable
  72. clear cfg data
  73. %% ------------------------- ARTIFACT DETECTION ------------------------ %%
  74. % open log file
  75. fid = fopen(fullfile(pn.history, [IDs{id}, '_task-xxxx_ArtCorr.txt']),'a');
  76. fprintf(fid,['********************* BLOCK *********************\n']);
  77. fprintf(fid,['function: a6_automatic_artifact_correction.m \n\n']);
  78. fprintf(fid,['eeg file = ' config.data_file '\n\n']);
  79. n_trl = length(tmpdat.trial);
  80. %% get artifact contaminated channels by kurtosis, low & high frequency artifacts
  81. cfg.criterion = 3;
  82. cfg.recursive = 'no';
  83. [index0 parm0 zval0] = cm_MWB_channel_x_epoch_artifacts_20170922(cfg,tmpdat);
  84. % write log
  85. tmp_log = '';
  86. for j = 1:length(index0.c)
  87. tmp_log = [tmp_log num2str(index0.c(j)) ' '];
  88. end; clear j
  89. tmp_log = [tmp_log(1:end-1) '\n'];
  90. fprintf(fid,'(1) automatic bad channel detection:\n');
  91. fprintf(fid,['MWB: channel(s) ' tmp_log]);
  92. % clear cfg
  93. clear cfg tmp_log
  94. %% get artifact contaminated channels by FASTER
  95. cfg.criterion = 3;
  96. cfg.recursive = 'no';
  97. [index1 parm1 zval1] = THG_FASTER_1_channel_artifacts_20140302(cfg,tmpdat);
  98. % write log
  99. tmp_log = '';
  100. for j = 1:length(index1)
  101. tmp_log = [tmp_log num2str(index1(j)) ' '];
  102. end; clear j
  103. tmp_log = [tmp_log(1:end-1) '\n'];
  104. fprintf(fid,['FASTER: channel(s) ' tmp_log]);
  105. % clear cfg
  106. clear cfg tmp_log
  107. %% interpolate artifact contaminated channels
  108. % collect bad channels
  109. badchan = unique([index0.c; index1]);
  110. if ~isempty(badchan)
  111. fprintf(fid,['--> ' num2str(length(badchan)) ' channels interpolated\n\n']);
  112. cfg.method = 'spline';
  113. cfg.badchannel = tmpdat.label(badchan);
  114. cfg.trials = 'all';
  115. cfg.lambda = 1e-5;
  116. cfg.order = 4;
  117. cfg.elec = config.elec;
  118. % interpolate
  119. tmpdat = ft_channelrepair(cfg,tmpdat);
  120. % clear cfg
  121. clear cfg
  122. end
  123. %% equalize duration of trials to the trial with fewest samples
  124. for indTrial = 1:numel(tmpdat.trial)
  125. TrialLength(indTrial) = size(tmpdat.trial{indTrial},2);
  126. end
  127. [val, idx] = min(TrialLength);
  128. for indTrial = 1:numel(tmpdat.trial)
  129. tmpdat.trial{indTrial} = tmpdat.trial{indTrial}(:,1:val);
  130. tmpdat.time{indTrial} = tmpdat.time{idx};
  131. end
  132. %% get artifact contaminated epochs & exclude epochs
  133. % includes: - THG_MWB_channel_x_epoch_artifacts_20140311
  134. % - THG_FASTER_2_epoch_artifacts_20140302
  135. % recursive epoch exclusion!
  136. [tmpdat index] = THG_automatic_artifact_correction_trials_20170922(tmpdat);
  137. % write log
  138. fprintf(fid,'(2) automatic recursive bad epoch detection:\n');
  139. fprintf(fid,['MWB & FASTER: ' num2str(n_trl-length(index)) ' bad epoch(s) detected\n\n']);
  140. %% get channel x epoch artifacts
  141. % cfg
  142. cfg.criterion = 3;
  143. cfg.recursive = 'yes';
  144. [index3 parm3 zval3] = THG_FASTER_4_channel_x_epoch_artifacts_20140302(cfg,tmpdat);
  145. % write log
  146. fprintf(fid,'(3) automatic single epoch/channel detection:\n');
  147. fprintf(fid,['FASTER: ' num2str(sum(sum(index3))) ' channel(s) x trial(s) detected\n\n']);
  148. % clear cfg
  149. clear cfg
  150. %% collect and save detected artifacts & artifact correction infos
  151. % include ArtDect.parameters
  152. % bad channels
  153. ArtDect.channels = badchan;
  154. % bad trials
  155. tmp = zeros(n_trl,1); tmp(index,1) = 1;
  156. badtrl = find(tmp==0);
  157. ArtDect.trials = badtrl;
  158. clear tmp
  159. % bad single epoch(s)/channel(s) - after exclusion of bad epochs
  160. ArtDect.channels_x_trials = index3;
  161. % overview
  162. ind = [1:n_trl];
  163. ind(badtrl) = [];
  164. tmp = ones(length(tmpdat.label),n_trl);
  165. tmp(:,ind) = index3;
  166. tmp(badchan,:) = 1;
  167. ArtDect.channels_x_trials_all = tmp;
  168. clear tmp
  169. % save version
  170. ArtDect.version = 'JQK 20180123';
  171. % add to config
  172. config.ArtDect = ArtDect;
  173. % save config
  174. save(fullfile(pn.history, [IDs{id}, '_task-xxxx_config.mat']),'config');
  175. %% finalize log
  176. % log
  177. fprintf(fid,'Artifact detection completed.\n');
  178. fprintf(fid,['Information saved to: ' IDs{id} '_config.mat\n\n']);
  179. fclose(fid);
  180. end