Version 1.0.0
This repository is the original implementation of ARMBR:
Artifact-Reference Multivariate Backward Regression (ARMBR) Outperforms Common EEG Blink Artifact Removal Methods
by Ludvik Alkhoury, Giacomo Scanavini, Samuel Louviot, Ana Radanovic, Sudhin A. Shah, and N. Jeremy Hill
Below, we provide instructions on how to:
- download the package
- implement the code in Matlab and Python
You can download the package directly from this repository. If so, we recommend downloading a stable release.
Alternatively, you can use git:
- Select a directory to save this repository to. This can be done by creating a directory on your Desktop (for example: C:/MyPC/Desktop/GitRepo/). Open the Git bash and type:
cd "C:/MyPC/Desktop/GitRepo/"
- Download (clone) this repository in the directory that we previously created. This can be done by opening Git bash inside the directory we just created (for example: C:/MyPC/Desktop/GitRepo/) and typing:
git clone "https://github.com/S-Shah-Lab/ARMBR.git"
and then go the repository directory by typing:
cd ARMBR/
- Now that you have the repository, run setup.py to install all dependent packages:
python -m pip install -e ./Python
ARMBR can be used in Python as follows. First, make sure that your working directory is Maltab
.
Here is how to implement ARMBR using Matlab on the semi-synthetic data used in the paper. This implementation will work with any EEG array.
clc; clear; close all;
fs = 128; % Set sampling rate
sub = 1; % Set subject number
% Load clean and blink-contaminated EEG signals
Clean_EEG = load("..\SemiSyntheticData\Sub"+num2str(sub)+"\Sub"+num2str(sub)+"_Clean_EEG.mat").Clean_EEG;
Sythentic_Blink_Contaminated_EEG = load("..\SemiSyntheticData\Sub"+num2str(sub)+"\Sub"+num2str(sub)+"_Synthetic_Blink_Contaminated_EEG.mat").Sythentic_Blink_Contaminated_EEG;
% Bandpass filter the data from 1 to 40
Sythentic_Blink_Contaminated_EEG = BPF(Sythentic_Blink_Contaminated_EEG, fs, [1 40]);
Clean_EEG = BPF(Clean_EEG, fs, [1 40]);
% Run ARMBR
ref_chan_nbr = [80, 93]; %indices for Fp1 and Fp2
[ARMBR_EEG, Set_IQR_Thresh, Blink_Ref, Blink_Artifact, BlinkSpatialPattern] = ARMBR(Sythentic_Blink_Contaminated_EEG, ref_chan_nbr, fs);
% Compute performance metrics
[PearCorr, RMSE, SNR] = PerformanceMetrics(Clean_EEG, ARMBR_EEG);
% Display computed metrics
disp(['========================================='])
disp(['Pearson correlation for subject ',num2str(sub),': ', num2str(round(mean(PearCorr), 2))])
disp(['SNR for subject ',num2str(sub),': ', num2str(round(mean(SNR), 2))])
disp(['RMSE for subject ',num2str(sub),': ', num2str(round(mean(RMSE), 2))])
disp(['========================================='])
Here, make sure you install EEGLAB and add the path to your directory.
We will create an EEGLAB structure and apply ARMBR to the EEG structure using pop_ARMBR
. The blink spatial pattern can be accessed from the EEG structure: EEG.BlinkSpatialPattern
. You can use the already-trained blink spatial pattern on new EEG data. This is done by: EEG_without_Blinks = EEG_with_Blinks * BlinkSpatialPattern;
.
clc
close all
clear
fs = 128; % Set sampling rate
sub = 1; % Set subject number
% Load clean and blink-contaminated EEG signals
Clean_EEG = load("..\SemiSyntheticData\Sub"+num2str(sub)+"\Sub"+num2str(sub)+"_Clean_EEG.mat").Clean_EEG;
Sythentic_Blink_Contaminated_EEG = load("..\SemiSyntheticData\Sub"+num2str(sub)+"\Sub"+num2str(sub)+"_Synthetic_Blink_Contaminated_EEG.mat").Sythentic_Blink_Contaminated_EEG;
% Bandpass filter the data from 1 to 40
Sythentic_Blink_Contaminated_EEG = BPF(Sythentic_Blink_Contaminated_EEG, fs, [1 40]);
Clean_EEG = BPF(Clean_EEG, fs, [1 40]);
EEG = pop_importdata('dataformat','matlab','nbchan',128,'data', Sythentic_Blink_Contaminated_EEG', 'srate',fs, 'chanlocs','Biosemi128.ced');
eeglab redraw
blink_chan = ["C16", "C29"]; %or you can use blink_chan = [80, 93]; the index number
[EEG] = pop_ARMBR(EEG, blink_chan);
% Compute performance metrics
[PearCorr, RMSE, SNR] = PerformanceMetrics(Clean_EEG, EEG.data);
% Display computed metrics
disp(['========================================='])
disp(['Pearson correlation for subject ',num2str(sub),': ', num2str(round(mean(PearCorr), 2))])
disp(['SNR for subject ',num2str(sub),': ', num2str(round(mean(SNR), 2))])
disp(['RMSE for subject ',num2str(sub),': ', num2str(round(mean(RMSE), 2))])
disp(['========================================='])
ARMBR can be used in Python as follows. First, make sure that your working directory is Python
.
Open your terminal and use one of the following commands:
If you want to use the indices of the blink reference channels then use below, where -c "79, 92" represents indices 79 and 92:
python -m ARMBR -p "..\SemiSyntheticData\Sub1\Sub1_Synthetic_Blink_Contaminated_EEG.fif" -c "79,92" --plot
If you want to use the name of the blink reference channels then use below, where -c "C16,C29" represents channel name C16 and C29:
python -m ARMBR -p "..\SemiSyntheticData\Sub1\Sub1_Synthetic_Blink_Contaminated_EEG.fif" -c "C16,C29" --plot
At this point, this command line supports data of .fif, .edf, and .dat type.
You can use a numpy array EEG with ARMBR. Here is a script:
from ARMBR.ARMBR_Library import *
import mne
import matplotlib.pyplot as plt
EEG_Blink = np.array([.....])
Clean = np.array([.....])
fs = 128
ChannelsName = ['EEG1', EEG2', ...'EEGn']
myARMBR = ARMBR(EEG=EEG_w_Blink,
Fs=fs,
ChannelsName=ChannelsName,
EEGGT=Clean)
myARMBR.ARMBR(blink_chan=['EEG1','EEG2']).PerformanceMetrics().DispMetrics().Plot()
in this script EEGGT
is the EEG ground truth if you are working with synthetic signals or you know what the signal should look like without blinks.
When EEGGT
is available, you can run methods like PerformanceMetrics()
and DispMetrics()
. PerformanceMetrics()
will compute the Pearson correlation, RMSE, and SNR for all channels. DispMetrics()
will display an average across channels.
You can also use ARMBR with mne raw objects. Below is a script.
You can extract the blink spatial pattern from the ARMBR object, myARMBR
, using myARMBR.BlinkSpatialPattern
.
This pattern can be applied to another EEG dataset. First, create an ARMBR object for the second EEG dataset, denoted myARMBR2
.
Now apply the spatial pattern computed from the original EEG signal:
myARMBR2.ApplyBlinkSpatialPattern(myARMBR.BlinkSpatialPattern)
from ARMBR.ARMBR_Library import *
import mne
import matplotlib.pyplot as plt
raw = mne.io.read_raw_fif("..\SemiSyntheticData\Sub1\Sub1_Synthetic_Blink_Contaminated_EEG.fif", preload=True)
raw.filter(l_freq=1, h_freq=40)
myARMBR = ARMBR()
myARMBR.ImportFromRaw(raw)
myARMBR.ARMBR(blink_chan=['C16','C29'])
myARMBR.UnloadIntoRaw(raw)
raw.plot()
plt.show()
# raw.save("SAVE_PATH.fif")
With this code you can process the raw data using ARMBR and load it back to the raw object.
Below is an example showing the blink contaminated region of a subject 1 before and after running ARMBR: