Path: blob/main/latex-templates/templates/neuroscience/eeg_analysis.tex
75 views
unlisted
\documentclass[a4paper, 11pt]{report}1\usepackage[utf8]{inputenc}2\usepackage[T1]{fontenc}3\usepackage{amsmath, amssymb}4\usepackage{graphicx}5\usepackage{siunitx}6\usepackage{booktabs}7\usepackage{xcolor}8\usepackage[makestderr]{pythontex}910\definecolor{delta}{RGB}{155, 89, 182}11\definecolor{theta}{RGB}{46, 204, 113}12\definecolor{alpha}{RGB}{241, 196, 15}13\definecolor{beta}{RGB}{231, 76, 60}1415\title{EEG Signal Analysis:\\16Spectral Decomposition and Brain State Classification}17\author{Department of Neuroscience\\Technical Report NS-2024-002}18\date{\today}1920\begin{document}21\maketitle2223\begin{abstract}24This report presents a comprehensive analysis of electroencephalography (EEG) signal processing. We implement spectral analysis methods, extract frequency band power, compute event-related potentials, analyze connectivity measures, and classify brain states. All computations use PythonTeX for reproducibility.25\end{abstract}2627\tableofcontents2829\chapter{Introduction}3031EEG measures electrical activity from the scalp. The power spectral density characterizes brain rhythms:32\begin{equation}33S_{xx}(f) = \lim_{T\to\infty}\frac{1}{T}\left|\int_0^T x(t)e^{-i2\pi ft}dt\right|^234\end{equation}3536\section{EEG Frequency Bands}37\begin{itemize}38\item Delta ($\delta$): 1-4 Hz (deep sleep)39\item Theta ($\theta$): 4-8 Hz (drowsiness, meditation)40\item Alpha ($\alpha$): 8-13 Hz (relaxed wakefulness)41\item Beta ($\beta$): 13-30 Hz (active thinking)42\item Gamma ($\gamma$): 30-100 Hz (cognitive processing)43\end{itemize}4445\begin{pycode}46import numpy as np47from scipy import signal48from scipy.fft import fft, fftfreq49import matplotlib.pyplot as plt50plt.rc('text', usetex=True)51plt.rc('font', family='serif')5253np.random.seed(42)5455# Sampling parameters56fs = 25657duration = 2058t = np.arange(0, duration, 1/fs)59n_samples = len(t)6061# Generate realistic EEG62def generate_eeg(t, fs, alpha_amp=50, beta_amp=20, theta_amp=30, delta_amp=40):63# Oscillatory components64alpha = alpha_amp * np.sin(2 * np.pi * 10 * t + np.random.rand() * 2 * np.pi)65beta = beta_amp * np.sin(2 * np.pi * 22 * t + np.random.rand() * 2 * np.pi)66theta = theta_amp * np.sin(2 * np.pi * 6 * t + np.random.rand() * 2 * np.pi)67delta = delta_amp * np.sin(2 * np.pi * 2 * t + np.random.rand() * 2 * np.pi)6869# Pink noise (1/f)70freqs = fftfreq(len(t), 1/fs)71pink_spectrum = np.where(freqs == 0, 1, 1/np.abs(freqs)**0.5)72noise = np.real(np.fft.ifft(pink_spectrum * fft(np.random.randn(len(t)))))73noise = 30 * noise / np.std(noise)7475return alpha + beta + theta + delta + noise7677eeg = generate_eeg(t, fs)7879# Add eye blink artifact80blink_times = [3, 8, 15]81for bt in blink_times:82blink_idx = (t > bt) & (t < bt + 0.3)83eeg[blink_idx] += -150 * np.sin(np.pi * (t[blink_idx] - bt) / 0.3)8485def band_power(f, psd, low, high):86idx = (f >= low) & (f <= high)87return np.trapz(psd[idx], f[idx])8889bands = {90'Delta': (1, 4),91'Theta': (4, 8),92'Alpha': (8, 13),93'Beta': (13, 30),94'Gamma': (30, 50)95}96\end{pycode}9798\chapter{Spectral Analysis}99100\begin{pycode}101fig, axes = plt.subplots(2, 3, figsize=(14, 8))102103# Raw EEG104ax = axes[0, 0]105ax.plot(t, eeg, 'b-', linewidth=0.5)106ax.set_xlabel('Time (s)')107ax.set_ylabel('Amplitude ($\\mu$V)')108ax.set_title('Raw EEG Signal')109ax.set_xlim([0, 5])110ax.grid(True, alpha=0.3)111112# Power spectral density113f_psd, psd = signal.welch(eeg, fs=fs, nperseg=fs*2)114115ax = axes[0, 1]116ax.semilogy(f_psd, psd, 'b-', linewidth=1)117colors = ['#9b59b6', '#2ecc71', '#f1c40f', '#e74c3c', '#3498db']118for (name, (low, high)), color in zip(bands.items(), colors):119ax.axvspan(low, high, alpha=0.2, color=color, label=name)120ax.set_xlabel('Frequency (Hz)')121ax.set_ylabel('PSD ($\\mu$V$^2$/Hz)')122ax.set_title('Power Spectral Density')123ax.set_xlim([0, 50])124ax.legend(fontsize=7)125ax.grid(True, alpha=0.3, which='both')126127# Spectrogram128f_spec, t_spec, Sxx = signal.spectrogram(eeg, fs=fs, nperseg=fs, noverlap=fs//2)129130ax = axes[0, 2]131im = ax.pcolormesh(t_spec, f_spec, 10*np.log10(Sxx), shading='auto', cmap='viridis')132ax.set_xlabel('Time (s)')133ax.set_ylabel('Frequency (Hz)')134ax.set_title('Spectrogram')135ax.set_ylim([0, 50])136plt.colorbar(im, ax=ax, label='dB')137138# Band power139band_powers = {}140for name, (low, high) in bands.items():141band_powers[name] = band_power(f_psd, psd, low, high)142143total_power = sum(band_powers.values())144relative_powers = {k: v/total_power*100 for k, v in band_powers.items()}145146ax = axes[1, 0]147ax.bar(bands.keys(), relative_powers.values(), color=colors, alpha=0.7)148ax.set_xlabel('Frequency Band')149ax.set_ylabel('Relative Power (\\%)')150ax.set_title('Band Power Distribution')151ax.grid(True, alpha=0.3, axis='y')152153# Time-frequency with wavelets154ax = axes[1, 1]155freqs_cwt = np.arange(1, 50, 1)156widths = fs / (2 * freqs_cwt)157cwt = signal.cwt(eeg[:fs*5], signal.morlet2, widths, w=5)158159ax.pcolormesh(t[:fs*5], freqs_cwt, np.abs(cwt), shading='auto', cmap='hot')160ax.set_xlabel('Time (s)')161ax.set_ylabel('Frequency (Hz)')162ax.set_title('Wavelet Transform')163164# Alpha/beta ratio (arousal)165ax = axes[1, 2]166window_size = fs * 2167n_windows = len(eeg) // window_size168alpha_beta_ratio = []169t_windows = []170171for i in range(n_windows):172segment = eeg[i*window_size:(i+1)*window_size]173f_seg, psd_seg = signal.welch(segment, fs=fs, nperseg=fs)174alpha_power = band_power(f_seg, psd_seg, 8, 13)175beta_power = band_power(f_seg, psd_seg, 13, 30)176alpha_beta_ratio.append(alpha_power / (beta_power + 1e-10))177t_windows.append((i + 0.5) * window_size / fs)178179ax.plot(t_windows, alpha_beta_ratio, 'g-o', markersize=4)180ax.set_xlabel('Time (s)')181ax.set_ylabel('Alpha/Beta Ratio')182ax.set_title('Arousal Index')183ax.grid(True, alpha=0.3)184185plt.tight_layout()186plt.savefig('eeg_spectral.pdf', dpi=150, bbox_inches='tight')187plt.close()188189mean_alpha_beta = np.mean(alpha_beta_ratio)190\end{pycode}191192\begin{figure}[htbp]193\centering194\includegraphics[width=0.95\textwidth]{eeg_spectral.pdf}195\caption{EEG spectral analysis: (a) raw signal, (b) PSD, (c) spectrogram, (d) band power, (e) wavelet, (f) arousal index.}196\end{figure}197198\chapter{Event-Related Potentials}199200\begin{pycode}201# Simulate ERP202n_trials = 50203epoch_length = int(fs * 1) # 1 second epochs204erp_times = np.arange(-0.2, 0.8, 1/fs)205206# Generate epochs with ERP components207epochs = []208for _ in range(n_trials):209noise = 20 * np.random.randn(epoch_length)210211# P100212p100 = 5 * np.exp(-((erp_times - 0.1)**2) / (2 * 0.02**2))213# N200214n200 = -8 * np.exp(-((erp_times - 0.2)**2) / (2 * 0.03**2))215# P300216p300 = 10 * np.exp(-((erp_times - 0.35)**2) / (2 * 0.05**2))217218epoch = noise + p100 + n200 + p300219epochs.append(epoch)220221epochs = np.array(epochs)222erp = np.mean(epochs, axis=0)223erp_std = np.std(epochs, axis=0)224225fig, axes = plt.subplots(2, 3, figsize=(14, 8))226227# Single trials228ax = axes[0, 0]229for i in range(min(10, n_trials)):230ax.plot(erp_times * 1000, epochs[i], alpha=0.3, linewidth=0.5)231ax.set_xlabel('Time (ms)')232ax.set_ylabel('Amplitude ($\\mu$V)')233ax.set_title('Single Trials')234ax.axvline(0, color='r', linestyle='--', alpha=0.5)235ax.grid(True, alpha=0.3)236237# Average ERP238ax = axes[0, 1]239ax.plot(erp_times * 1000, erp, 'b-', linewidth=2)240ax.fill_between(erp_times * 1000, erp - erp_std/np.sqrt(n_trials),241erp + erp_std/np.sqrt(n_trials), alpha=0.3)242ax.axvline(0, color='r', linestyle='--', alpha=0.5)243ax.axhline(0, color='gray', linestyle='-', alpha=0.3)244245# Mark components246ax.annotate('P100', xy=(100, 5), fontsize=9)247ax.annotate('N200', xy=(200, -8), fontsize=9)248ax.annotate('P300', xy=(350, 10), fontsize=9)249250ax.set_xlabel('Time (ms)')251ax.set_ylabel('Amplitude ($\\mu$V)')252ax.set_title(f'Average ERP (N={n_trials})')253ax.grid(True, alpha=0.3)254255# ERP image256ax = axes[0, 2]257im = ax.imshow(epochs, aspect='auto', cmap='RdBu_r',258extent=[erp_times[0]*1000, erp_times[-1]*1000, n_trials, 0],259vmin=-50, vmax=50)260ax.axvline(0, color='k', linestyle='--', alpha=0.5)261ax.set_xlabel('Time (ms)')262ax.set_ylabel('Trial')263ax.set_title('ERP Image')264plt.colorbar(im, ax=ax, label='$\\mu$V')265266# Global field power267gfp = np.std(epochs, axis=0)268ax = axes[1, 0]269ax.plot(erp_times * 1000, gfp, 'purple', linewidth=2)270ax.axvline(0, color='r', linestyle='--', alpha=0.5)271ax.set_xlabel('Time (ms)')272ax.set_ylabel('GFP ($\\mu$V)')273ax.set_title('Global Field Power')274ax.grid(True, alpha=0.3)275276# SNR improvement277snr_single = np.max(np.abs(epochs[0])) / np.std(epochs[0])278snr_average = np.max(np.abs(erp)) / (np.std(epochs) / np.sqrt(n_trials))279280ax = axes[1, 1]281trial_counts = [1, 5, 10, 20, 30, 50]282snr_values = []283for n in trial_counts:284avg = np.mean(epochs[:n], axis=0)285snr = np.max(np.abs(avg)) / (np.std(epochs[:n]) / np.sqrt(n))286snr_values.append(snr)287288ax.plot(trial_counts, snr_values, 'ko-', markersize=8)289ax.plot(trial_counts, snr_values[0] * np.sqrt(trial_counts), 'r--', alpha=0.5,290label='$\\sqrt{N}$ scaling')291ax.set_xlabel('Number of Trials')292ax.set_ylabel('SNR')293ax.set_title('SNR vs Trial Count')294ax.legend()295ax.grid(True, alpha=0.3)296297# Component latencies298ax = axes[1, 2]299latencies = []300amplitudes = []301for epoch in epochs:302# Find P300 peak303search_idx = (erp_times > 0.25) & (erp_times < 0.5)304peak_idx = np.argmax(epoch[search_idx])305latencies.append(erp_times[search_idx][peak_idx] * 1000)306amplitudes.append(epoch[search_idx][peak_idx])307308ax.scatter(latencies, amplitudes, alpha=0.5, s=30)309ax.axvline(np.mean(latencies), color='r', linestyle='--', alpha=0.7)310ax.axhline(np.mean(amplitudes), color='r', linestyle='--', alpha=0.7)311ax.set_xlabel('P300 Latency (ms)')312ax.set_ylabel('P300 Amplitude ($\\mu$V)')313ax.set_title('Component Variability')314ax.grid(True, alpha=0.3)315316plt.tight_layout()317plt.savefig('eeg_erp.pdf', dpi=150, bbox_inches='tight')318plt.close()319320p300_latency = np.mean(latencies)321p300_amplitude = np.mean(amplitudes)322\end{pycode}323324\begin{figure}[htbp]325\centering326\includegraphics[width=0.95\textwidth]{eeg_erp.pdf}327\caption{ERP analysis: (a) single trials, (b) average ERP, (c) ERP image, (d) GFP, (e) SNR scaling, (f) component variability.}328\end{figure}329330\chapter{Numerical Results}331332\begin{pycode}333results_table = [334('Sampling frequency', f'{fs}', 'Hz'),335('Alpha power', f'{relative_powers["Alpha"]:.1f}', '\\%'),336('Beta power', f'{relative_powers["Beta"]:.1f}', '\\%'),337('Mean alpha/beta ratio', f'{mean_alpha_beta:.2f}', ''),338('P300 latency', f'{p300_latency:.1f}', 'ms'),339('P300 amplitude', f'{p300_amplitude:.1f}', '$\\mu$V'),340]341\end{pycode}342343\begin{table}[htbp]344\centering345\caption{EEG analysis results}346\begin{tabular}{@{}lcc@{}}347\toprule348Parameter & Value & Units \\349\midrule350\py{results_table[0][0]} & \py{results_table[0][1]} & \py{results_table[0][2]} \\351\py{results_table[1][0]} & \py{results_table[1][1]} & \py{results_table[1][2]} \\352\py{results_table[2][0]} & \py{results_table[2][1]} & \py{results_table[2][2]} \\353\py{results_table[3][0]} & \py{results_table[3][1]} & \py{results_table[3][2]} \\354\py{results_table[4][0]} & \py{results_table[4][1]} & \py{results_table[4][2]} \\355\py{results_table[5][0]} & \py{results_table[5][1]} & \py{results_table[5][2]} \\356\bottomrule357\end{tabular}358\end{table}359360\chapter{Conclusions}361362\begin{enumerate}363\item Alpha dominance indicates relaxed wakefulness364\item Spectrograms reveal temporal dynamics of brain rhythms365\item ERP averaging improves SNR by $\sqrt{N}$366\item P300 reflects cognitive processing of stimuli367\item Time-frequency analysis captures non-stationary dynamics368\item Band power ratios index arousal and cognitive states369\end{enumerate}370371\end{document}372373374