import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from scipy.fft import fft, ifft
Chapter 20
Chapter 20
Analyzing Neural Time Series Data
Python code for Chapter 20 – converted from original Matlab by AE Studio (and ChatGPT)
Original Matlab code by Mike X Cohen
This code accompanies the book, titled “Analyzing Neural Time Series Data” (MIT Press).
Using the code without following the book may lead to confusion, incorrect data analyses, and misinterpretations of results.
Mike X Cohen and AE Studio assume no responsibility for inappropriate or incorrect use of this code.
Import necessary libraries
Figure 20.1
# Load sample EEG data
= loadmat('../data/sampleEEGdata.mat')['EEG'][0, 0]
EEG
# Define channel to plot
= 'O1'
chan2plot
# Wavelet parameters
= 2
min_freq = 30
max_freq = 20
num_frex
# Baseline time window
= [-400, -100]
baseline_time
# Other wavelet parameters
= np.logspace(np.log10(min_freq), np.log10(max_freq), num_frex)
frequencies = np.arange(-1, 1 + 1/EEG['srate'][0][0], 1/EEG['srate'][0][0])
time = (len(time) - 1) // 2
half_of_wavelet_size
# FFT parameters
= len(time)
n_wavelet = EEG['pnts'][0][0] * EEG['trials'][0][0]
n_data = [n_wavelet + n_data - 1, n_wavelet + n_data - 1, n_wavelet + EEG['pnts'][0][0] - 1]
n_convolution
# Find sensor index
= EEG['chanlocs'][0]['labels']==chan2plot
sensoridx
# Compute ERP
= np.squeeze(np.mean(EEG['data'][sensoridx, :, :], axis=2))
erp
# Compute induced power by subtracting ERP from each trial
= np.squeeze(EEG['data'][sensoridx, :, :]) - erp[:, np.newaxis]
induced_EEG
# FFT of data
= [
fft_EEG 'data'][sensoridx, :, :].flatten('F'), n_convolution[0]), # total
fft(EEG['F'), n_convolution[1]), # induced
fft(induced_EEG.flatten(2]) # evoked
fft(erp, n_convolution[
]
# Convert baseline from ms to indices
= [np.argmin(np.abs(EEG['times'][0] - bt)) for bt in baseline_time]
baseline_idx
# Initialize output time-frequency data
= np.zeros((4, len(frequencies), EEG['pnts'][0][0]))
tf
for fi in range(len(frequencies)):
# Create wavelet
= np.exp(2 * 1j * np.pi * frequencies[fi] * time) * np.exp(-time**2 / (2 * (4 / (2 * np.pi * frequencies[fi]))**2)) / frequencies[fi]
wavelet
# Run convolution for each of total, induced, and evoked
for i in range(3):
# Take FFT of wavelet
= fft(wavelet, n_convolution[i])
fft_wavelet
# Convolution
= ifft(fft_wavelet * fft_EEG[i], n_convolution[i])
convolution_result_fft = convolution_result_fft[half_of_wavelet_size:-half_of_wavelet_size]
convolution_result_fft
# Reshaping and trial averaging is done only on all trials
if i < 2:
= np.reshape(convolution_result_fft, (EEG['pnts'][0][0], EEG['trials'][0][0]), 'F')
convolution_result_fft
# Compute power
= np.mean(np.abs(convolution_result_fft)**2, axis=1)
tf[i, fi, :] else:
# With only one trial-length, just compute power with no averaging
= np.abs(convolution_result_fft)**2
tf[i, fi, :]
# dB correct power
= 10 * np.log10(tf[i, fi, :] / np.mean(tf[i, fi, baseline_idx[0]:baseline_idx[1]+1]))
tf[i, fi, :]
# Inter-trial phase consistency on total EEG
if i == 0:
3, fi, :] = np.abs(np.mean(np.exp(1j * np.angle(convolution_result_fft)), axis=1))
tf[
# Analysis labels
= ['Total', 'Non-phase-locked', 'ERP power', 'ITPC']
analysis_labels
# Color limits
= [[-3, 3], [-3, 3], [-12, 12], [0, 0.6]]
clims
# Scale ERP for plotting
= (erp - np.min(erp)) / np.max(erp - np.min(erp))
erpt = erpt * (frequencies[-1] - frequencies[0]) + frequencies[0]
erpt
# Plotting
=(12, 8))
plt.figure(figsizefor i in range(4):
2, 3, i+1)
plt.subplot('times'][0], frequencies, tf[i, :, :], 40, cmap='viridis')
plt.contourf(EEG[
plt.clim(clims[i])-400, 1000])
plt.xlim([-200, 1000, 200))
plt.xticks(np.arange('Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel(
plt.title(analysis_labels[i])'times'][0], erpt, 'k')
plt.plot(EEG[
2, 3, 5)
plt.subplot('times'][0], frequencies, tf[0, :, :] - tf[1, :, :], 40, cmap='viridis')
plt.contourf(EEG[0])
plt.clim(clims[-400, 1000])
plt.xlim([-200, 1000, 200))
plt.xticks(np.arange('Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Phase-locked')
plt.title('times'][0], erpt, 'k')
plt.plot(EEG[
plt.tight_layout() plt.show()
=(10, 8))
plt.figure(figsize221)
plt.subplot(2, :, :].flatten(), tf[3, :, :].flatten(), '.')
plt.plot(tf['ERP power')
plt.xlabel('ITPC')
plt.ylabel(
222)
plt.subplot(0, :, :] - tf[1, :, :]).flatten(), tf[3, :, :].flatten(), '.')
plt.plot((tf['Phase-locked power')
plt.xlabel('ITPC')
plt.ylabel(-.3, 4])
plt.xlim([
223)
plt.subplot(0, :, :].flatten(), tf[1, :, :].flatten(), '.')
plt.plot(tf['Total power')
plt.xlabel('Non-phase-locked power')
plt.ylabel(-2, 6])
plt.xlim([-2, 6])
plt.ylim([
224)
plt.subplot(0, :, :] - tf[1, :, :]).flatten(), tf[2, :, :].flatten(), '.')
plt.plot((tf['Phase-locked power')
plt.xlabel('ERP power')
plt.ylabel(-.3, 4])
plt.xlim([
plt.tight_layout() plt.show()