├── Readme.doc ├── data_eeg.mat ├── data_lep.mat ├── data_vep.mat ├── demo_erserd.m ├── README.md ├── demo_periodogram.m ├── subfunc_mwt.m ├── demo_multitaper.m ├── demo_welch.m ├── demo_yulear.m ├── demo_stft.m ├── subfunc_stft.m └── demo_mwt.m /Readme.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangzg78/eegbook/HEAD/Readme.doc -------------------------------------------------------------------------------- /data_eeg.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangzg78/eegbook/HEAD/data_eeg.mat -------------------------------------------------------------------------------- /data_lep.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangzg78/eegbook/HEAD/data_lep.mat -------------------------------------------------------------------------------- /data_vep.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangzg78/eegbook/HEAD/data_vep.mat -------------------------------------------------------------------------------- /demo_erserd.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangzg78/eegbook/HEAD/demo_erserd.m -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MATLAB files (scripts and data) used in Chapter 6 "Spectral and Time-frequency Analyses" of the book "EEG SIGNAL PROCESSING AND FEATURE EXTRACTION" 2 | 3 | 中文:在《脑电信号处理与特征提取》一书的第5章“频谱分析和时频分析”使用的MATLAB文件(程序和数据)。 4 | 5 | Author/作者: Zhiguo Zhang/张治国 6 | Email: zgzhang@szu.edu.cn 7 | -------------------------------------------------------------------------------- /demo_periodogram.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to estimate the spectrum of an 3 | % EEG signal using the periodogram. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_eeg.mat 18 | % data_eeg.mat contains 2 variables 19 | % - x: the EEG signal (with eyes-closed) 20 | % - Fs: the sampling rate (Fs = 160Hz) 21 | 22 | N = length(x); % the number of samples (N=480) 23 | x = detrend(x); % remove the low-frequency trend from EEG 24 | 25 | %% spectral estimation (periodogram) 26 | nfft = 2^nextpow2(N); % the number of FFT points 27 | % check the help file to learn how to specify parameters in "peridogram.m" 28 | [P_per, f] = periodogram(x,[],nfft,Fs); 29 | 30 | %% display spectral estimates 31 | f_lim = f((f>0)&(f<=50)); % specify the frequency range to be shown 32 | 33 | figure('units','normalized','position',[0.1 0.3 0.8 0.5]) 34 | subplot(1,2,1) 35 | hold on; box on; 36 | plot(f,P_per,'k','linewidth',1) % show the periodogram in a linear scale 37 | xlabel('Frequency (Hz)'); ylabel('Power (\muV^2/Hz)') 38 | title(['Periodogram (in a linear scale)'],'fontsize',12) 39 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 40 | 41 | subplot(1,2,2) 42 | hold on; box on; 43 | plot(f,10*log10(P_per),'k','linewidth',1) % show the periodogram in a log scale 44 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 45 | title(['Periodogram (in a logarithmic scale)'],'fontsize',12) 46 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 47 | -------------------------------------------------------------------------------- /subfunc_mwt.m: -------------------------------------------------------------------------------- 1 | function [P, S] = subfunc_mwt(x, f, Fs, omega, sigma) 2 | % Morlet wavelet transform (continuous wavelet transform with Morlet basis) 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % Description: This is a sub-function to calculate Morlet wavelet transform. 5 | % 6 | % Note: This script is a supplementary file of Chapter6 in the book 7 | % "EEG Signal Processing and Feature Extraction" (Springer) 8 | % 9 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 10 | % School of Biomedical Engineering, Shenzhen University, 11 | % Shenzhen, China 12 | % Jan 2019 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | % // Input // % 15 | % x: the original data samples (Time Points x Channels) 16 | % Fs: sampling rate 17 | % omega: a parameter to define the central frequency of Morlet wavelet 18 | % sigma: a parameter to define the spread of Morlet wavelet in time domain 19 | 20 | % // Output // % 21 | % P: squared magnitude of MWT (scaleogram) 22 | % S: complex values of Morlet wavelet transform 23 | 24 | fprintf('Calculating Morlet Wavelet Transform ... ') 25 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 26 | 27 | %% Pre-processing and Parameters 28 | if size(x,2)==1; x = x.'; end 29 | x = detrend(x,'linear'); % remove linear trends 30 | 31 | N_F = length(f); % number of frequency bins 32 | N_T = length(x); % number of time samples 33 | f = f/Fs; % normalized frequency 34 | 35 | S = single(zeros(N_F,N_T)); % define the size of output 36 | 37 | %% Morlet wavelet transform 38 | L_hw = N_T; % filter length 39 | for fi=1:N_F 40 | scaling_factor = omega./f(fi); % the scaling factor 41 | u = (-[-L_hw:L_hw])./scaling_factor; 42 | hw = sqrt(1/scaling_factor)*exp(-(u.^2)/(2*sigma.^2)).* exp(1i*2*pi*omega*u); 43 | S_full = conv(x,conj(hw)); 44 | S(fi,:) = S_full(L_hw+1:L_hw+N_T); % complex values 45 | end 46 | P = abs(S).^2; % power values 47 | 48 | fprintf('Done!\n') 49 | -------------------------------------------------------------------------------- /demo_multitaper.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to estimate the spectrum of an 3 | % EEG signal using the multitaper method. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_eeg.mat 18 | % data_eeg.mat contains 2 variables 19 | % - x: the EEG signal (with eyes-closed) 20 | % - Fs: the sampling rate (Fs = 160Hz) 21 | 22 | N = length(x); % the number of samples (N=480) 23 | x = detrend(x); % remove the low-frequency trend from EEG 24 | 25 | %% spectral estimation (the multitaper method) 26 | nfft = 2^nextpow2(N); % the number of FFT points 27 | [P_per, f] = periodogram(x,[],nfft,Fs); % periodogram is also estimated for comparison 28 | % check the help file to learn how to specify parameters in "pmtm.m" 29 | % three parameter settings are used below 30 | [P_mtm_1, f] = pmtm(x,4,nfft,Fs); 31 | [P_mtm_2, f] = pmtm(x,2,nfft,Fs); 32 | [P_mtm_3, f] = pmtm(x,6,nfft,Fs); 33 | 34 | %% display spectral estimates 35 | f_lim = f((f>0)&(f<=50)); % specify the frequency range to be shown 36 | 37 | figure('units','normalized','position',[0.1 0.3 0.8 0.5]) 38 | subplot(1,2,1) 39 | hold on; box on; 40 | plot(f,10*log10(P_per),'k','linewidth',0.5) 41 | plot(f,10*log10(P_mtm_1),'r','linewidth',2) 42 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 43 | hl = legend('Periodogram','Multitaper (L=4)'); 44 | set(hl,'box','off','location','southwest') 45 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 46 | 47 | subplot(1,2,2) 48 | hold on; box on; 49 | plot(f,10*log10(P_mtm_1),'r','linewidth',2) 50 | plot(f,10*log10(P_mtm_2),'g','linewidth',1) 51 | plot(f,10*log10(P_mtm_3),'b','linewidth',1) 52 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 53 | hl = legend('Multitaper (L=4)','Multitaper (L=2)','Multitaper (L=6)'); 54 | set(hl,'box','off','location','southwest') 55 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 56 | -------------------------------------------------------------------------------- /demo_welch.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to estimate the spectrum of an 3 | % EEG signal using the Welch's method. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_eeg.mat 18 | % data_eeg.mat contains 2 variables 19 | % - x: the EEG signal (with eyes-closed) 20 | % - Fs: the sampling rate (Fs = 160Hz) 21 | 22 | N = length(x); % the number of samples (N=480) 23 | x = detrend(x); % remove the low-frequency trend from EEG 24 | 25 | %% spectral estimation (the Welch's method) 26 | nfft = 2^nextpow2(N); % the number of FFT points 27 | [P_per, f] = periodogram(x,[],nfft,Fs); % periodogram is also estimated for comparison 28 | % check the help file to learn how to specify parameters in "pwelch.m" 29 | % three parameter settings are used below 30 | [P_wel_1, f] = pwelch(x,Fs,Fs/2,nfft,Fs); 31 | [P_wel_2, f] = pwelch(x,Fs,0,nfft,Fs); 32 | [P_wel_3, f] = pwelch(x,Fs/2,0,nfft,Fs); 33 | 34 | %% display spectral estimates 35 | f_lim = f((f>0)&(f<=50)); % specify the frequency range to be shown 36 | 37 | figure('units','normalized','position',[0.1 0.3 0.8 0.5]) 38 | subplot(1,2,1) 39 | hold on; box on; 40 | plot(f,10*log10(P_per),'k','linewidth',0.5) 41 | plot(f,10*log10(P_wel_1),'r','linewidth',2) 42 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 43 | hl = legend('Periodogram','Welch''s method (M=160, D=80)'); 44 | set(hl,'box','off','location','southwest') 45 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 46 | 47 | subplot(1,2,2) 48 | hold on; box on; 49 | plot(f,10*log10(P_wel_1),'r','linewidth',2) 50 | plot(f,10*log10(P_wel_2),'g','linewidth',1) 51 | plot(f,10*log10(P_wel_3),'b','linewidth',1) 52 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 53 | hl = legend('Welch''s (M=160, D=80)','Welch''s (M=160, D=0)','Welch''s (M=80, D=0)'); 54 | set(hl,'box','off','location','southwest') 55 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 56 | -------------------------------------------------------------------------------- /demo_yulear.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to estimate the spectrum of an 3 | % EEG signal based on the AR model and using the Yule-Walker method. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_eeg.mat 18 | % data_eeg.mat contains 2 variables 19 | % - x: the EEG signal (with eyes-closed) 20 | % - Fs: the sampling rate (Fs = 160Hz) 21 | 22 | N = length(x); % the number of samples (N=480) 23 | x = detrend(x); % remove the low-frequency trend from EEG 24 | 25 | %% spectral estimation (the multitaper method) 26 | nfft = 2^nextpow2(N); % the number of FFT points 27 | [P_per, f] = periodogram(x,[],nfft,Fs); % periodogram is also estimated for comparison 28 | % check the help file to learn how to specify parameters in "pmtm.m" 29 | % three parameter settings (AR orders) are used below 30 | p1 = 20; 31 | p2 = 10; 32 | p3 = 50; 33 | [P_ar_1,f] = pyulear(x,p1,nfft,Fs); 34 | [P_ar_2,f] = pyulear(x,p2,nfft,Fs); 35 | [P_ar_3,f] = pyulear(x,p3,nfft,Fs); 36 | 37 | %% display spectral estimates 38 | f_lim = f((f>0)&(f<=50)); % specify the frequency range to be shown 39 | 40 | figure('units','normalized','position',[0.1 0.3 0.8 0.5]) 41 | subplot(1,2,1) 42 | hold on; box on; 43 | plot(f,10*log10(P_per),'k','linewidth',0.5) 44 | plot(f,10*log10(P_ar_1),'r','linewidth',2) 45 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 46 | hl = legend('Periodogram','AR (P=20)'); 47 | set(hl,'box','off','location','southwest') 48 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 49 | 50 | subplot(1,2,2) 51 | hold on; box on; 52 | plot(f,10*log10(P_ar_1),'r','linewidth',2) 53 | plot(f,10*log10(P_ar_2),'g','linewidth',1) 54 | plot(f,10*log10(P_ar_3),'b','linewidth',1) 55 | xlabel('Frequency (Hz)'); ylabel('Power (dB)') 56 | hl = legend('AR (P=20)','AR (P=10)','AR (P=50)'); 57 | set(hl,'box','off','location','southwest') 58 | set(gca,'xlim',[min(f_lim),max(f_lim)]) 59 | -------------------------------------------------------------------------------- /demo_stft.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to calculate the short-time Fourier 3 | % transform (STFT) of a VEP signal. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_vep.mat 18 | % data_vep.mat contains 3 variables 19 | % - x: the VEP signal (512 time points, averaged from multiple trials) 20 | % - Fs: the sampling rate (Fs = 250Hz) 21 | % - t: the time indices (256 pre-stimulus samples and 256 post-stimulus samples, with a time interval of 1/Fs) 22 | % The original data are from https://vis.caltech.edu/~rodri/data/cg_o1t.asc 23 | % Please see https://vis.caltech.edu/~rodri/data.htm for more details. 24 | 25 | N = numel(x); % the number of time points 26 | x = x - mean(x(t<0)); % baseline corrction for averaged VEP 27 | 28 | %% perform time-frequency analysis using STFT 29 | nfft = 2^nextpow2(N); % the number of FFT points 30 | winsize = round([0.2 0.4 0.8]*Fs); % three window sizes (0.2s, 0.4s, 08s) are used in STFT for comparison 31 | for n=1:numel(winsize) 32 | [P(:,:,n),f] = subfunc_stft(x, winsize(n), nfft, Fs); 33 | end 34 | 35 | %% display VEP and STFT results with different window sizes 36 | f_lim = [min(f(f>0)), 30]; % specify the frequency range to be shown (remove 0Hz) 37 | f_idx = find((f<=f_lim(2))&(f>=f_lim(1))); 38 | t_lim = [-0.2, 1]; % specify the time range to be shown 39 | t_idx = find((t<=t_lim(2))&(t>=t_lim(1))); 40 | 41 | figure('units','normalized','position',[0.1 0.15 0.8 0.7]) 42 | subplot(2,2,1) 43 | hold on; box on 44 | plot(t(t_idx),x(t_idx),'k','linewidth',1); 45 | plot([-1 1],[0 0],'k--') 46 | plot([0 0],[-30 30],'k--') 47 | set(gca,'xlim',[min(t_lim),max(t_lim)]) 48 | xlabel('Time (s)') 49 | ylabel('Amplitude (\muV)') 50 | title(['VEP'],'fontsize',12) 51 | for n=1:numel(winsize) 52 | subplot(2,2,n+1) 53 | imagesc(t(t_idx),f(f_idx),P(f_idx,t_idx,n)) 54 | xlabel('Time (s)') 55 | ylabel('Frequency (Hz)') 56 | set(gca,'xlim',t_lim,'ylim',f_lim) 57 | axis xy; hold on; 58 | plot([0 0],[0 Fs/2],'w--') 59 | text(t_lim(2),f_lim(2)/2,'Power (dB)','rotation',90,'horizontalalignment','center','verticalalignment','top') 60 | title(['Spectrogram (winsize = ',num2str(winsize(n)/Fs,'%1.2g'),'s)'],'fontsize',12) 61 | colorbar 62 | end 63 | -------------------------------------------------------------------------------- /subfunc_stft.m: -------------------------------------------------------------------------------- 1 | function [P, f, S] = subfunc_stft(x, winparam, nfft, fs) 2 | % Short-time Fourier Transform (STFT) 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % Description: This is a sub-function to calculate STFT. 5 | % 6 | % Note: This script is a supplementary file of Chapter6 in the book 7 | % "EEG Signal Processing and Feature Extraction" (Springer) 8 | % 9 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 10 | % School of Biomedical Engineering, Shenzhen University, 11 | % Shenzhen, China 12 | % Jan 2019 13 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14 | % // Input // % 15 | % x: the original data samples (Time Points x Channels/Trials) 16 | % winparam: for an positive interger input, winparam is the window size (default window is hamming) 17 | % for a vector input, winparam is a window 18 | % nfft: number of fft points 19 | % fs: sampling rate 20 | 21 | % // Output // % 22 | % P: squared magnitude of STFT (spectrogram) 23 | % f: evaluated frequency bins in STFT 24 | % S: complex time-frequency value of STFT 25 | 26 | fprintf('\nShort-time Fourier Transform: ') 27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28 | 29 | %% Specify Parameters 30 | if size(x,1)==1; x = x.'; end; % transpose data if the 1st dimension is 1 31 | f = fs/2*linspace(0,1,nfft/2+1)'; 32 | N_Trials = size(x,2); % number of trials 33 | N_T = size(x,1); % number of time samples 34 | N_F = length(f); % number of frequency bins 35 | 36 | fprintf('%d Time Points x %d Frequency Bins x %d Trial(s)\n',N_T,N_F,N_Trials); 37 | S = single(zeros(N_F,N_T,N_Trials)); 38 | fprintf('Processing... ') 39 | 40 | %% Windowing and Padding 41 | if length(winparam)==1 % a window size is specified 42 | if mod(winparam,2); h = winparam; % window size (points) 43 | else h = winparam+1; % window size (points); 44 | end 45 | win = window('hamming',h); % window (one trial); default window type is hamming 46 | else 47 | win = winparam; 48 | h = length(win); 49 | end 50 | W = repmat(win,1,N_Trials); % window (all trials) 51 | U = win'*win; % compensates for the power of the window 52 | 53 | % Zero padding (default mode is "zero") 54 | X = padarray(x,(h-1)/2); % padding data 55 | X = detrend(X,'linear'); % remove low-frequency trend 56 | 57 | %% STFT 58 | for n=1:N_T 59 | fprintf('\b\b\b\b%3.0f%%',n/N_T*100) 60 | X_n = X(n+[0:h-1],:); % windowed data segment 61 | X_n = detrend(X_n); % remove low-frequency trend 62 | S_n = fft(X_n.*W,nfft,1); % FFT of windowed data 63 | S(:,n,:) = S_n(1:(nfft/2+1),:) / sqrt(U); % complex values 64 | end 65 | P = S.*conj(S)/fs; % power values 66 | fprintf(' Done!\n') 67 | 68 | end -------------------------------------------------------------------------------- /demo_mwt.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Description: This is the demo script to calculate the continuous wavelet 3 | % transform (CWT) of a VEP signal with the Morlet wavelet basis. 4 | % 5 | % Note: This script is a supplementary file of Chapter6 in the book 6 | % "EEG Signal Processing and Feature Extraction" (Springer) 7 | % 8 | % Author: ZHANG Zhiguo, zgzhang@szu.edu.cn 9 | % School of Biomedical Engineering, Shenzhen University, 10 | % Shenzhen, China 11 | % Jan 2019 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | %% load data and define parameters 15 | clear all; clc; 16 | 17 | load data_vep.mat 18 | % data_vep.mat contains 3 variables 19 | % - x: the VEP signal (512 time points, averaged from multiple trials) 20 | % - Fs: the sampling rate (Fs = 250Hz) 21 | % - t: the time indices (256 pre-stimulus samples and 256 post-stimulus samples, with a time interval of 1/Fs) 22 | % The original data are from https://vis.caltech.edu/~rodri/data/cg_o1t.asc 23 | % Please see https://vis.caltech.edu/~rodri/data.htm for more details. 24 | 25 | N = numel(x); % the number of time points 26 | x = x - mean(x(t<0)); % baseline corrction for averaged VEP 27 | 28 | %% perform time-frequency analysis using MWT 29 | nfft = 2^nextpow2(N); % the number of FFT points 30 | [P_stft,f] = subfunc_stft(x,100, nfft, Fs); % STFT (with a window size of 100) is calculated for comparison 31 | % note: the frequency index f is obtained from STFT in this demo, while it 32 | % can actually be defined by users. 33 | N_F = length(f); % number of frequency bins 34 | 35 | omega = [0.5 1]; % test two values for the parameter omega 36 | sigma = [0.5 .2]; % test two values for the parameter sigma 37 | 38 | ff = f/Fs; % normalized frequency 39 | L_hw = N; % filter length 40 | for fi=1:N_F 41 | scaling_factor = omega(1)./ff(fi); 42 | u = (-[-L_hw:L_hw])./scaling_factor; 43 | w(:,fi) = sqrt(1/scaling_factor)*exp(-(u.^2)/(2*sigma(1).^2)); 44 | hw(:,fi) = w(:,fi).'.* exp(1i*2*pi*omega(1)*u); 45 | end 46 | 47 | for n_omega=1:numel(omega) 48 | for n_sigma=1:numel(sigma) 49 | [P_mwt(:,:,n_omega,n_sigma)] = subfunc_mwt(x, f, Fs, omega(n_omega), sigma(n_sigma)); 50 | end 51 | end 52 | 53 | %% display MWT results with different parameters 54 | f_lim = [min(f(f>0)), 30]; % specify the frequency range to be shown (remove 0Hz) 55 | f_idx = find((f<=f_lim(2))&(f>=f_lim(1))); 56 | t_lim = [-0.2, 1]; % specify the time range to be shown 57 | t_idx = find((t<=t_lim(2))&(t>=t_lim(1))); 58 | 59 | figure('units','normalized','position',[0.1 0.15 0.8 0.7]) 60 | for n_omega=1:numel(omega) 61 | for n_sigma=1:numel(sigma) 62 | n = (n_omega-1)*2+n_sigma; 63 | subplot(2,2,n) 64 | imagesc(t(t_idx),f(f_idx),P_mwt(f_idx,t_idx,n_omega,n_sigma)) 65 | xlabel('Time (s)') 66 | ylabel('Frequency (Hz)') 67 | set(gca,'xlim',t_lim,'ylim',f_lim) 68 | axis xy; hold on; 69 | plot([0 0],[0 Fs/2],'w--') 70 | title(['Scaleogram (\omega = ',num2str(omega(n_omega),'%1.2g'),', \sigma = ',num2str(sigma(n_sigma),'%1.2g'),')'],'fontsize',12) 71 | text(t_lim(2),f_lim(2)/2,'Power (\muV^2/Hz)','rotation',90,'horizontalalignment','center','verticalalignment','top') 72 | colorbar 73 | end 74 | end 75 | --------------------------------------------------------------------------------