Decomposing an EEG Signal from Scratch

TheCedarPrince
Thu, 20 Jun 2024 06:05:53 +0000
General Usage

Hey folks!

I’ve been recently tinkering with decomposing some EEG data into various visualizations and want to make sure I am going about things the right way (the data using is openly available from here). Here is how I approached processing some of this EEG data as well as questions I had at the end.

Minor Data Prep

First, as the data was in fdt files, I wrote my own parser to read it (this is where raw channel level data comes from):
fdt Parser (click for more details)
Then, I loaded up the .set and .fdt files to have as a reference for the session recording that I was analyzing. This was pretty straightforward:
Loading Data (click for more details)
Visualizing Electrode Positions

This session recorded EEG signal across 61 different channels (i.e. electrodes). For a quick visualization of that, I used TopoPlot.jl by @behinger which gave the following photo (code is below the photo):

Topoplot Code (click for more details)
Quick Data Preview

For the next parts of this work, I decided to only use 1 channel for my analysis as I thought I could scale up complexity later (i.e. analyzing and averages all channels together later). To get a sense of the signal on this channel, I did a quick plot of the voltage amplitude recorded (measured in \mu V); here’s that plot (with code below):

Raw Voltage Plot (click for more details)
Signal Decomposition

After this, I get to the part that is the most challenging for me – decomposing the signal into different bands (i.e. delta, theta, alpha, beta, and gamma). This part is where I could use the most checking. How I first went about this was to use DSP.jl to compute a Welsh Periodogram of the time series:

s = welch_pgram(channel_data[1, :], fs = 500)

f = s.freq
p = s.power

Then, taking liberal usage of Prof. Makoto Miyakoshi’s notes, I think I somewhat figured out how to extract the bands after translating some MATLAB ideas into Julia. Here is how I approached it:

delta = findall(x -> x>=0 && x<4, f);
theta = findall(x -> x>=4 && x<8, f);
alpha = findall(x -> x>=8 && x<12, f);
beta = findall(x -> x>=12 && x<30, f);
gamma = findall(x -> x>=30 && x<200, f);

And with these parts segmented out, I created the following plot here:

Segmented Wave Bands (click for more details)
Additionally, I created a Power Spectral Density plot as follows for additional visualization (with some aesthetic banding for easier viewing):

Abbreviated, Banded PSD Plot (click for more details)

Note: I cut off the gamma band in this particular diagram prematurely as it resulted in a rather “scrunched up” graphic. This was purely for presentation purposes.

Outstanding Questions

I hope that more or less made sense so far! It was somewhat tough tracking down these methods outside of established software (like MATLAB’s EEGLAB or Python’s MNE-Python). I definitely could have made errors so far and that leads me to outstanding questions I had from this work so far:

First, in the plot where I segmented out the different regions, I am unsure how to make a visualization like this:

As one can see, the different bands of one signal are all somehow harmonized against the same x-axis. My segmented one is not. How can I make a plot like this?

Second, are the methods I have used so far to extract the bands correct? I tried creating a nice bandpass filter with DSP.jl but couldn’t get it to work so just opted to directly use the Welch Periodogram function that comes with DSP.jl instead. Would there be a better way to do things here?

Third, is it often standard practice to take the mean of signals across all channels over time when computing brainwaves? In my readings, it seems like that is one way to do it to aggregate occurrences across the entire recording during a session but was curious what else folks do.

Thanks all!

~ tcp

23 posts - 9 participants