mtspectrumc_unequal_length_trials.m 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. function [ S, f, Serr ]= mtspectrumc_unequal_length_trials( data, movingwin, params, sMarkers )
  2. % This routine computes the multi-taper spectrum for a given set of unequal length segments. It is
  3. % based on modifications to the Chronux routines. The segments are continuously structured in the
  4. % data matrix, with the segment boundaries given by markers. Below,
  5. % movingwin is used in a non-overlaping way to partition each segment into
  6. % various windows. Th spectrum is evaluated for each window, and then the
  7. % window spectrum estimates averaged. Further averaging is conducted by
  8. % repeating the process for each segment.
  9. %
  10. % Inputs:
  11. %
  12. % data = data( samples, channels )- here segments must be stacked
  13. % as explained in the email
  14. % movingwin = [window winstep] i.e length of moving
  15. % window and step size. Note that units here have
  16. % to be consistent with units of Fs. If Fs=1 (ie normalized)
  17. % then [window winstep]should be in samples, or else if Fs is
  18. % unnormalized then they should be in time (secs).
  19. % sMarkers = N x 2 array of segment start & stop marks. sMarkers(n, 1) = start
  20. % sample index; sMarkers(n,2) = stop sample index for the nth segment
  21. % params = see Chronux help on mtspecgramc
  22. %
  23. % Output:
  24. %
  25. % S frequency x channels
  26. % f frequencies x 1
  27. % Serr (error bars) only for err(1)>=1
  28. %
  29. %
  30. iwAvg = 1; % 0=no weighted average, 1=weighted average
  31. debug = 0; % will display intermediate calcs.
  32. if nargin < 2; error('Unequal length trials:: Need data and window parameters'); end;
  33. if nargin < 3; params=[]; end;
  34. if isempty( sMarkers ), error( 'Unequal length trials:: Need Markers...' ); end
  35. [ tapers, pad, Fs, fpass, err, trialave, params ] = getparams( params );
  36. if nargout > 2 && err(1)==0;
  37. % Cannot compute error bars with err(1)=0. change params and run again.
  38. error('Unequal length trials:: When Serr is desired, err(1) has to be non-zero.');
  39. end;
  40. % Set moving window parameters to no-overlapping
  41. if abs(movingwin(2) - movingwin(1)) >= 1e-6, disp( 'avgSpectrum:: Warming: Window parameters for averaging should be non-overlapping. Set movingwin(2) = movingwin(1).' ); end
  42. wLength = round( Fs * movingwin(1) ); % number of samples in window
  43. wStep = round( movingwin(2) * Fs ); % number of samples to step through
  44. % Check whether window lengths satify segment length > NW/2
  45. if ( wLength < 2*tapers(1) ), error( 'avgSpectrum:: movingwin(1) > 2*tapers(1)' ); end
  46. % Left align segment markers for easier coding
  47. sM = ones( size( sMarkers, 1 ), 2 );
  48. sM( :, 2 ) = sMarkers( :, 2 ) - sMarkers( :, 1 ) + 1;
  49. % min-max segments
  50. Nmax = max( sM(:,2) ); Nmin = min( sM(:,2) );
  51. if ( Nmin < 2*tapers(1) ), error( 'avgSpectrum:: Smallest segment length > 2*tapers(1). Change taper settings' ); end
  52. % max time-sample length will be the window length.
  53. nfft = 2^( nextpow2( wLength ) + pad );
  54. [ f, findx ] = getfgrid( Fs, nfft, fpass);
  55. % Precompute all the tapers
  56. sTapers = tapers;
  57. sTapers = dpsschk( sTapers, wLength, Fs ); % compute tapers for window length
  58. nChannels = size( data, 2 );
  59. nSegments = size( sMarkers, 1 );
  60. if debug
  61. disp( ['Window Length = ' num2str(wLength)] );
  62. disp( ['Window Step = ' num2str(wStep)] );
  63. disp( ' ' );
  64. end
  65. s = zeros( length(f), nChannels );
  66. serr = zeros( 2, length(f), nChannels );
  67. S = zeros( length(f), nChannels );
  68. Serr = zeros( 2, length(f), nChannels );
  69. nWins = 0;
  70. for sg = 1 : nSegments
  71. % Window lengths & steps fixed above
  72. % For the given segment, compute the positions & number of windows
  73. N = sM(sg,2);
  74. wStartPos = 1 : wStep : ( N - wLength + 1 );
  75. nWindows = length( wStartPos );
  76. if nWindows
  77. nWins = nWins + nWindows; % for averaging purposes
  78. w=zeros(nWindows,2);
  79. for n = 1 : nWindows
  80. w(n,:) = [ wStartPos(n), (wStartPos(n) + wLength - 1) ]; % nWindows x 2. just like segment end points
  81. end
  82. % Shift window limits back to original sample-stamps
  83. w(:, 1) = w(:,1) + (sMarkers( sg, 1 ) - 1);
  84. w(:, 2) = w(:,2) + (sMarkers( sg, 1 ) - 1);
  85. if debug
  86. disp( ['Segment Start/Stop = ' num2str( w(1,1) ) ' ' num2str( w(end,2) ) ] );
  87. disp( ['Min / Max Window Positions = ' num2str( min(w(:,1)) ) ' ' num2str( max(w(:,1)) ) ] );
  88. disp( ['Total Number of Windows = ' num2str(nWindows) ]);
  89. disp( ' ' );
  90. end
  91. % Pile up window segments similar to segment pileup
  92. wData = zeros( wLength, nChannels, nWindows ); %initialize to avoid fragmentation
  93. for n = 1:nWindows
  94. %wData( :, :, n ) = detrend( data( w(n,1):w(n,2), : ), 'constant' );
  95. wData( :, :, n ) = detrend( data( w(n,1):w(n,2), : ) );
  96. end
  97. % J1 = frequency x taper x nWindows
  98. % J2 = frequency x taper x nWindows x nChannels
  99. J2 = zeros( length(f), tapers(2), nWindows, nChannels ); J2 = complex( J2, J2 );
  100. for c = 1 : nChannels
  101. J1 = mtfftc( squeeze(wData( :, c, : )), sTapers, nfft, Fs ); % FFT for the tapered data
  102. J2( :, :, :, c ) = J1(findx,:,:);
  103. end
  104. % J2 = frequency x taper x nWindows x nChannels
  105. % Inner mean = Average over tapers => frequency x nWindows x nChannels
  106. % Outer mean = Average over windows => frequency x nChannels
  107. dim1 = [length(f), nWindows, nChannels];
  108. dim2 = [length(f), nChannels];
  109. % s = frequency x nChannels
  110. s = reshape( squeeze( mean( reshape( squeeze( mean( conj(J2).*J2, 2 ) ), dim1), 2 ) ), dim2 );
  111. % Now treat the various "windowed data" as "trials"
  112. % serr = 2 x frequency x channels. Output from specerr = 2 x frequency x 1
  113. for c = 1 : nChannels
  114. serr( :, :, c ) = specerr( squeeze( s(:, c ) ), squeeze( J2(:,:,:, c ) ), err, 1 );
  115. end
  116. if iwAvg
  117. % Segment Weighted error estimates.
  118. S = S + nWindows*s;
  119. Serr = Serr + nWindows*serr;
  120. else
  121. S = S + s;
  122. Serr = Serr + serr;
  123. end
  124. else
  125. if debug, disp(['avgSpectrum:: Zero windows for segment: ' num2str(sg) ]); end
  126. end
  127. end
  128. % Segment Weighted error estimates.
  129. % Only over those that had non-zero windows
  130. if nWins && iwAvg
  131. S=S/nWins; Serr=Serr/nWins;
  132. end
  133. if ~nWins
  134. if debug, disp(['avgCoherence:: No segment long enough with movingwin parameters found. Reduce movingwin.' ]); end
  135. end