Skip to content

Commit

Permalink
add descriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
AyaKabbara committed Jul 21, 2022
1 parent 908e0f9 commit b72de67
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 1,385 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# Successful reproduction of a large EEG study across software packages

by
Aya Kabbara
Nina Forde
Camille Maumet
Mahmoud Hassan

> This is a guide for researchers to reproduce the results and figures published in the paper
This paper has been submitted for publication in NeuroImage Reports.

> This study sheds light on how the software tool used to preprocess EEG signals impacts the analysis results and conclusions. EEGLAB, Brainstorm and FieldTrip were used to reproduce the same preprocessing pipeline of a published EEG study performed on 500 participants.
![](figures/figure1_preprocess.001.jpeg)

*The full pipeline of the study. (a) EEGs were acquired from 500 participants performing a simple gambling task of six blocks composed of 20 trials. (b) The same dataset was then preprocessed using the different software tools: Reference (using the code published by the original paper (Williams et al. 2021)), EEGLAB, Brainstorm and FieldTrip. The preprocessing steps to be performed in each tool includes: the reduction to 32 electrodes, the re-referencing, the automatic detection of bad electrodes, the band-pass filtering, the interpolation of bad channels, the segmentation into time-locked epochs and the removal of artifactual trials. (c) The preprocessed signals derived from the four preprocessing codes are used to validate and reproduce the reference statistics and hypotheses. A quantitative comparison between the resulting signals is also conducted in terms of signal features*


## Abstract

> As an active field of research, Electroencephalography (EEG) analysis workflow has increasing flexibility and complexity, with a great variety of methodological options and tools to be selected at each step. This high analytical flexibility can be problematic as it can yield variability in research outcomes. Therefore, growing attention has been recently paid to understand the potential of different methodological decisions to influence the reproducibility of results. In this paper, we aim to examine how sensitive the results of EEG analyses are to variations in software tools. We reanalyzed shared EEG data (N=500) previously used in a published task EEG study using three of the most commonly used software tools: EEGLAB, Brainstorm and FieldTrip. After reproducing the same original preprocessing workflow in each software, the resultant evoked-related potentials (ERPs) were qualitatively and quantitatively compared in order to examine the degree of consistency/discrepancy between softwares. Our findings show a good degree of convergence in terms of the general profile of ERP waveforms, peak latencies and effect size estimates related to specific signal features. However, considerable variability was also observed between software packages as reflected by the similarity values and observed statistical differences at particular channels and time instants. In conclusion, we believe that this study provides valuable clues to better understand the impact of the software tool on analysis results of EEG.



# StageEEGpre

dependencies:
Expand Down
Binary file added figures/figure1_preprocess.001.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 45 additions & 73 deletions src/BST/bsPreprocessing.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
% % --- This is the preprocessing workflow reproduced by Brainstorm functions---
% % For contact: [email protected]


% ======= CREATE PROTOCOL =======
% The protocol name has to be a valid folder name (no spaces, no weird characters...)
ProtocolName = 'Protocol_PreProc1';
ProtocolName = 'Protocol_PreProc';
% Start brainstorm without the GUI
if ~brainstorm('status')
brainstorm nogui
Expand All @@ -10,20 +14,21 @@
% Create new protocol
gui_brainstorm('CreateProtocol', ProtocolName, 0, 0);

cd('/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1'); %Find and change working folder to raw EEG data
cd('/Raw Data Part 1'); %Find and change working folder to raw EEG data
filenames = dir('*.vhdr')
nb=500;
trials_1=0;
trials_2=0;
load('/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1/set/Subject001/channelsTokeep.mat');
load('/Raw Data Part 1/set/Subject001/channelsTokeep.mat');
BS_db='Documents/brainstorm_db/'; %Changed this to the brainstorm_db directory

for participant =421:500 %Cycle through participants
for participant =1:nb %Cycle through participants

% Get participant name information
disp(['Participant: ', num2str(participant)]) %Display current participant being processed
participant_number = strsplit(filenames(participant).name(1:end-5),'_'); %Split filename into components

RawFile = ['/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1/set/Subject' participant_number{2} '/set_' participant_number{2} '.set'];
RawFile = ['/Raw Data Part 1/set/Subject' participant_number{2} '/set_' participant_number{2} '.set'];
SubjectName = ['participant_' participant_number{2}];

% Check if the folder contains the required files
Expand All @@ -39,12 +44,6 @@
'channelreplace', 0, ...
'channelalign', 0)



