Independent Component Analysis

Initialize NeuroAnalyzer
using NeuroAnalyzer
using Plots
eeg = load("files/eeg.hdf")

Independent Component Analysis (ICA) is a computational technique used to separate a complex signal like EEG into statistically independent subcomponents. ICA helps isolate artifacts (e.g., eye blinks, muscle activity) and neural sources from mixed EEG signals, enabling cleaner data for further analysis.

Key Concepts

  • Blind Source Separation: ICA is a “blind” technique because it doesn’t require prior knowledge of the source signals or mixing process
  • Statistical Independence: Components are maximally independent, not just uncorrelated (like PCA)
  • Non-Gaussian Sources: ICA works best when sources have non-Gaussian distributions
  • Linear Mixing: Assumes EEG channels are linear combinations of independent sources

Why Use ICA for EEG?

  • Artifact Correction: Removes non-brain signals (eye blinks, muscle noise, line noise)
  • Source Separation: Isolates neural sources for better analysis
  • Improved Signal Quality: Enhances the clarity of EEG data
  • Cognitive Neuroscience: Helps study brain networks and connectivity

ICA Workflow in NeuroAnalyzer

Understand the ICA Model

  • Original Signal (X): Your raw EEG data, a 10×2560 matrix (10 channels, 2560 time points).
  • Mixing Matrix (A): The matrix that mixes the independent components (ICs) to form the original signal. This is often called the weighting matrix or unmixing matrix in ICA literature. In your case, it’s a 10×5 matrix.
  • Independent Components (S): The 5×2560 matrix of components you obtained from ICA.

The relationship is:

\[ X = A \cdot S \]

where:
\(X\) is the original signal (10×2560),
\(A\) is the mixing matrix (10×5),
\(S\) is the matrix of independent components (5×2560).

Interpreting ICA Results

Component Types

  • Eye Blink Components: High variance, frontal topography, power in low frequencies (1-4 Hz)
  • Muscle Components: High frequency (20-60 Hz), concentrated at temporal sites
  • Line Noise Components: Narrow peak at power line frequency (50/60 Hz)
  • Heartbeat Components: Periodic activity around 1 Hz, often at temporal sites
  • Neural Components: Varied topography, specific frequency bands (alpha, beta, etc.)

Component Selection Criteria

  1. Variance Explained: Higher variance = more significant contribution
  2. Topography: Does the scalp distribution match known artifact patterns?
  3. Power Spectrum: Does the spectrum match known artifact characteristics?
  4. Temporal Characteristics: Does the time course show artifact patterns (e.g., blinks, muscle twitches)?

Common Artifacts

Artifact Type Characteristics
Eye Blinks Frontal topography, low frequency (1-4 Hz)
Eye Movements Lateral topography, low frequency
Muscle Activity High frequency (20-60 Hz), temporal sites
Line Noise Narrow peak at 50/60 Hz
ECG/Heartbeat Periodic, ~1 Hz, often at temporal sites

Best Practices and Tips

Data Requirements

  • Sampling Rate: At least 100-200 Hz for EEG ICA
  • Duration: Longer recordings (>2 minutes) provide better separation
  • Electrodes: Full-head coverage (32+ electrodes) works best
  • Preprocessing: High-pass filter at 1-2 Hz, remove line noise

ICA Parameters

  • Number of Components: Start with n_components = number of channels, then reduce
  • Algorithm: FastICA is generally reliable for EEG
  • Nonlinearity: tanh usually works well for EEG data
  • Iterations: 100-200 iterations are typically sufficient

Troubleshooting

  • Poor Separation: Try different preprocessing (filtering, referencing)
  • Too Many Components: Reduce n_components parameter
  • Unstable Results: Increase iterations or try different nonlinearity
  • Residual Artifacts: Check for components that may have been missed

Validation

  • Visual Inspection: Plot component topographies and time courses
  • Power Spectra: Check that components have expected frequency characteristics
  • Correlation: Check that removed components correlate with known artifact patterns
  • Reconstruction: Compare original and reconstructed signals

Comparison

ICA vs PCA vs Other Methods

Method Type Independence Use Case
ICA Blind Source Separation Statistical independence Artifact removal, source separation
PCA Dimensionality Reduction Uncorrelated components Noise reduction, feature extraction
SSD Source Separation Spatially smooth sources Blink/eye movement detection
Beamforming Source Localization Spatial filters Source localization

Key Differences:

  • ICA finds components that are statistically independent, while PCA finds components that are uncorrelated
  • ICA can separate artifacts from neural sources, while PCA cannot
  • ICA requires more data for stable results
  • ICA is more computationally intensive than PCA

