import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat
from scipy.fftpack import fft, ifft
from scipy.stats import zscore
Chapter 18
Chapter 18
Analyzing Neural Time Series Data
Python code for Chapter 18 – 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 18.1
# 1/f function
= 1
c = 1
x / np.arange(1, 101)**x)
plt.plot(c 0, 100])
plt.xlim([0, 1])
plt.ylim([ plt.show()
Figure 18.2
# Load sample EEG data
= loadmat('../data/sampleEEGdata.mat')['EEG'][0, 0]
EEG
# Wavelet parameters
= 2
min_freq = 128
max_freq = 30
num_frex
# Other wavelet parameters
= np.logspace(np.log10(min_freq), np.log10(max_freq), num_frex)
frequencies = np.arange(-1, 1 + 1/EEG['srate'], 1/EEG['srate'])
time = (len(time) - 1) // 2
half_of_wavelet_size
# FFT parameters
= len(time)
n_wavelet = EEG['pnts'][0][0]
n_data = n_wavelet + n_data - 1
n_convolution = int(2**np.ceil(np.log2(n_convolution)))
n_conv_pow2 = 4
wavelet_cycles
# FFT of data (note: this doesn't change on frequency iteration)
= fft(EEG['data'][22, :, 0], n_conv_pow2)
fft_data
# Initialize output time-frequency data
= np.zeros((len(frequencies), EEG['pnts'][0][0]))
tf_data
for fi in range(len(frequencies)):
# Create wavelet and get its FFT
= (np.pi * frequencies[fi] * np.sqrt(np.pi))**-0.5 * np.exp(2 * 1j * np.pi * frequencies[fi] * time) * np.exp(-time**2 / (2 * (wavelet_cycles / (2 * np.pi * frequencies[fi]))**2)) / frequencies[fi]
wavelet = fft(wavelet, n_conv_pow2)
fft_wavelet
# Run convolution
= ifft(fft_wavelet * fft_data, n_conv_pow2)
convolution_result_fft = convolution_result_fft[:n_convolution]
convolution_result_fft = convolution_result_fft[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft
# Put power data into time-frequency matrix
= np.abs(convolution_result_fft)**2
tf_data[fi, :]
# Plot results
=(10, 8))
plt.figure(figsize= np.arange(2, num_frex+4, 4)
ytickskip
# Subplot 1
221)
plt.subplot(='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(tf_data, aspect0, 5000)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.'Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel(
plt.gca().invert_yaxis()'Color limit of 0 to 5000')
plt.title(
# Subplot 2
222)
plt.subplot(='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(tf_data, aspect0, 800)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Color limit of 0 to 800')
plt.title(
# Subplot 3
223)
plt.subplot(='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(tf_data, aspect0, 25)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Color limit of 0 to 25')
plt.title(
# Subplot 4
224)
plt.subplot(='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(np.log10(tf_data), aspect-4, 4)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Color limit of -4 to 4 (log10 units)')
plt.title(
plt.tight_layout() plt.show()
Figure 18.3
# Define baseline period
= [-500, -200] # in ms
baselinetime
# Convert baseline window time to indices
= [np.argmin(np.abs(EEG['times'][0] - bt)) for bt in baselinetime]
baselineidx
# dB-correct
= np.mean(tf_data[:, baselineidx[0]:baselineidx[1]+1], axis=1)
baseline_power = 10 * np.log10(tf_data / baseline_power[:, np.newaxis])
dbconverted
# Plot
=(8, 6))
plt.figure(figsize'times'][0], frequencies, dbconverted, 40, cmap='viridis')
plt.contourf(EEG[-12, 12)
plt.clim(-500, 1500])
plt.xlim(['Color limit of -12 to +12 dB')
plt.title('log')
plt.yscale(= np.round(np.logspace(np.log10(frequencies[0]),np.log10(frequencies[-1]),10)*100)/100
ylabels
plt.yticks(ylabels, ylabels) plt.show()
Figure 18.4
# Time to plot
= 300 # in ms
time2plot
# Find the index of the time to plot
= np.argmin(np.abs(EEG['times'][0] - time2plot))
timeidx
# Plot frequencies
=(10, 6))
plt.figure(figsize
# Subplot 1: Raw power
211)
plt.subplot(
plt.plot(frequencies, tf_data[:, timeidx])f'Power spectrum at {EEG["times"][0][timeidx]:.4f} ms')
plt.title(0, 140])
plt.xlim([0, 600])
plt.ylim(['Raw power (uV^2)')
plt.ylabel('Frequency (Hz)')
plt.xlabel(
# Subplot 2: Baseline-normalized power
212)
plt.subplot(
plt.plot(frequencies, dbconverted[:, timeidx])0, 140])
plt.xlim([-20, 5])
plt.ylim(['Baseline-normalized power (dB)')
plt.ylabel('Frequency (Hz)')
plt.xlabel(
plt.tight_layout() plt.show()
## Figure 18.5
# This figure was created by changing the color limits of figure 18.3
Figure 18.6
# Activity and baseline
= np.arange(1, 20.001, 0.01)
activity = 10
baseline
# Compute dB and percent change
= 10 * np.log10(activity / baseline)
db = 100 * (activity - baseline) / baseline
pc
# Plot
=(8, 6))
plt.figure(figsize
plt.plot(db, pc)-10, 4])
plt.xlim([-100, 100])
plt.ylim(['dB')
plt.xlabel('Percent change')
plt.ylabel(
# Find indices where db is closest to -/+2
= np.argmin(np.abs(db - 2))
dbOf2 = np.argmin(np.abs(db - (-2)))
dbOfminus2
print(f'dB of -2 corresponds to {pc[dbOfminus2]:.1f}% change.')
print(f'dB of +2 corresponds to +{pc[dbOf2]:.1f}% change.')
=db[dbOf2], color='k', linestyle='--')
plt.axvline(x=pc[dbOf2], color='k', linestyle='--')
plt.axhline(y=db[dbOfminus2], color='k', linestyle='--')
plt.axvline(x=pc[dbOfminus2], color='k', linestyle='--')
plt.axhline(y
'Relationship between dB and Percent Change')
plt.title(
plt.show()
# Real data: percent change vs. baseline division
=(12, 10))
plt.figure(figsize
# Baseline power and percent change
= np.mean(tf_data[:, baselineidx[0]:baselineidx[1]+1], axis=1)
baseline_power = 100 * (tf_data - baseline_power[:, np.newaxis]) / baseline_power[:, np.newaxis]
pctchange
# Subplot 1: Baseline division
221)
plt.subplot(= tf_data / baseline_power[:, np.newaxis]
baselinediv 'F')[::5], baselinediv.flatten('F')[::5], '.')
plt.plot(dbconverted.flatten(-40, 10])
plt.xlim([0, 7])
plt.ylim(['DB')
plt.xlabel('Baseline division')
plt.ylabel(
# Subplot 2: dB vs. baseline division
222)
plt.subplot('F')[::5], baselinediv.flatten('F')[::5], '.')
plt.plot(pctchange.flatten(-200, 600])
plt.xlim([0, 7])
plt.ylim(['Percent change')
plt.xlabel('Baseline division')
plt.ylabel(
# Subplot 3: Z-transform vs. percent change
223)
plt.subplot(= (tf_data - baseline_power[:, np.newaxis]) / np.std(tf_data[:, baselineidx[0]:baselineidx[1]+1], axis=1, ddof=1)[:, np.newaxis]
baselineZ 'F')[::5], pctchange.flatten('F')[::5], '.')
plt.plot(baselineZ.flatten(-40, 10])
plt.xlim([-100, 600])
plt.ylim(['Z-transform')
plt.xlabel('Percent change')
plt.ylabel(
# Subplot 4: Z-transform vs. dB
224)
plt.subplot('F')[::5], dbconverted.flatten('F')[::5], '.')
plt.plot(baselineZ.flatten(-40, 10])
plt.xlim([-40, 10])
plt.ylim(['Z-transform')
plt.xlabel('DB')
plt.ylabel(
plt.tight_layout() plt.show()
dB of -2 corresponds to -36.9% change.
dB of +2 corresponds to +58.5% change.
Figure 18.7
# Plot dB-converted power, percent-change, divide by baseline, and z-transform
=(12, 10))
plt.figure(figsize
# Subplot 1: dB change from baseline
221)
plt.subplot(='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(dbconverted, aspect-10, 10)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'dB change from baseline')
plt.title(
# Subplot 2: Percent change from baseline
222)
plt.subplot(= 100 * (tf_data - baseline_power[:, np.newaxis]) / baseline_power[:, np.newaxis]
pctchange ='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(pctchange, aspect-500, 500)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Percent change from baseline')
plt.title(
# Subplot 3: Divide by baseline
223)
plt.subplot(= tf_data / baseline_power[:, np.newaxis]
baselinediv ='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(baselinediv, aspect-7.5, 7.5)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Divide by baseline')
plt.title(
# Subplot 4: Z-transform
224)
plt.subplot(= zscore(tf_data, axis=1, ddof=1)
baselineZ ='auto', extent=[EEG['times'][0][0], EEG['times'][0][-1], ytickskip[-1], ytickskip[0]])
plt.imshow(baselineZ, aspect-3.5, 3.5)
plt.clim(-500, 1500])
plt.xlim([round(frequencies[ytickskip-1]).astype(int))
plt.yticks(ytickskip, np.
plt.gca().invert_yaxis()'Z-transform')
plt.title(
plt.tight_layout() plt.show()
Figure 18.8
# Define baseline period and channel to plot
= 'FCz' # p1 for figure 18.11
chan2plot = [-500, -200] # in ms
baselinetime
# Convert baseline window time to indices
= [np.argmin(np.abs(EEG['times'][0] - bt)) for bt in baselinetime]
baselineidx
# Initialize time-frequency data
= np.zeros((2, len(frequencies), EEG['pnts'][0][0]))
tf_data
# Update FFT parameters for multiple trials
= EEG['pnts'][0][0] * EEG['trials'][0][0]
n_data = n_wavelet + n_data - 1
n_convolution = int(2**np.ceil(np.log2(n_convolution)))
n_conv_pow2
# FFT of data
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==chan2plot].flatten('F'), n_conv_pow2)
fft_data
# Convolution for each frequency
for fi in range(len(frequencies)):
# Create wavelet and get its FFT
= (np.pi * frequencies[fi] * np.sqrt(np.pi))**-0.5 * np.exp(2 * 1j * np.pi * frequencies[fi] * time) * np.exp(-time**2 / (2 * (wavelet_cycles / (2 * np.pi * frequencies[fi]))**2)) / frequencies[fi]
wavelet = fft(wavelet, n_conv_pow2)
fft_wavelet
# Run convolution
= ifft(fft_wavelet * fft_data, n_conv_pow2)
convolution_result_fft = convolution_result_fft[:n_convolution]
convolution_result_fft = convolution_result_fft[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft = np.reshape(convolution_result_fft, (EEG['pnts'][0][0], EEG['trials'][0][0]), 'F')
convolution_result_fft
# Save single-trial data from one frequency band
if fi == 5:
= convolution_result_fft
convdat2keep
# Put power data into time-frequency matrix
0, fi, :] = np.mean(np.abs(convolution_result_fft)**2, axis=1)
tf_data[1, fi, :] = np.median(np.abs(convolution_result_fft)**2, axis=1)
tf_data[
# dB-correct and plot
= ['mean', 'median']
labelz =(12, 10))
plt.figure(figsizefor i in range(2):
= np.mean(tf_data[i, :, baselineidx[0]:baselineidx[1]+1], axis=1)
baseline_power = 10 * np.log10(tf_data[i] / baseline_power[:, np.newaxis])
dbconverted
# Plot
2, 2, i + 1)
plt.subplot('times'][0], frequencies, dbconverted, 40, cmap='viridis')
plt.contourf(EEG[-3, 3)
plt.clim(-200, 1000])
plt.xlim(['Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('log')
plt.yscale(= np.round(np.logspace(np.log10(frequencies[0]),np.log10(frequencies[-1]),6), 1)
ylabels
plt.yticks(ylabels, ylabels)
plt.title(labelz[i])
# Plot relationship between mean and median
223)
plt.subplot(= 10 * np.log10(tf_data[0] / np.mean(tf_data[0, :, baselineidx[0]:baselineidx[1]+1], axis=1)[:, np.newaxis])
db_mean = 10 * np.log10(tf_data[1] / np.mean(tf_data[1, :, baselineidx[0]:baselineidx[1]+1], axis=1)[:, np.newaxis])
db_medn 'F'), db_medn.flatten('F'), '.')
plt.plot(db_mean.flatten(= np.corrcoef(db_mean.flatten('F'), db_medn.flatten('F'))[0, 1]
r f'R^2 = {r**2:.5f}'])
plt.legend(['dB from Mean')
plt.xlabel('dB from Median')
plt.ylabel(
plt.tight_layout() plt.show()
Figure 18.9
# Plot all trials, mean, and median
=(12, 6))
plt.figure(figsize
# Subplot 1: All trials
211)
plt.subplot('times'][0], np.abs(convdat2keep)**2)
plt.plot(EEG[-200, 1000])
plt.xlim([0, 1400])
plt.ylim([
# Subplot 2: Mean and median
212)
plt.subplot('times'][0], np.mean(np.abs(convdat2keep)**2, axis=1), label='Mean')
plt.plot(EEG['times'][0], np.median(np.abs(convdat2keep)**2, axis=1), 'r', label='Median')
plt.plot(EEG[-200, 1000])
plt.xlim([min(np.median(np.abs(convdat2keep)**2, axis=1)), 200])
plt.ylim([np.
plt.legend()
plt.tight_layout()
plt.show()
# Add an outlier trial
= np.column_stack((convdat2keep, convdat2keep[:, 9] * 100))
convdat2keep1 # Note we save to a new variable so the cell can be re-run without issue
# The Matlab code does not do this and gives different plots when the single section is re-run
=(12, 10))
plt.figure(figsize
# Subplot 3: Median with and without outlier
223)
plt.subplot('times'][0], np.median(np.abs(convdat2keep1)**2, axis=1), label='With outlier')
plt.plot(EEG['times'][0], np.median(np.abs(convdat2keep1[:, :-1])**2, axis=1), 'r', label='Without outlier')
plt.plot(EEG[-200, 1000])
plt.xlim([20, 140])
plt.ylim([
plt.legend()'Median: insensitive to outlier trial')
plt.title(
# Subplot 4: Mean with and without outlier
224)
plt.subplot('times'][0], np.mean(np.abs(convdat2keep1)**2, axis=1), label='With outlier')
plt.plot(EEG['times'][0], np.mean(np.abs(convdat2keep1[:, :-1])**2, axis=1), 'r', label='Without outlier')
plt.plot(EEG[-200, 1000])
plt.xlim([0, 100000])
plt.ylim([
plt.legend()'Mean: sensitive to outlier trial')
plt.title(
plt.tight_layout() plt.show()
Figure 18.10
# Convenientize power
= np.abs(convdat2keep1)**2
convdatPower
# Single-trial linear baseline correction
= convdatPower - np.mean(convdatPower[baselineidx[0]:baselineidx[1]+1, :], axis=0)
convdat2keepB
# Single-trial Z score
= (convdatPower - np.mean(convdatPower[baselineidx[0]:baselineidx[1]+1, :], axis=0)) / np.std(convdatPower[baselineidx[0]:baselineidx[1]+1, :], axis=0)
convdat2keepZ
# Single-trial log10
= np.log10(convdatPower)
convdat2keepL
# Plot
=(12, 10))
plt.figure(figsize
# Subplot 1: Linear baseline subtraction
221)
plt.subplot('times'][0], np.mean(convdat2keepB, axis=1), 'r', label='Mean')
plt.plot(EEG['times'][0], np.median(convdat2keepB, axis=1), 'b', label='Median')
plt.plot(EEG[-200, 1000])
plt.xlim([-20000, 80000])
plt.ylim(['Time (ms)')
plt.xlabel('Power')
plt.ylabel(
plt.legend()'Linear baseline subtraction')
plt.title(
# Subplot 2: Z-transformation
222)
plt.subplot('times'][0], np.mean(convdat2keepZ, axis=1), 'r', label='Mean')
plt.plot(EEG['times'][0], np.median(convdat2keepZ, axis=1), 'b', label='Median')
plt.plot(EEG[-200, 1000])
plt.xlim([-2, 10])
plt.ylim(['Time (ms)')
plt.xlabel('Power_Z')
plt.ylabel(
plt.legend()'Z-transformation')
plt.title(
plt.tight_layout() plt.show()
Figure 18.11
This figure was made by running the code for figure 18.8 but using P1 instead of FCz. (Fewer frequencies were also plotted.)
Figure 18.12
# Initialize SNR and trial-averaged power arrays
= np.zeros((len(frequencies), EEG['pnts'][0][0]))
snr_bs = np.zeros((len(frequencies), EEG['pnts'][0][0]))
snr_tf = np.zeros((len(frequencies), EEG['pnts'][0][0]))
tf
# Compute SNR and trial-averaged power for each frequency
for fi in range(len(frequencies)):
# Create wavelet and get its FFT
= np.exp(2 * 1j * np.pi * frequencies[fi] * time) * np.exp(-time**2 / (2 * (wavelet_cycles / (2 * np.pi * frequencies[fi]))**2)) / frequencies[fi]
wavelet = fft(wavelet, n_conv_pow2)
fft_wavelet
# Run convolution
= ifft(fft_wavelet * fft_data, n_conv_pow2) * np.sqrt(wavelet_cycles /(2 * np.pi * frequencies[fi]))
convolution_result = convolution_result[:n_convolution]
convolution_result = convolution_result[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result = np.reshape(convolution_result, (EEG['pnts'][0][0], EEG['trials'][0][0]), 'F')
convolution_result
# Extract SNR in two ways
= np.mean(np.abs(convolution_result)**2, axis=1) / np.std(np.abs(convolution_result)**2, axis=1)
snr_tf[fi, :] = np.mean(np.abs(convolution_result)**2, axis=1) / np.std(np.mean(np.abs(convolution_result[baselineidx[0]:baselineidx[1]+1, :])**2, axis=0))
snr_bs[fi, :]
# Extract trial-averaged power
= np.mean(np.abs(convolution_result)**2, axis=1)
tf[fi, :]
# Plot SNR_baseline and SNR_tf
=(12, 6))
plt.figure(figsize
# Subplot 1: SNR_baseline (mean/std)
121)
plt.subplot('times'][0], frequencies, snr_bs, 40, cmap='viridis')
plt.contourf(EEG[# plt.colorbar()
0.5, 2)
plt.clim(-200, 1000])
plt.xlim([0], 40])
plt.ylim([frequencies['Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('SNR_baseline (mean/std)')
plt.title(
# Subplot 2: Relationship between SNR_baseline and Power/baseline
122)
plt.subplot(= np.mean(tf[:, baselineidx[0]:baselineidx[1]+1], axis=1)
baseline_power = tf / baseline_power[:, np.newaxis]
baselinediv 'F')[::3], baselinediv.flatten('F')[::3], '.')
plt.plot(snr_bs.flatten(0, 10])
plt.xlim([0, 6])
plt.ylim(['SNR_baseline')
plt.xlabel('Power (/baseline)')
plt.ylabel(
plt.tight_layout()
plt.show()
# Plot SNR_tf
=(12, 6))
plt.figure(figsize
# Subplot 1: SNR_tf (mean/std)
121)
plt.subplot('times'][0], frequencies, snr_tf, 40, cmap='viridis')
plt.contourf(EEG[# plt.colorbar()
0.5, 1.25)
plt.clim(-200, 1000])
plt.xlim([0], 40])
plt.ylim([frequencies['Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('SNR_tf (mean/std)')
plt.title(
# Subplot 2: Relationship between SNR_tf and Power/baseline
122)
plt.subplot('F')[::3], baselinediv.flatten('F')[::3], '.')
plt.plot(snr_tf.flatten(0, 1.4])
plt.xlim([0, 6])
plt.ylim(['SNR_tf')
plt.xlabel('Power (/baseline)')
plt.ylabel(
plt.tight_layout()
plt.show()
# Time-series of SNR
=(8, 4))
plt.figure(figsize= np.mean(EEG['data'][46, :, :], axis=1)
mean_data = np.std(EEG['data'][46, :, :], axis=1)
std_data 'times'][0], np.abs(mean_data / std_data))
plt.plot(EEG[-200, 1000])
plt.xlim(['Time (ms)')
plt.xlabel('SNR')
plt.ylabel('Time-domain SNR time series')
plt.title(
plt.show()
# Compute SNR of peak compared to prestim noise
= np.argmin(np.abs(EEG['times'][0] - 150))
stimeidx = np.argmin(np.abs(EEG['times'][0] - 400))
etimeidx = np.max(mean_data[stimeidx:etimeidx]) / np.std(mean_data[baselineidx[0]:baselineidx[1]+1])
erp_snr print(f'ERP SNR between 150 and 400 ms at FCz: {erp_snr}')
ERP SNR between 150 and 400 ms at FCz: 10.508532524108887
Figure 18.13
# Initialize variables
= 10
iterations = 'P7' # or FCz
chan2plot = False
dbcorrect
= np.zeros((len(frequencies), EEG['trials'][0][0]))
powerByTrialFreq
# Define time range
= -200 # in ms
start_time = 1200
end_time
# FFT of data
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==chan2plot].flatten('F'), n_conv_pow2)
fft_data = [np.argmin(np.abs(EEG['times'][0] - t)) for t in [start_time, end_time]]
timeidx
# Compute power by trial frequency
for fi in range(len(frequencies)):
# Create wavelet and get its FFT
= np.exp(2 * 1j * np.pi * frequencies[fi] * time) * np.exp(-time**2 / (2 * (wavelet_cycles / (2 * np.pi * frequencies[fi]))**2)) / frequencies[fi]
wavelet = fft(wavelet, n_conv_pow2)
fft_wavelet
# Run convolution
= ifft(fft_wavelet * fft_data, n_conv_pow2) * np.sqrt(wavelet_cycles / (2 * np.pi * frequencies[fi]))
convolution_result = convolution_result[:n_convolution]
convolution_result = convolution_result[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result = np.abs(np.reshape(convolution_result, (EEG['pnts'][0][0], EEG['trials'][0][0]), 'F'))**2 # reshape and convert to power
convolution_result
# "Gold standard" is average of all trials
if dbcorrect:
= 10 * np.log10(np.mean(convolution_result, axis=1) / np.mean(np.mean(convolution_result[baselineidx[0]:baselineidx[1]+1, :], axis=0)))
template = template[timeidx[0]:timeidx[1]+1]
template else:
= np.mean(convolution_result[timeidx[0]:timeidx[1]+1], axis=1)
template = (template - np.mean(template)) / np.std(template)
template
for iteri in range(iterations):
for triali in range(5, EEG['trials'][0][0]): # start at 5 trials...
= np.random.choice(EEG['trials'][0][0], triali, replace=False)
trials2use
# Compute power time series from the random selection of trials
if dbcorrect:
= 10 * np.log10(np.mean(convolution_result[:, trials2use], axis=1) / np.mean(np.mean(convolution_result[baselineidx[0]:baselineidx[1]+1, trials2use])))
tempdat = tempdat[timeidx[0]:timeidx[1]+1]
tempdat else:
= np.mean(convolution_result[timeidx[0]:timeidx[1]+1, trials2use], axis=1)
tempdat = (tempdat - np.mean(tempdat)) / np.std(tempdat)
tempdat
# Compute Pearson correlation
+= np.dot(tempdat, template) / np.dot(tempdat, tempdat)
powerByTrialFreq[fi, triali]
/= iterations
powerByTrialFreq
# Plot
=(10, 8))
plt.figure(figsize5, EEG['trials'][0][0] + 1), powerByTrialFreq[:, 4:].T)
plt.plot(np.arange('Number of trials')
plt.xlabel('Power')
plt.ylabel(-0.1, 1.1])
plt.ylim(['Each line is a frequency band')
plt.title(
=(10, 8))
plt.figure(figsize5, EEG['trials'][0][0] + 1), frequencies, powerByTrialFreq[:, 4:], 40, cmap='viridis')
plt.contourf(np.arange(0.6, 1)
plt.clim('Number of trials')
plt.xlabel('Frequency (Hz)')
plt.ylabel('DB normalized' if dbcorrect else 'Not dB normalized')
plt.title(
plt.tight_layout() plt.show()