% % Input files
% sFiles = {...
% 'Subject01/@rawNDARAA075AMK/data_0raw_NDARAA075AMK.mat'};

% % Start a new report
bst_report('Start', sFiles);

Expand All @@ -54,7 +53,7 @@
'eegref', 'TP9, TP10', ...
'sensortypes', 'EEG');

% % % ==== bad channel identification ===
% % % ==== Bad channel identification ===
sFiles=bst_process('CallProcess', 'process_import_data_time', sFiles, [], ...
'subjectname', SubjectName, ...
'timewindow', []);
Expand All @@ -64,10 +63,11 @@
'timewindow', [], ...
'eeg', [10,2000],'rejectmode',1);

% interpolate the flat channels
% % % ==== Bad channel interpolation ===
sFiles=bst_process('CallProcess', 'process_eeg_interpbad', [sFilesInterp], []);

% % ====filtering====
% % ====Filtering====

% Process: Notch filter: 50Hz 100Hz 150Hz
sFiles = bst_process('CallProcess', 'process_notch', sFiles, [], ...
'sensortypes', 'EEG', ...
Expand All @@ -85,7 +85,7 @@
'attenuation', 'strict', ... % 60dB
'ver', '2019', ... % 2019
'mirror', 0, ...
'read_all', 0);
'read_all', 0);

% % ===== Epoching =====

Expand All @@ -99,54 +99,44 @@
'eventname', 'S110', ...
'timewindow', [], ...
'epochtime', [-0.5, 1.3], ...
'baseline', [-0.2, 0]);
'baseline', [-0.2, 0]);

sFilesEpochs2 = bst_process('CallProcess', 'process_import_data_event', sFiles, [], ...
'subjectname', SubjectName, ...
'eventname', 'S111', ...
'timewindow', [], ...
'epochtime', [-0.5, 1.3], ...
'baseline', [-0.2, 0]);
'baseline', [-0.2, 0]);

sFilesEpochs1 = bst_process('CallProcess', 'process_baseline', sFilesEpochs1, [],'baseline', [-0.2, 0])
sFilesEpochs2 = bst_process('CallProcess', 'process_baseline', sFilesEpochs2, [],'baseline', [-0.2, 0])

% % ===== trials detection =====
% % ===== Bad Trials detection =====
sFilesEpochs3=bst_process('CallProcess', 'process_detectbad', [sFilesEpochs1], [], ...
'timewindow', [], ...
'eeg', [0,100],'rejectmode',2);
% % for the second threshold

sFilesEpochs32=bst_process('CallProcess', 'process_detectbad', [sFilesEpochs1], [], ...
'timewindow', [], ...
'eeg', [0,200],'rejectmode',2);



%
sFilesEpochs4=bst_process('CallProcess', 'process_detectbad', [sFilesEpochs2], [], ...
'timewindow', [], ...
'eeg', [0,100],'rejectmode',2);
% % for the second threshold

sFilesEpochs42=bst_process('CallProcess', 'process_detectbad', [sFilesEpochs2], [], ...
'timewindow', [], ...
'eeg', [0,200],'rejectmode',2);

% % ===== erp computation =====
%
'eeg', [0,100],'rejectmode',2);

% % ===== ERP computation =====

sFilesAvg = bst_process('CallProcess', 'process_average', [sFilesEpochs3, sFilesEpochs4], [], ...
'avgtype', 5, ... % By trial groups (folder average)
'avg_func', 1, ... % Arithmetic average: mean(x)
'weighted', 0, ...
'keepevents', 1);
% % for the second threshold
sFilesAvg2 = bst_process('CallProcess', 'process_average', [sFilesEpochs32, sFilesEpochs42], [], ...
'avgtype', 5, ... % By trial groups (folder average)
'avg_func', 1, ... % Arithmetic average: mean(x)
'weighted', 0, ...
'keepevents', 1);
%
%
try
BS_db='/Users/ayakabbara/Documents/brainstorm_db/';
BS_db='Documents/brainstorm_db/';
dirr=[BS_db ProtocolName '/data/' sFilesAvg(1).FileName];

FF=load(dirr);
Expand All @@ -160,25 +150,7 @@
catch
% rem_part(end+1)=participant;
end

% % second threshold
try
BS_db='/Users/ayakabbara/Documents/brainstorm_db/';
dirr=[BS_db ProtocolName '/data/' sFilesAvg2(1).FileName];