ICA in Cognitive Neuroscience

Studying Brain Networks

  • ICA can identify resting-state networks from EEG data
  • Useful for analyzing task-related network dynamics
  • Helps study functional connectivity

Event-Related Potentials (ERPs)

  • ICA can isolate ERP components from background noise
  • Useful for studying P300, N400, and other ERP components
  • Helps separate stimulus-related activity from artifacts

Oscillatory Dynamics

  • ICA components can be used to study oscillatory activity
  • Helps analyze alpha, beta, gamma oscillations and their modulation
  • Useful for studying cross-frequency coupling

ICA Processing

Step 1: Decomposition

Deconstructing all EEG channels into defined number (3) of components:

ic, ic_mw, ic_var = ica_decompose(eeg, ch = "eeg", n = 3)

ic is the matrix of independent components and ic_mw is the mixing matrix.

Components are sorted in the order of decreasing variance (ic_var) accounted for (the higher the value, the higher the component accounts for all the data).

By default, 100 iterations per each tolerance value ([0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 0.5, 0.9, 0.99]); hence the default 100 iterations gives 900 steps.

Step 2: Component Selection

Sort components by variance explained (higher = more significant).

println("Variance explained by each component: ", round.(ic_var, digits=2))

Step 3: Reconstruction

To remove ICA (Independent Component Analysis) components from your EEG signal, you need to reconstruct the original signal without the unwanted components. Here’s a step-by-step explanation of the process:

Reconstruct the Signal Without Specific Components

To remove a component (say, component \(i\)), you set its row in \(S\) to zero and reconstruct \(X\):

\[ X_{\text{reconstructed}} = A \cdot S_{\text{modified}} \]

where \(S_{\text{modified}}\) is the matrix \(S\) with the \(i\)-th row set to zero.

Practical Steps

  1. Identify the components to remove: Decide which of the 5 components you want to remove (e.g., based on artifact analysis).
  2. Zero out the unwanted components: Create a modified SSS matrix where the rows corresponding to the unwanted components are set to zero.
  3. Reconstruct the signal: Multiply the mixing matrix \(A\) by the modified \(S\) to get the reconstructed signal without the unwanted components.

Result

The reconstructed signal \(X_{\text{reconstructed}}\) will be a 10×2560 matrix, just like your original signal, but with the unwanted components removed.

Reconstructing the source signal without a specific component(s):

ica_remove!(eeg,
            ch = "eeg",
            ic = ic,
            ic_mw = ic_mw,
            ic_idx = [1, 3])

To reconstruct the source signal keeping only the selected component(s), use keep=true option:

ica_remove!(eeg,
            ch = "eeg",
            ic = ic,
            ic_mw = ic_mw,
            ic_idx = 1,
            keep = true)

which is equivalent to

ica_remove!(eeg,
            ch = "eeg",
            ic = ic,
            ic_mw = ic_mw,
            ic_idx = [2, 3])

Visualizing ICA Components

Plotting the first components:

ica1 = ic[1, :]
NeuroAnalyzer.plot(eeg.time_pts,
                   ica1)

Plot the first component power spectrum:

psd_data = psd(ica1, fs = sr(eeg), db = true)
NeuroAnalyzer.plot_psd(psd_data.f,
                       psd_data.p,
                       xlabel = "Frequency [Hz]",
                       ylabel = "Power [dB]")

Plot the first component spectrogram:

spec_data = spectrogram(ica1, fs = sr(eeg), db = true)
NeuroAnalyzer.plot_spectrogram(spec_data.t,
                               spec_data.f,
                               spec_data.p,
                               xlabel = "Time [s]",
                               ylabel = "Frequency [Hz]")

Removing ECG artifacts using ICA

EEG has already been filtered at 1 Hz and 40 hz:

NeuroAnalyzer.plot(eeg,
                   ch="all",
                   gui = false)

Decompose all channels:

ic, ic_mw, ic_var = ica_decompose(eeg, ch = "all", n = 5)

Preview the first component:

ica1 = ic[1, :]
t1 = t2s(eeg, t = 0)
t2 = t2s(eeg, t = 10)
NeuroAnalyzer.plot(eeg.time_pts[t1:t2],
                   ica1[t1:t2])

Removing the first component:

eeg_clean = ica_remove(eeg,
                       ch = "all",
                       ic = ic,
                       ic_mw = ic_mw,
                       ic_idx = 1)

Comparing the original and processed signals:

NeuroAnalyzer.plot(eeg,
                   eeg_clean,
                   ch="all",
                   gui = false)