function [spec, f, err] = dmtspec(X, tapers, sampling, fk, pad, pval, flag) % DMTSPEC calculates the direct multitaper spectral estimate for time series. % % [SPEC, F, ERR] = DMTSPEC(X, TAPERS, SAMPLING, FK, PAD, PVAL, FLAG) % % Inputs: X = Time series array in [Space/Trials,Time] form. % TAPERS = Data tapers in [K,TIME], [N,P,K] or [N,W] form. % Defaults to [N,3,5] where N is duration of X. % SAMPLING = Sampling rate of time series X in Hz. % Defaults to 1. % FK = Frequency range to return in Hz in % either [F1,F2] or [F2] form. % In [F2] form, F1 is set to 0. % Defaults to [0,SAMPLING/2] % PAD = Padding factor for the FFT. % i.e. For N = 500, if PAD = 2, we pad the FFT % to 1024 points; if PAD = 4, we pad the FFT % to 2048 points. % Defaults to 2. % PVAL = P-value to calculate error bars for. % Defaults to 0.05 i.e. 95% confidence. % % FLAG = 0: calculate SPEC seperately for each channel/trial. % FLAG = 1: calculate SPEC by pooling across channels/trials. % % Outputs: SPEC = Spectrum of X in [Space/Trials, Freq] form. % F = Units of Frequency axis for SPEC. % ERR = Error bars for SPEC in [Hi/Lo, Space/Trials, Freq] % form given by a Jacknife-t interval for PVAL. % % Modification History: % Written by: Bijan Pesaran, 08/97 % Modified: Added error bars BP 08/27/98 sX = size(X); nt = sX(2); nch = sX(1); % Set the defaults if nargin < 3 sampling = 1; end nt = nt./sampling; if nargin < 2 tapers = [nt,3,5]; end if length(tapers) == 2 n = tapers(1); w = tapers(2); p = n*w; k = floor(2*p-1); tapers = [n,p,k]; % disp(['Using ' num2str(k) ' tapers.']); end if length(tapers) == 3 tapers(1) = floor(tapers(1).*sampling); tapers = dpsschk(tapers); end if nargin < 4 fk = [0,sampling./2]; end if length(fk) == 1 fk = [0,fk]; end if nargin < 5 pad = 2; end if nargin < 6 pval = 0.05; end if nargin < 7 flag = 0; end N = length(tapers(:,1)); nt = floor(nt.*sampling); if N ~= nt error('Error: Length of time series and tapers must be equal'); end K = length(tapers(1,:)); nf = max(256,pad*2.^(nextpow2(N+1))); nfk = floor(fk./sampling.*nf); dof = 2.*nch.*K; % Determine outputs f = linspace(fk(1),fk(2),diff(nfk)); errorchk = 0; if nargout > 2 errorchk = 1; end if ~flag % No pooling across trials spec = zeros(nch, diff(nfk)); err = zeros(2, nch, diff(nfk)); for ch=1:nch tmp = detrend(X(ch,:))'; xk = fft(tapers(:,1:K).*tmp(:,ones(1,K)),nf)'; xk = xk(:,nfk(1)+1:nfk(2)); Sk = abs(xk).^2; spec(ch,:) = mean(Sk,1); if errorchk % Estimate error bars using Jacknife for ik = 1:K indices = setdiff([1:K],[ik]); xj = xk(indices,:); jlsp(ik,:) = log(mean(abs(xj).^2,1)); end lsig = sqrt(K-1).*std(jlsp,1); crit = tinv(1-pval./2,dof-1); % Determine the scaling factor err(1,ch,:) = exp(log(spec(ch,:))+crit.*lsig); err(2,ch,:) = exp(log(spec(ch,:))-crit.*lsig); end end end if flag % Pooling across trials spec = zeros(1, diff(nfk)); err = zeros(2, diff(nfk)); Xk = zeros(nch*K, diff(nfk)); for ch=1:nch tmp = detrend(X(ch,:))'; xk = fft(tapers(:,1:K).*tmp(:,ones(1,K)),nf)'; Xk((ch-1)*K+1:ch*K,:) = xk(:,nfk(1)+1:nfk(2)); end spec = mean(abs(Xk).^2,1); if errorchk % Estimate error bars using Jacknife for ik = 1:nch*K indices = setdiff([1:K*nch],[ik]); xj = Xk(indices,:); jlsp(ik,:) = log(mean(abs(xj).^2,1)); end lsig = sqrt(nch*K-1).*std(jlsp,1); crit = tinv(1-pval./2,dof-1); % Determine the scaling factor err(1,:) = exp(log(spec)+crit.*lsig); err(2,:) = exp(log(spec)-crit.*lsig); end end