FF=load(dirr);
if(size(FF,1)>32)
All_ERP_BS2(1,:,:,participant) = FF.F(ChannelsTokeep(1:29),151:750); %Store all the ERP data into a single variable
else
All_ERP_BS2(1,:,:,participant) = FF.F([1:9 11:20 22:31],151:750); %Store all the ERP data into a single variable

end
% trials_1=trials_1+sFilesAvg(1).iStudy;
catch
% rem_part(end+1)=participant;
end

BS_db='/Users/ayakabbara/Documents/brainstorm_db/';

try
dirr=[BS_db ProtocolName '/data/' sFilesAvg(2).FileName];
FF=load(dirr);
Expand All @@ -193,26 +165,26 @@
% rem_part(end+1)=participant;
end

% % second threshold
BS_db='/Users/ayakabbara/Documents/brainstorm_db/';
try
dirr=[BS_db ProtocolName '/data/' sFilesAvg2(2).FileName];
FF=load(dirr);
if(size(FF,1)>32)
All_ERP_BS2(2,:,:,participant) = FF.F(ChannelsTokeep(1:29),151:750); %Store all the ERP data into a single variable
else
All_ERP_BS2(2,:,:,participant) = FF.F([1:9 11:20 22:31],151:750); %Store all the ERP data into a single variable
end
catch
% rem_part(end+1)=participant;
end

% % ===delete subject for space issues
% bst_process('CallProcess', 'process_delete','subjectname', SubjectName)
end

% save('first500AllERP_BS','All_ERP_BS');
save('first500AllERP_BS2','All_ERP_BS2');
save('AllERP_BS','All_ERP_BS');

All_ERP=All_ERP(:,:,151:750,:).*1000000; % the unit in BS is in microVolts so it should be transfomed
channelOfInterest=26;

tt1=squeeze(All_ERP(1,channelOfInterest,:,:));
tt2=squeeze(All_ERP(2,channelOfInterest,:,:));



% save('fourT1','trials_1');
% save('fourT2','trials_2');
csvwrite('bs_RewP_Waveforms.csv',[(-200:2:998)',nanmean(squeeze(All_ERP(1,26,:,:)),2),nanmean(squeeze(All_ERP(2,26,:,:)),2),nanmean(squeeze(All_ERP(1,26,:,:)),2)-nanmean(squeeze(All_ERP(2,26,:,:)),2)]); %Export data. Conditions: Time, Loss, Win, Difference. Electrode 26 is FCz.
% %% RewP_Waveforms_AllPs
csvwrite('bs_RewP_Waveforms_AllPs.csv',[tt1,tt2]'); %Export data. Conditions: Loss, Win. Electrode 26 is FCz.
% %% RewP_Latency
[~,peak_loc] = max(squeeze(All_ERP(1,26,226:276,:))-squeeze(All_ERP(2,26,226:276,:))); %Determine where the peak amplitude is for each participant. Electrode 26 is FCz.
peak_loc = (((peak_loc+225)*2)-200)/1000; %Convert into seconds
peak_loc(toberemoved)=[];
csvwrite('bs_RewP_Latency.csv',peak_loc'); %Export data
16 changes: 8 additions & 8 deletions src/BST/toset.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
% EEGLAB history file generated on the 04-Jan-2022
% ------------------------------------------------
%
cd('/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1'); %Find and change working folder to raw EEG data
% % code to save .set file for each vhdr file
% % Contact: [email protected]

cd('/Raw Data Part 1'); %Find and change working folder to raw EEG data
filenames = dir('*.vhdr')
nb=500;
for participant = 1:nb %Cycle through participants
Expand All @@ -10,8 +10,8 @@
disp(['Participant: ', num2str(participant)]) %Display current participant being processed
participant_number = strsplit(filenames(participant).name(1:end-5),'_'); %Split filename into components
participant_varname = ['set_',participant_number{2}]; %Create new file name
EEG = pop_loadbv('/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1/', filenames(participant).name);
EEG = pop_loadbv('/Raw Data Part 1/', filenames(participant).name);
%ajouter chanlocs
EEG= pop_chanedit(EEG, 'lookup','/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/eeglab2021.1/functions/supportfiles/Standard-10-20-Cap81.ced');
save(['/Users/ayakabbara/Desktop/projects/EEG_PreProcessing/Raw Data Part 1/set/' participant_varname '.set'],'EEG');
end
EEG= pop_chanedit(EEG, 'lookup','/eeglab2021.1/functions/supportfiles/Standard-10-20-Cap81.ced');
save(['/Raw Data Part 1/set/' participant_varname '.set'],'EEG');
end
Loading

0 comments on commit b72de67

Please sign in to comment.