├── Window_then_Taper.m ├── TSpectrogram.m ├── confidence_interval_CMT.m ├── MTSpectrogram.m ├── log_DBMTSpectrogram.m ├── Post_mode_var.m ├── confidence_interval_log_DBMT.m ├── README.md ├── DBMTSpectrogram.m ├── confidence_interval_DBMT.m ├── main.m ├── DBMT_EM.m └── log_DBMT_EM.m /Window_then_Taper.m: -------------------------------------------------------------------------------- 1 | function [y] = Window_then_Taper( x,seq ) 2 | %[y] = Window_then_Taper( x,seq ) windows the data 3 | % and then multiply by taper (Used in DBMT algo). 4 | % 5 | % Output: 6 | % y = data 7 | % 8 | % Input: 9 | % x = time-series data 10 | % seq = Taper 11 | 12 | 13 | N = length(seq); 14 | W = floor(length(x)/N); 15 | 16 | y = zeros(N,W); 17 | for k = 0:1:W-1 18 | d = x(1+k*N:(k+1)*N); 19 | y(:,k+1) = d.*seq; 20 | end 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /TSpectrogram.m: -------------------------------------------------------------------------------- 1 | function [ o_mt_est ] = TSpectrogram( y,N,overlap,time_halfbandwidth,seq_num,Fs ) 2 | %[ o_mt_est ] = TSpectrogram( y,N,overlap,time_halfbandwidth,seq_num,Fs )computes 3 | % single tapered spectrogram. 4 | % 5 | % Outputs: 6 | % o_mt_est = conventional multitaper estimate 7 | % 8 | % Inputs: 9 | % y = Data 10 | % N = window length in seconds 11 | % overlap \in [0,1] 12 | % time_halfbandwidth = N*B 13 | % num_seq = taper to be used 14 | % Fs = Sampling Frequency 15 | 16 | 17 | N = floor(Fs*N); 18 | K = N*(1-overlap); 19 | W = floor(length(y)/K - N/K); 20 | 21 | seq_length = N; 22 | 23 | [dps_seq,lambda] = dpss(seq_length,time_halfbandwidth,seq_num); 24 | 25 | o_mt_est = zeros(N,W+1); 26 | 27 | for k = 0:1:W 28 | d = y(1+k*K:k*K+N); 29 | o_mt_est(:,k+1) = abs(fft(d.*dps_seq(:,seq_num))).^2; 30 | end 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /confidence_interval_CMT.m: -------------------------------------------------------------------------------- 1 | function [ u_b,l_b ] = confidence_interval_CMT( n, num_seq ) 2 | %[ u_b,l_b ] = confidence_interval_CMT( n, num_seq ) computes 3 | %95% confidence interval of conventional multitaper estimates 4 | %of a single window. 5 | % 6 | % Inputs: 7 | % n = window number 8 | % num_seq = # of tapers used 9 | % 10 | % Outputs: 11 | % u_b = upper confidence bound 12 | % l_b = lower confidence bound 13 | 14 | degrees_of_freedom = 2*num_seq; 15 | u_mul = 1.237; 16 | l_mul = 12.592; 17 | Fs = 110; % Sampling Frequency (Change accordingly) 18 | N = 6*Fs; % 6 sec window size (Change accordingly) 19 | 20 | pathname = fileparts('./CMT/file'); 21 | matfile = fullfile(pathname, 'mtm_est.mat'); 22 | load(matfile); 23 | 24 | S = c_mt_est(:,n); 25 | u_b = (degrees_of_freedom-1)*S/u_mul; 26 | l_b = (degrees_of_freedom-1)*S/l_mul; 27 | 28 | plot(Fs*(0:(21*N/Fs)-1)/N,10*log10(S(1:21*N/Fs)/Fs)); 29 | hold on; 30 | plot(Fs*(0:(21*N/Fs)-1)/N,10*log10(u_b(1:21*N/Fs)/Fs),'g'); 31 | plot(Fs*(0:(21*N/Fs)-1)/N,10*log10(l_b(1:21*N/Fs)/Fs),'r'); 32 | xlim([0 20]); 33 | ylim([-80 20]); 34 | grid on 35 | xlabel('Frequency(Hz)','Interpreter','Latex'); 36 | ylabel('PSD(in dB)','Interpreter','Latex'); 37 | legend('Est','Upper Bound','Lower Bound','Location','Northwestoutside'); 38 | end 39 | 40 | -------------------------------------------------------------------------------- /MTSpectrogram.m: -------------------------------------------------------------------------------- 1 | function [ c_mt_est ] = MTSpectrogram( y,W,overlap,time_halfbandwidth,num_seq,Fs ) 2 | %[ c_mt_est ] =MTSpectogram( y,N,overlap,time_halfbandwidth,num_seq,Fs ) computes overlapped 3 | % multitaper spectrogram. 4 | % 5 | % Outputs: 6 | % c_mt_est = conventional multitaper estimate 7 | % 8 | %Inputs: 9 | % y = Data 10 | % W = window length in seconds 11 | % overlap \in [0,1] 12 | % time_halfbandwidth = N*B 13 | % num_seq = # of tapers to be used 14 | % Fs = Sampling Frequency 15 | 16 | W = Fs*W; 17 | K = W*(1-overlap); 18 | N = floor(length(y)/K - W/K); 19 | 20 | seq_length = W; 21 | [dps_seq,lambda] = dpss(seq_length,time_halfbandwidth,num_seq); 22 | 23 | c_mt_est = zeros(W,N+1); 24 | 25 | for k = 0:1:N 26 | d = y(1+k*K:k*K+W); 27 | for j = 1:num_seq 28 | c_mt_est(:,k+1) = c_mt_est(:,k+1)+ abs(fft(d.*dps_seq(:,j))).^2; 29 | end 30 | end 31 | c_mt_est = c_mt_est/num_seq; 32 | %****************************Plot upto 20 Hz******************************* 33 | pcolor(((0:1:N)*K+W/2)/Fs,Fs*(0:(21*W/Fs)-1)/W,10*log10(c_mt_est(1:21*W/Fs,:)/Fs)); 34 | shading flat; 35 | colormap('jet'); 36 | colorbar; 37 | xlabel('Time(s)','Interpreter','Latex'); 38 | ylabel('Frequency(Hz)','Interpreter','Latex'); 39 | drawnow; 40 | title('Overlapped Multi-taper Spectrogram','Interpreter','Latex'); 41 | pathname = fileparts('./CMT/file'); 42 | matfile = fullfile(pathname, 'mtm_est'); 43 | save(matfile, 'c_mt_est'); 44 | end 45 | 46 | -------------------------------------------------------------------------------- /log_DBMTSpectrogram.m: -------------------------------------------------------------------------------- 1 | function [ final_est ] = log_DBMTSpectrogram( y,W,U,time_halfbandwidth,num_tapers,Fs ) 2 | %[ final_est ] = log_DBMTSpectrogram( y,W,U,time_halfbandwidth,num_tapers,Fs ) 3 | %computes log_DBMT spectrogram of time-series data. 4 | % 5 | % Outputs: 6 | % final_est = log-DBMT estimate 7 | % 8 | % Inputs: 9 | % y = Data 10 | % W = window length in seconds 11 | % U = # of frequency points to be estimated 12 | % time_halfbandwidth = N*B 13 | % num_tapers = # of tapers to be used 14 | % Fs = Sampling Frequency 15 | 16 | N = floor(length(y)/(W*Fs)); %# of windows 17 | TOL = 3*10^-2; 18 | max_iter = 40; 19 | 20 | final_est = 0; 21 | 22 | for seq_num = 1:1:num_tapers 23 | tic 24 | S = TSpectrogram(y,W,0,time_halfbandwidth,seq_num,Fs); 25 | Y = log(S(1:U+1,:)); 26 | x = 0*ones(size(Y)); %k|k or k|N 27 | alpha = 0; 28 | est = zeros(size(Y)); 29 | [est,alpha] = log_DBMT_EM(seq_num,x,N,Y,alpha,TOL,max_iter); 30 | toc 31 | final_est = final_est + exp(est); 32 | end 33 | final_est = final_est/num_tapers; 34 | 35 | %****************************Plot upto 20 Hz******************************* 36 | W = floor(Fs*W); 37 | K = W; 38 | W1 = floor(length(y)/K - W/K); 39 | pcolor(((0:1:W1)*K+W/2)/Fs,Fs*(0:(20*W/Fs)-1)/N,10*log10(final_est(1:20*W/Fs,:)/Fs)); 40 | shading flat; 41 | colormap('jet'); 42 | colorbar; 43 | xlabel('Time(s)','Interpreter','Latex'); 44 | ylabel('Frequency(Hz)','Interpreter','Latex'); 45 | title('log-DBMTSpectogram','Interpreter','Latex'); 46 | drawnow 47 | end 48 | 49 | -------------------------------------------------------------------------------- /Post_mode_var.m: -------------------------------------------------------------------------------- 1 | function [ x_sol, Sigma_sol ] = Post_mode_var( y, x, nu, Sigma ) 2 | %[ x_sol, Sigma_sol ] = Post_mode_var( y, x, nu, Sigma ) 3 | %Finds the posterior mode and variance in log_DBMT algo. 4 | % 5 | % Input: 6 | % y = observation 7 | % x = x_{(k|k-1)} One step prediction 8 | % nu = degrees of freedom 9 | % Sigma = \Sigma_{k|k-1} Prediction variance 10 | % 11 | % Output: 12 | % x_sol = posterior mode 13 | % Sigma_sol = posterior variance 14 | 15 | MAXLEN = 100; 16 | TOL = 10^-6; 17 | 18 | % degrees of freedom 19 | % nu = 1.0; 20 | 21 | % function def 22 | f = @(x_sol) nu*sum(x_sol-y) + sum(exp(y-x_sol+log(nu))) + (x_sol-x)'*(Sigma\(x_sol -x)); 23 | grad = @(x_sol) nu*ones(size(y)) - exp(y-x_sol+log(nu)) + Sigma\(x_sol-x); 24 | Hes = @(x_sol) Sigma\eye(length(y)) + diag(exp(y-x_sol+log(nu))); 25 | 26 | % f = @(x_sol) nu*sum(x_sol-y) + sum(exp(y+log(nu)).*(exp(-x_sol)+0.5*exp(-x_sol).*diag(Sigma))) + (x_sol-x)'*(Sigma\(x_sol -x)); 27 | % grad = @(x_sol) nu*ones(size(y)) - exp(y+log(nu)).*(exp(-x_sol)+0.5*exp(-x_sol).*diag(Sigma)) + Sigma\(x_sol-x); 28 | % Hes = @(x_sol) Sigma\eye(length(y)) + diag(exp(y+log(nu)).*(exp(-x_sol)+0.5*exp(-x_sol).*diag(Sigma))); 29 | 30 | 31 | x_sol = zeros(size(y)); 32 | g = grad(x_sol); 33 | H = Hes(x_sol); 34 | d = H\g; 35 | tau = 1; % Stepsize 36 | alpha = 0.01; 37 | 38 | res = g'*d; 39 | 40 | for i = 1:MAXLEN 41 | % Backtracking Line search 42 | while f(x_sol - tau*d) > f(x_sol) - alpha * tau * (g'*d) 43 | tau = tau/2; 44 | end 45 | x_sol = x_sol - tau*d; 46 | g = grad(x_sol); 47 | H = Hes(x_sol); 48 | d = H\g; 49 | if tau < 10^-15 50 | break; 51 | end 52 | tau = 1; % Stepsize 53 | res = [res; g'*d]; 54 | if res(end)/res(1) < TOL 55 | break; 56 | end 57 | end 58 | Sigma_sol = Hes(x_sol)\eye(length(y)); 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /confidence_interval_log_DBMT.m: -------------------------------------------------------------------------------- 1 | function [ final_Confidence_bounds ] = confidence_interval_log_DBMT( n, num_seq ) 2 | %[ final_Confidence_bounds ] = confidence_interval_log_DBMT(n, num_seq) 3 | %plots 95% confidence interval for log_DBMT estimate at nth 4 | %window assuming num_seq number of tapers were used in that 5 | %estimate. The multiplier can be changed to obtain any other 6 | %confidence level. 7 | % 8 | % Inputs: 9 | % n = window number 10 | % num_seq = # of tapers used 11 | % 12 | % Outputs: 13 | % final_Confidence_bounds(:,1) = upper confidence bound 14 | % final_Confidence_bounds(:,2) = lower confidence bound 15 | 16 | 17 | multiplier = 2.326; % From normal table 18 | Fs = 110; % in Hz , Sampling Frequency (Change Accordingly) 19 | W = 6; % s , Window length (Change Accordingly) 20 | W = W*Fs; 21 | final_est = 0; 22 | final_Confidence_bounds = 0; 23 | pathname = fileparts('./log_DBMT/file'); 24 | for j = 1:num_seq 25 | file_name = sprintf('taper%d.mat',j); 26 | matfile = fullfile(pathname, file_name); 27 | load(matfile); 28 | x_n = x(:,n); 29 | variance_n = P(:,:,n); 30 | Confidence_bounds = [x_n + multiplier*sqrt(diag(variance_n)),x_n - multiplier*sqrt(diag(variance_n))]; 31 | % figure, plot(x_n); 32 | % hold on; 33 | % plot(Confidence_bounds(:,1),'g'); 34 | % plot(Confidence_bounds(:,2),'r'); 35 | 36 | final_est = final_est + exp(x_n); 37 | final_Confidence_bounds = final_Confidence_bounds + exp(Confidence_bounds); 38 | 39 | end 40 | 41 | final_est = final_est/3; 42 | final_Confidence_bounds = final_Confidence_bounds/3; 43 | 44 | plot((0:120)/6,10*log10(final_est(1:121)/Fs)); 45 | hold on 46 | plot((0:120)/6,10*log10(final_Confidence_bounds(1:121,1)/Fs),'g'); 47 | plot((0:120)/6,10*log10(final_Confidence_bounds(1:121,2)/Fs),'r'); 48 | xlim([0 20]); 49 | ylim([-80 20]); 50 | grid on 51 | xlabel('Frequency(Hz)','Interpreter','Latex'); 52 | ylabel('PSD(in dB)','Interpreter','Latex'); 53 | legend('Est','Upper Bound','Lower Bound','Location','Northwestoutside'); 54 | end 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DBMT 2 | Dynamic Bayesian Multitaper Estimation MATLAB Codes 3 | 4 | Description: This repository contains implementations of the algorithms developed in Dynamic Bayesian Multi Taper estimation paradigm. 5 | 6 | Copyright (c) 2017 Proloy Das All Rights Reserved 7 | 8 | Contact: proloy@umd.edu 9 | 10 | Citation: If you find these piece of codes helpful in your reserach, please cite any/both of the following papers- 11 | 12 | (1)P. Das and B. Babadi, Dynamic Bayesian Multitaper Spectral Analysis; IEEE Trans. on Signal Processing, vol. 66, no. 6, pp. 1394-1409, March15, 15 2018. (Link: https://doi.org/10.1109/TSP.2017.2787146) 13 | 14 | (2)P. Das, B. Babadi, A Bayesian Multitaper Method for Nonstationary Data with Application to EEG Analysis; 2017 IEEE Signal Processing in Medicine and Biology Symposium (SPMB17), Dec. 2, Philadelphia, PA. (Link: https://www.isip.piconepress.com/conferences/ieee_spmb/2017/papers/l04_05.pdf) 15 | 16 | Date: June 5, 2017 17 | 18 | Requirements: 19 | implemented in Matlab R2016b version, but should run on most versions. 20 | 21 | Contents: 22 | 23 | 1. main.m: Master script. 24 | 2. TSpectrogram.m: genrates single taper sSpectrogram estimates. 25 | 2. MTSpectrogram.m: genrates overlapped multi taper spectrogram estimates. 26 | 3. DBMTSpectrogram.m: genrates DBMT estimates. 27 | 4. log_DBMTSpectrogram.m: genrates log_DBMT estimates. 28 | 5. DBMT_EM.m: EM step for DBMT algorithm. 29 | 6. log_DBMT_EM.m: EM step for log-DBMT algorithm. 30 | 7. Window_then_Taper.m: Segments the data and then multiplyes by taper (Used in DBMTSpectrogram). 31 | 8. Post_mode_var.m: Calculates posterior mode and variance in log_DBMT algorithm. 32 | 9. confidence_interval_CMT.m: plots 95% confidence interval of conventional multitaper estimates of a single window. 33 | 10. confidence_interval_DBMT.m: plots 95% confidence interval for DBMT estimate of a single window. 34 | 11. confidence_interval_log_DBMT.m: plots 95% confidence interval for log_DBMT estimate of a single window. 35 | 36 | 37 | Instructions: Simple and easy. 38 | Download all the codes in a directory and run main.m, that will generate one toy_example, its three spectrogram estimates as well as 39 | the true estimate. It also compares estimates of a single window, while constructing the confidence intervals. To use 40 | the functions individually please look at the function descriptions. 41 | 42 | Additional Note: Make sure that 3 folders (named CMT, DBMT, log_DBMT) is created after running the main script, they are necessary for 43 | constructing confidence intervals. 44 | -------------------------------------------------------------------------------- /DBMTSpectrogram.m: -------------------------------------------------------------------------------- 1 | function [ final_est ] = DBMTSpectrogram( y,W,K,U,time_halfbandwidth,num_tapers,Fs ) 2 | %[ final_est ] = DBMTSpectrogram( y,W,K,U,time_halfbandwidth,num_tapers,Fs ) computes DBMT 3 | % spectrogram of time-series data. 4 | % 5 | % Outputs: 6 | % final_est = DBMT estimate 7 | % 8 | %Inputs: 9 | % y = Data 10 | % W = window length in seconds 11 | % K = # of frequency bin 12 | % U = # of frequency points to be estimated 13 | % time_halfbandwidth = N*B 14 | % num_tapers = # of tapers to be used 15 | % Fs = Sampling Frequency 16 | 17 | W = W*Fs; 18 | N = floor(length(y)/W); %# of windows 19 | TOL = 3*10^-3; 20 | final_est = 0; 21 | max_iter = 40; % usually takes <10 iterations 22 | 23 | sigma2 = 0.0001; % sigma2 and Q^{[0]} needs to be chosen for faster convergence 24 | alpha = 0; 25 | 26 | %**********************generate dpss_sequences***************************** 27 | seq_length = W; 28 | [dps_seq,lambda] = dpss(seq_length,time_halfbandwidth,num_tapers); 29 | 30 | offset = 1; 31 | %**************************Fourier matrix********************************** 32 | F = zeros(W,2*U,N); 33 | for j = 1:N 34 | thetac = ((j-1)*W+(0:W-1))'*(1:U); 35 | thetas = ((j-1)*W+(0:W-1))'*(K/2+(K/2-1-U+1:K/2-1)); 36 | % thetac = ((j-1)*W+(0:W-1))'*(offset:U+offset-1); 37 | % thetas = ((j-1)*W+(0:W-1))'*(K/2+(K/2-U+1-offset:K/2-offset)); 38 | F(:,:,j) = [cos(2*pi/K*thetac), sin(2*pi/K*thetas)]; %/sqrt(U+1) 39 | end 40 | 41 | for seq_num = 1:1:num_tapers 42 | processed_data = Window_then_Taper(y,dps_seq(:,seq_num)); 43 | % x = 0*ones(2*U+1,N); %k|k or k|N 44 | x = 0*ones(2*U,N); %k|k or k|N 45 | tic 46 | [x_sol,alpha] = DBMT_EM(seq_num,x,F,N,W,U,processed_data,sigma2,alpha,TOL,max_iter); 47 | alpha = 0; 48 | toc 49 | est = zeros(U,N); 50 | for k = 1:N 51 | % est(:,k) = [(x_sol(1,k))^2;((x_sol(2:U+1,k)).^2+flipud((x_sol(U+2:2*U+1,k).^2)))/4]; 52 | est(:,k) = ((x_sol(1:U,k)).^2+flipud((x_sol(U+1:2*U,k).^2)))/4; 53 | end 54 | final_est = final_est + lambda(seq_num) * est; 55 | end 56 | final_est = final_est/num_tapers; 57 | %****************************Plot upto 20 Hz******************************* 58 | K = W; 59 | W1 = floor(length(y)/K - W/K); 60 | pcolor(((0:1:W1)*K+W/2)/Fs,Fs*(1:(20*W/Fs))/W,10*log10(W^2*final_est(1:20*W/Fs,:)/Fs)); 61 | ylim([0 20]); 62 | shading flat; 63 | colormap('jet'); 64 | colorbar; 65 | xlabel('Time(s)','Interpreter','Latex'); 66 | ylabel('Frequency(Hz)','Interpreter','Latex'); 67 | title('DBMTSpectogram','Interpreter','Latex'); 68 | drawnow 69 | end 70 | 71 | -------------------------------------------------------------------------------- /confidence_interval_DBMT.m: -------------------------------------------------------------------------------- 1 | function [ final_Confidence_bounds ] = confidence_interval_DBMT( n, num_seq ) 2 | %[ final_Confidence_bounds ] = confidence_interval_DBMT(n, num_seq) 3 | %plots 95% confidence interval for DBMT estimate at nth window 4 | %assuming num_seq number of tapers were used in that estimate. 5 | %The multiplier can be changed to obtain any other 6 | %confidence level. 7 | % 8 | % 9 | % Inputs: 10 | % n = window number 11 | % num_seq = # of tapers used 12 | % 13 | % Outputs: 14 | % final_Confidence_bounds(:,1) = upper confidence bound 15 | % final_Confidence_bounds(:,2) = lower confidence bound 16 | 17 | multiplier = 2.326; % From normal table 18 | Fs = 110; % in Hz , Sampling Frequency (Change Accordingly) 19 | W = 6; % s , Window length (Change Accordingly) 20 | W = W*Fs; 21 | final_est = 0; 22 | final_Confidence_bounds = 0; 23 | pathname = fileparts('./DBMT/file'); 24 | for j = 1:num_seq 25 | file_name = sprintf('taper%d.mat',j); 26 | matfile = fullfile(pathname, file_name); 27 | load(matfile); 28 | x_n = x(:,n); 29 | variance_n = P(:,:,n); 30 | Confidence_bounds = [x_n + multiplier*sqrt(diag(variance_n)),x_n - multiplier*sqrt(diag(variance_n))]; 31 | % figure, plot(x); 32 | % hold on; 33 | % plot(Confidence_bounds(:,1),'g'); 34 | % plot(Confidence_bounds(:,2),'r'); 35 | 36 | Confidence_bounds1 = zeros(size(Confidence_bounds)); 37 | for i = 1:length(x_n) 38 | if Confidence_bounds(i,1)*Confidence_bounds(i,2) < 0 39 | Confidence_bounds1(i,:) = [max(Confidence_bounds(i,:).^2),10^-15]; 40 | else 41 | Confidence_bounds1(i,:) = sort((Confidence_bounds(i,:)).^2,'descend'); 42 | end 43 | end 44 | % figure, plot(x.^2); 45 | % hold on; 46 | % plot(Confidence_bounds1(:,1),'g'); 47 | % plot(Confidence_bounds1(:,2),'r'); 48 | 49 | est = (x_n(1:length(x_n)/2).^2 + flipud(x_n(length(x_n)/2+1:length(x_n))).^2)/4; 50 | Confidence_bounds2 = (Confidence_bounds1(1:length(x_n)/2,:) + flipud(Confidence_bounds1(1+length(x_n)/2:end,:)))/4; 51 | % figure, plot(est); 52 | % hold on 53 | % plot(Confidence_bounds2(:,1),'g'); 54 | % plot(Confidence_bounds2(:,2),'r'); 55 | 56 | final_est = final_est + est; 57 | final_Confidence_bounds = final_Confidence_bounds + Confidence_bounds2; 58 | end 59 | final_est = final_est/3; 60 | final_Confidence_bounds = final_Confidence_bounds/3; 61 | 62 | plot((1:120)/6,10*log10(W^2*final_est((1:120))/Fs)); 63 | hold on 64 | plot((1:120)/6,10*log10(W^2*final_Confidence_bounds(1:120,1)/Fs),'g'); 65 | plot((1:120)/6,10*log10(W^2*final_Confidence_bounds(1:120,2)/Fs),'r'); 66 | xlim([0 20]); 67 | ylim([-80 20]); 68 | grid on 69 | xlabel('Frequency(Hz)','Interpreter','Latex'); 70 | ylabel('PSD(in dB)','Interpreter','Latex'); 71 | legend('Est','Upper Bound','Lower Bound','Location','Northwestoutside'); 72 | 73 | end 74 | 75 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | %Dynamic Bayesian Multi Taper Estimation algorithms 2 | %Master script to regenerate the Fig. 3 in Dynamic Bayesian Multitaper 3 | %Spectral Analysis. 4 | 5 | clear all 6 | mkdir CMT 7 | mkdir DBMT 8 | mkdir log_DBMT 9 | %*************************Generation of Toy Example*********************** 10 | T = 600; % in s 11 | Fs = 110; 12 | f0 = 0.02; % in Hz 13 | f1 = 11; %in Hz 14 | f2 = 5; % in Hz; 15 | t = 0:(T/(Fs*600-1)):T; 16 | sigma_b = 6*10^-4; 17 | sigma_a = 1*10^-5; 18 | 19 | %************************Amplitude Modulated Component********************* 20 | b = conv(conv(conv([1 -0.98*exp(1j*2*(pi)*f1/110)],[1 -0.98*exp(-1j*2*(pi)*f1/110)]),conv([1 -0.98*exp(1j*2*(pi)*f1/110)],[1 -0.98*exp(-1j*2*(pi)*f1/110)])),conv([1 -0.95*exp(1j*2*(pi)*f1/110)],[1 -0.95*exp(-1j*2*(pi)*f1/110)])); 21 | y1 = filter(1,b,sigma_b*randn(size(t))); 22 | y1 = y1(end-66000+1:end).*((cos(2*pi*f0*t)).^8+0.1); 23 | 24 | %************************Frequency Modulated Component********************* 25 | f2d = f2-12/25; 26 | a = conv(conv(conv([1 -0.95*exp(1j*(2*pi)*f2d/110)],[1 -0.95*exp(-1j*2*(pi)*f2d/110)]),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])); 27 | c = conv(conv([1 1],[1 1]),conv([1 1],[1 1])); 28 | y2 = filter(c,a,0.1*randn(5*110,1)); 29 | for k = 1:25 30 | f2d = f2d+12/25; 31 | a = conv(conv(conv([1 -0.95*exp(1j*(2*pi)*f2d/110)],[1 -0.95*exp(-1j*2*(pi)*f2d/110)]),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])); 32 | y_inter = filter(c,a,sigma_a*randn(26*110,1)*(1.17)^(k-1)); 33 | y2 = [y2;y_inter(221:26*110)]; 34 | end 35 | y2 = y2(end-66000+1:end); 36 | 37 | %******************************True data y_true**************************** 38 | y_true = y1' + y2; 39 | % figure, plot(t,y_true,'k'); 40 | % xlabel('time','Interpreter','Latex'); 41 | % ylabel('Amplitude','Interpreter','Latex'); 42 | 43 | %**************************Noisy version of data, y************************ 44 | sigma_n = sqrt(var(y_true)/10^(30/10)); 45 | y = y_true + sigma_n*randn(size(y_true)); 46 | 47 | figure, plot(t,y,'k'); 48 | title('Noisy AR process'); 49 | xlabel('time','Interpreter','Latex'); 50 | ylabel('Amplitude','Interpreter','Latex') 51 | 52 | %****************************Ground Truth*********************************** 53 | sigma_b =(5*10^-4); 54 | [Hb,Freq] = freqz(1,b,330,Fs); 55 | % figure, plot(Freq, 20*log10(abs(Hb))); 56 | var_b = cos(2*pi*f0*t).^8; 57 | PSDb = []; 58 | for n = 1:100 59 | PSDb = [PSDb, (sigma_b*(mean(var_b((n-1)*660+1:n*660))+0.1).^2)*(Hb)]; 60 | end 61 | f2d = f2-12/25; 62 | a = conv(conv(conv([1 -0.95*exp(1j*(2*pi)*f2d/110)],[1 -0.95*exp(-1j*2*(pi)*f2d/110)]),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])); 63 | c = conv(conv([1 1],[1 1]),conv([1 1],[1 1])); 64 | PSDa = []; 65 | for k = 1:25 66 | f2d = f2d+12/25; 67 | a = conv(conv(conv([1 -0.95*exp(1j*(2*pi)*f2d/110)],[1 -0.95*exp(-1j*2*(pi)*f2d/110)]),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])),conv([1 -0.98*exp(1j*2*(pi)*f2d/110)],[1 -0.98*exp(-1j*2*(pi)*f2d/110)])); 68 | [Ha,Freq] = freqz(c,a,330,Fs); 69 | PSDa = [PSDa, (1.17)^(k-1)*(sigma_a*(Ha)),(1.17)^(k-1)*(sigma_a*(Ha)),(1.17)^(k-1)*(sigma_a*(Ha)),(1.17)^(k-1)*(sigma_a*(Ha))]; 70 | end 71 | PSD_y = 10*log10((abs(PSDa+PSDb).^2+sigma_n^2)/(Fs)); 72 | PSD_true = 10*log10((abs(PSDa+PSDb).^2)/(Fs)); 73 | figure, 74 | subplot(4,1,1), pcolor(((0:99)'+0.5)*6,Freq(1:300),PSD_y(1:300,1:100)); 75 | ylim([0 20]); 76 | caxis([-50 15]); 77 | shading flat; 78 | colormap('jet'); 79 | colorbar; 80 | xlabel('Time(s)','Interpreter','Latex'); 81 | ylabel('Frequency(Hz)','Interpreter','Latex'); 82 | title('Ground Truth','Interpreter','Latex'); 83 | drawnow 84 | %*****************************Estimates************************************ 85 | W = 6; % 6 s window-length 86 | R = Fs*6; % freq resolution 87 | U = 329; % # of frequency bins to be estimated 88 | N = floor(length(y)/(Fs*W)); 89 | rho = 3; 90 | K = 3; % # of tapers 91 | 92 | %************************Multitaper Spectrogram**************************** 93 | overlap = 0.5; % 50% Overlap 94 | subplot(4,1,2), 95 | mtm_est = MTSpectrogram(y,W,overlap,rho,K,Fs); 96 | caxis([-50 15]); 97 | 98 | %***************************DBMT Spectrogram******************************* 99 | subplot(4,1,3), 100 | DBMT_est = DBMTSpectrogram(y,W,R,U,rho,K,Fs); 101 | caxis([-50 15]); 102 | 103 | %*************************log_DBMT Spectrogram***************************** 104 | subplot(4,1,4), 105 | log_DBMT_est = log_DBMTSpectrogram(y,W,U,rho,K,Fs); 106 | caxis([-50 15]); 107 | 108 | %*****Confidence Intervals for window starting at t = 79*6 = 477 sec******* 109 | figure, 110 | subplot(4,1,1), 111 | plot(Freq(1:150),PSD_y(1:150,79)) 112 | hold on 113 | plot(Freq(1:150),PSD_true(1:150,79)) 114 | xlim([0 20]); 115 | ylim([-80 20]); 116 | xlabel('Frequency(Hz)','Interpreter','Latex'); 117 | ylabel('PSD(in dB)','Interpreter','Latex'); 118 | legend('Noisy','True','Location','Northwestoutside'); 119 | grid on 120 | subplot(4,1,2) 121 | confidence_interval_CMT(157,3); 122 | plot(Freq(1:150),PSD_y(1:150,79),'k-.'); %reference 123 | subplot(4,1,3) 124 | confidence_interval_DBMT(79,3); 125 | plot(Freq(1:150),PSD_true(1:150,79),'k-.'); %reference 126 | subplot(4,1,4) 127 | confidence_interval_log_DBMT(79,3); 128 | plot(Freq(1:150),PSD_y(1:150,79),'k-.'); %reference 129 | -------------------------------------------------------------------------------- /DBMT_EM.m: -------------------------------------------------------------------------------- 1 | function [ x_sol, alpha_sol ] = DBMT_EM( num,x,F,N,W,U,data,sigma2,alpha,TOL,max_iter ) 2 | %[ x_sol, alpha_sol ] = DBMT_EM( num,x,F,N,W,U,data,sigma2,alpha,TOL,max_iter ) 3 | % implements EM algorithm required for DBMT analysis. 4 | % 5 | % Outputs: 6 | % x_sol = time-frequency representation 7 | % alpha_sol = Estimated Smoothing Parameter 8 | % 9 | % Inputs: 10 | % num = sequence number 11 | % data = data 12 | % x = initial guess 13 | % F = Fourier matrix 14 | % N = # of windows 15 | % W = Window length 16 | % U = # of frequency bins 17 | % sigma2 = \sigma^2, observation noise variance 18 | % alpha = initial guess for smoothing parameter(usually 0) 19 | % TOL = tolerence for convergence 20 | % max_iter = maximum # of of iteration 21 | 22 | x0 = 0*ones(2*U,N); %Dummy 23 | % x = 0*ones(2*U+1,N); %k|k or k|N 24 | x1 = 0*ones(2*U,N); %k|k-1 25 | K1 = zeros(2*U,W,N); 26 | 27 | P = zeros(2*U,2*U,N); %k|k or k|N 28 | for i = 1:N 29 | % P(:,:,i) = 0.00001*eye(2*U); 30 | P(:,:,i) = 0.000001*diag(rand(2*U,1)+0.01); 31 | end 32 | P0 = P; %k|k store 33 | P1 = P; %k|k-1 34 | P2 = P; %k-1,k|N 35 | P2(:,:,1) = zeros(2*U,2*U); 36 | 37 | Q = zeros(2*U,2*U,N); %k|k or k|N 38 | for i = 1:N 39 | Q(:,:,i) = 0.000001*diag(rand(2*U,1)+0.01); 40 | end 41 | 42 | B = zeros(2*U,2*U,N); 43 | 44 | variable = []; 45 | 46 | for r = 1:max_iter 47 | %*********************************E step*********************************** 48 | % E step I 49 | for k = 1:N 50 | if k == 1 51 | % one step prediction 52 | x1(:,1) = alpha*zeros(size(x1(:,1))); 53 | % one step variance prediction 54 | P1(:,:,1) = Q(:,:,1); 55 | else 56 | % one step prediction 57 | x1(:,k) = alpha*x(:,k-1); 58 | % one step variance prediction 59 | P1(:,:,k) = alpha^2*P(:,:,k-1) + Q(:,:,k); 60 | end 61 | % K1(:,:,k) = P1(:,:,k)*F(:,:,k)'*((F(:,:,k)*P1(:,:,k)*F(:,:,k)'+sigma2*eye(W))\eye(W)); 62 | K1(:,:,k) = ((F(:,:,k)'*F(:,:,k)/sigma2+(P1(:,:,k)\eye(2*U))))\F(:,:,k)'/sigma2; 63 | % Posteror mode 64 | x(:,k) = x1(:,k) + K1(:,:,k)*(data(:,k)-F(:,:,k)*x1(:,k)); 65 | % posterior variance 66 | P(:,:,k) = P1(:,:,k) - K1(:,:,k)*F(:,:,k)*P1(:,:,k); 67 | end 68 | P0 = P; 69 | % E step II FIS 70 | for k = N-1:-1:1 71 | % B(:,:,k) = alpha*P(:,:,k)*(P1(:,:,k+1)\eye(2*U+1)); 72 | B(:,:,k) = alpha*P(:,:,k)*(P1(:,:,k+1)\eye(2*U)); 73 | % z(k|N) 74 | x(:,k) = x(:,k) + B(:,:,k)*(x(:,k+1)-x1(:,k+1)); 75 | % P(k|N) 76 | P(:,:,k) = P(:,:,k) + B(:,:,k)*(P(:,:,k+1)-P1(:,:,k+1))*(B(:,:,k)'); 77 | end 78 | % E step III state-space covar algorithm 79 | for k = 2:N 80 | P2(:,:,k) = B(:,:,k-1)*P(:,:,k); 81 | end 82 | %*********************************M step*********************************** 83 | %****************************Update alpha********************************** 84 | W1 = 0; 85 | for k = 1:N-1 86 | % W1 = W1 + x(:,k)'*(Q(:,:,k+1)\x(:,k)) + trace(Q(:,:,k+1)\P(:,:,k)); 87 | W1 = W1 + x(:,k).^2./diag(Q(:,:,k+1)) + diag(P(:,:,k))./diag(Q(:,:,k+1)); 88 | end 89 | W1 = sum(W1); 90 | W2 = 0; 91 | for k = 2:N 92 | % W2 = W2 + x(:,k-1)'*(Q(:,:,k)\x(:,k)) + trace(Q(:,:,k)\(P2(:,:,k)+P2(:,:,k)')/2); 93 | W2 = W2 + (x(:,k-1).*x(:,k))./diag(Q(:,:,k)) + diag(P2(:,:,k))./diag(Q(:,:,k)); 94 | end 95 | W2 = sum(W2); 96 | alpha = W2/W1; 97 | 98 | 99 | %*************************Stopping condition******************************* 100 | variable = [variable, norm(x-x0,'fro')/norm(x,'fro')]; 101 | if variable(r) < TOL 102 | break; % Convergence reached 103 | else 104 | %***********************GOTO next iterations******************************* 105 | x0 = x; 106 | P = P0; 107 | Q(:,:,1) = diag(diag(x(:,1)*x(:,1)'+P(:,:,1))); 108 | P2(:,:,1) = Q(:,:,1); 109 | for k = 2:N 110 | % W3 = P2(:,:,k) + x(:,k)*x(:,k-1)'; 111 | Q(:,:,k) = diag((x(:,k)-alpha*x(:,k-1)).^2 + diag(P(:,:,k))+alpha^2*diag(P(:,:,k-1))-2*alpha*diag(P2(:,:,k))); 112 | % Q(:,:,k) = ((x(:,k)*x(:,k)'+P(:,:,k) + alpha^2*(x(:,k-1)*x(:,k-1)'+P(:,:,k-1))-alpha*(W3+W3'))); 113 | end 114 | end 115 | end 116 | 117 | x_sol = x; 118 | alpha_sol = alpha; 119 | 120 | %*********************Save Variables for CI******************************** 121 | pathname = fileparts('./DBMT/file'); 122 | file_name = sprintf('taper%d.mat',num); 123 | matfile = fullfile(pathname, file_name); 124 | save(matfile, 'x', 'P'); 125 | 126 | end 127 | 128 | -------------------------------------------------------------------------------- /log_DBMT_EM.m: -------------------------------------------------------------------------------- 1 | function [ x_sol, alpha_sol ] = log_DBMT_EM( num,x,N,Y,alpha,TOL,max_iter ) 2 | %[ x_sol, alpha_sol ] = log_DBMT_EM( num,x,N,Y,alpha,TOL,max_iter ) 3 | % implements EM algorithm required for log_DBMT analysis. 4 | % 5 | % Outputs: 6 | % x_sol = time-frequency representation 7 | % alpha_sol = Estimated Smoothing Parameter 8 | % 9 | % Inputs: 10 | % num = sequence number 11 | % x = initial guess 12 | % N = # of windows 13 | % Y = data, noisy spectral estimates 14 | % alpha = initial guess for smoothing parameter(usually 0) 15 | % TOL = tolerence for convergence 16 | % max_iter = maximum # of of iteration 17 | 18 | x0 = 0*ones(size(Y)); %Dummy 19 | % x = 0*ones(2*U+1,N); %k|k or k|N 20 | x1 = 0*ones(size(Y)); %k|k-1 21 | 22 | P = zeros(size(Y,1),size(Y,1),N); %k|k or k|N 23 | for i = 1:N 24 | P(:,:,i) = 10^-1*eye(size(Y,1)); 25 | end 26 | P0 = P; %k|k store 27 | P1 = P; %k|k-1 28 | P2 = P; %k-1,k|N 29 | P2(:,:,1) = zeros(size(Y,1),size(Y,1)); 30 | 31 | Q = zeros(size(Y,1),size(Y,1),N); %k|k or k|N 32 | for i = 1:N 33 | Q(:,:,i) = 10^-1*eye(size(Y,1)); 34 | end 35 | 36 | B = zeros(size(Y,1),size(Y,1),N); 37 | 38 | variable = []; 39 | 40 | nu = 2; % initialize nu 41 | 42 | for r = 1:max_iter 43 | %*********************************E step*********************************** 44 | % E step I 45 | for k = 1:N 46 | if k == 1 47 | % one step prediction 48 | x1(:,1) = alpha*zeros(size(x1(:,1))); 49 | % one step variance prediction 50 | P1(:,:,1) = Q(:,:,1); 51 | else 52 | % one step prediction 53 | x1(:,k) = alpha*x(:,k-1); 54 | % one step variance prediction 55 | P1(:,:,k) = alpha^2*P(:,:,k-1) + Q(:,:,k); 56 | end 57 | % Posteror mode and posterior variance 58 | [x(:,k),P(:,:,k)] = Post_mode_var(Y(:,k), x1(:,k), nu, P1(:,:,k)); 59 | end 60 | P0 = P; 61 | % E step II FIS 62 | for k = N-1:-1:1 63 | B(:,:,k) = alpha*P(:,:,k)*(P1(:,:,k+1)\eye(size(Y,1))); 64 | % z(k|N) 65 | x(:,k) = x(:,k) + B(:,:,k)*(x(:,k+1)-x1(:,k+1)); 66 | % P(k|N) 67 | P(:,:,k) = P(:,:,k) + B(:,:,k)*(P(:,:,k+1)-P1(:,:,k+1))*(B(:,:,k)'); 68 | end 69 | % E step III state-space covar algorithm 70 | for k = 2:N 71 | P2(:,:,k) = B(:,:,k-1)*P(:,:,k); 72 | end 73 | %*********************************M step*********************************** 74 | %****************************Update alpha********************************** 75 | W1 = 0; 76 | for k = 1:N-1 77 | % W1 = W1 + x(:,k)'*(Q(:,:,k+1)\x(:,k)) + trace(Q(:,:,k+1)\P(:,:,k)); 78 | W1 = W1 + x(:,k).^2./diag(Q(:,:,k+1)) + diag(P(:,:,k))./diag(Q(:,:,k+1)); 79 | end 80 | W1 = sum(W1); 81 | W2 = 0; 82 | for k = 2:N 83 | % W2 = W2 + x(:,k-1)'*(Q(:,:,k)\x(:,k)) + trace(Q(:,:,k)\(P2(:,:,k)+P2(:,:,k)')/2); 84 | W2 = W2 + (x(:,k-1).*x(:,k))./diag(Q(:,:,k)) + diag(P2(:,:,k))./diag(Q(:,:,k)); 85 | end 86 | W2 = sum(W2); 87 | alpha = W2/W1; 88 | 89 | %*****************************Update nu************************************ 90 | cnst = 0; 91 | for k = 1:N 92 | cnst = cnst + sum(Y(:,k)-x(:,k)-exp(Y(:,k)-x(:,k))); 93 | end 94 | cnst = cnst/(N*size(Y,1)); 95 | f = @(nu) log(gamma(nu)) - nu*log(2*nu) - (cnst+1)*nu; 96 | df =@(nu) psi(nu) - log(nu) - (cnst+1); 97 | d2f =@(nu) psi(1,nu) - 1/nu; 98 | tau = 1; 99 | nu = 1; 100 | dir = -df(nu)/d2f(nu); 101 | for k = 1:100 102 | while nu+tau*dir < 0.01 103 | tau = tau/2; 104 | if tau < 10^-10 105 | break 106 | end 107 | end 108 | nu = nu + tau * dir; 109 | dir = -df(nu)/d2f(nu); 110 | if -df(nu)*dir < 10^-4 || tau < 10^-10 111 | break 112 | end 113 | tau = 1; 114 | end 115 | fprintf('itr = %d, nu = %f \n', r,nu); 116 | 117 | 118 | %*************************Stopping condition******************************* 119 | variable = [variable, norm(x-x0,'fro')/norm(x,'fro')]; 120 | if variable(end) < TOL 121 | break; % Convergence reached 122 | else 123 | %***********************GOTO next iterations******************************* 124 | x0 = x; 125 | %***********************************Update Q******************************* 126 | Q(:,:,1) = diag(diag(x(:,1)*x(:,1)'+P(:,:,1))); 127 | P2(:,:,1) = Q(:,:,1); 128 | for k = 2:N 129 | % W3 = P2(:,:,k) + x(:,k)*x(:,k-1)'; 130 | Q(:,:,k) = diag((x(:,k)-alpha*x(:,k-1)).^2 + diag(P(:,:,k))+alpha^2*diag(P(:,:,k-1))-2*alpha*diag(P2(:,:,k))); 131 | % Q(:,:,k) = ((x(:,k)*x(:,k)'+P(:,:,k) + alpha^2*(x(:,k-1)*x(:,k-1)'+P(:,:,k-1))-alpha*(W3+W3'))); 132 | end 133 | end 134 | end 135 | 136 | x_sol = x; 137 | alpha_sol = alpha; 138 | 139 | %*********************Save Variables for CI******************************** 140 | pathname = fileparts('./log_DBMT/file'); 141 | file_name = sprintf('taper%d.mat',num); 142 | matfile = fullfile(pathname, file_name); 143 | save(matfile, 'x', 'P'); 144 | 145 | end 146 | 147 | --------------------------------------------------------------------------------