RS_Processing.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. %% define some variables
  2. clear
  3. % remove recordings
  4. remI = 0; % remove certain recordings from analysis? (0: no, 1: yes)
  5. % define recordings to be removed from analysis (if remI==1)
  6. remRec{1} = []; % in dataset 1 (25 ms)
  7. remRec{2} = []; % in dataset 2 (50 ms)
  8. % select processing options
  9. detrendI = 0; % detrend data? (1: yes, 0: no)
  10. zsNormI = 0; % z-normalise data data? (1: yes, 0: no)
  11. demeanI = 0; % demean data? (this is independent from baseline correction!)
  12. recDurMult = 1; % multiplier of recdur (1 = original rec dur)
  13. % subsample blocks
  14. subSConS = 0; % decide whether to subsample number of blocks in order to have the same number of trials as in oddball condition
  15. % define channels to be processed; type "all" to process all channels
  16. channels = ["Plus"];
  17. % filter settings
  18. type = 1; % 1: Butterworth, 2: IFFT
  19. order = 4;
  20. lowc = [0.1,10,40,45,50]; % low cut frequency in Hz
  21. hic = 1500; % high cut frequency in Hz
  22. nFilt = size(lowc,2)+1; % number of filters used (+1 because of unfiltered data)
  23. % rejection criterion
  24. artRejI = 1; % turn artefact rejection on (1) or off (0)
  25. rejThr = 200; % uV threshold (every trial with min/max value exceeding this will be rejected before averaging)
  26. remTrArtI = 1; % should trigger artifact be removed from the data?
  27. trArtDate = '20231220'; % day before which trigger artifact existed
  28. % baseline correction settings
  29. % TEST
  30. blcWin = 0.005; % length of time window for baseline correction in s
  31. chirpPeak = [0.00648,0.00842]; % amplitude peaks of chirps (first: low, second: high)
  32. blcEnd = chirpPeak; % end of baseline correction window in s (first: low freq chirp, second: high freq chirp)
  33. % speaker distance
  34. spDis = 0.26; % distance from ear to speaker in m (to correct for sound-travel delay)
  35. %% data processing
  36. % name combinations and load data
  37. for repDaSe = 1:2 % run once for each condition
  38. % load DD data (for number of conS trials)
  39. switch repDaSe
  40. case 1
  41. load("DD_avData_Oddball_25ms_SbD.mat")
  42. case 2
  43. load("DD_avData_Oddball_50ms_SbD.mat")
  44. end
  45. % calculate mean number of trials
  46. conST = round(mean(mean(conST{1},1),2));
  47. switch repDaSe
  48. case 1 % 25 ms
  49. repRateName = '_25ms';
  50. case 2 % 50 ms
  51. repRateName = '_50ms';
  52. end
  53. load(['RS_Data',repRateName,'.mat'])
  54. fileName = append("RS_avData",repRateName);
  55. SOAName = repRateName(2:end);
  56. combName = ["Low";"High";"Low_o1st";"High_o1st"];
  57. nComb = size(combName,1); % number of different stimulus combination to be processed
  58. dataAv_cell = cell(1,nComb); % preallocate
  59. dataGrAv_cell = cell(1,nComb); % preallocate
  60. dataSe_cell = cell(1,nComb); % preallocate
  61. filenames_stim_cell = cell(1,nComb); % preallocate
  62. recID_cell = cell(1,nComb); % preallocate
  63. timetrBlck_cell = cell(1,nComb); % preallocate
  64. timetrUnit_cell = cell(1,nComb); % preallocate
  65. pts2begin_cell = cell(1,nComb); % preallocate
  66. nBlcks_cell = cell(1,nComb); % preallocate
  67. nCh_s_cell = cell(1,nComb); % preallocate
  68. nFiles_cell = cell(1,nComb); % preallocate
  69. nFilt_cell = cell(1,nComb); % preallocate
  70. nResp_cell = cell(1,nComb); % preallocate
  71. SOA_cell = cell(1,nComb); % preallocate
  72. stimDur_cell = cell(1,nComb); % preallocate
  73. stimDelay_cell = cell(1,nComb); % preallocate
  74. nBlcksAcc_cell = cell(1,nComb); % preallocate
  75. fs_stim_cell = cell(1,nComb); % preallocate
  76. fs_cell = cell(1,nComb); % preallocate
  77. ch_idx_cell = cell(1,nComb); % preallocate
  78. nameCh_cell = cell(1,nComb); % preallocate
  79. chLbl_cell = cell(1,nComb); % preallocate
  80. pSiResp_cell = cell(1,nComb); % preallocate
  81. stimCat_cell = cell(1,nComb); % preallocate
  82. for c = 1:nComb % run analysis once for each stimulation-combination
  83. switch c % switch dataset depending on loop iteration
  84. case 1
  85. data = Data_Low;
  86. case 2
  87. data = Data_High;
  88. case 3
  89. data = Data_Low_o1st;
  90. case 4
  91. data = Data_High_o1st;
  92. end
  93. % Organise dataset in multiple variables (in separate script)
  94. RS_OrgData
  95. % extract data of channel to be processed NOT FINISHED YET
  96. ch_idx = zeros(nCh_s(1),nFiles,'single'); % preallocate
  97. rec_raw_ch = cell(nFiles,1); % preallocate
  98. recRawCut = zeros(pUnit,nBlcks,nFiles); % preallocate
  99. for f = 1:nFiles
  100. ch_idx(:,f) = find(ismember(chLbl(f,:),nameCh)); % calculate indices of channels to be processed
  101. rec_raw_ch{f} = rec_raw{f}(ch_idx(:,f),:); % pick data from channels to be processed
  102. recRawCut(:,:,f) = cutblockOnset(rec_raw_ch{f},trigs_all(f,:),pUnit,nBlcks); % cut out buffers and overlengths from raw data and split data into step-blocks; ATTENTION: different routine to DD processing (cutblockOnset vs. cutblockTrial)
  103. % if repDaSe==2
  104. % figure; plot(recRawCut(:,:,f)) % plot raw trace to identify artefacts
  105. % end
  106. end
  107. % artefact rejection
  108. nBlcksAcc = zeros(1,nFiles); % preallocate
  109. switch artRejI
  110. case 0 % if artefact rejection is turned off
  111. nBlcksAcc(:) = nBlcks;
  112. case 1 % run if artefact rejection is turned on
  113. % preallocate
  114. maxV = zeros(1,nBlcks,nFiles);
  115. rejIdx = zeros(1,nBlcks,nFiles);
  116. for f = 1:nFiles
  117. for t = 1:nBlcks
  118. maxV(1,t,f) = max(abs(recRawCut(:,t,f))); % find (absolute) max value in each trial
  119. rejIdx(1,t,f) = maxV(:,t,f)<rejThr; % compare max value of trial with rejection threshold, "1" if max is smaller than threshold -> trial will be accepted later
  120. end % repeat for every trial in current file and (level-)step
  121. nBlcksAcc(f) = sum(rejIdx(:,:,f)); % count number of accepted trials for current file and step
  122. recRawCut(:,1:nBlcksAcc(f),f) = recRawCut(:,logical(rejIdx(:,:,f)),f); % apply previously created rejection index-array as logical array on 2nd dimension (trials) of filtered data. Indexing is applied on all filters (5th dim) simultaneously; array is filled only until number of accepted responses is reached (3rd dim), the rest is still filled with zeros
  123. end
  124. end
  125. % remove trigger artifact
  126. if remTrArtI==1
  127. for f = 1:nFiles
  128. switch artDateI(f)
  129. case 0 % if no Stimtrak was used
  130. nArt = 1; % fix only first artifact
  131. case 1 % if Stimtrak was used
  132. nArt = 2; % fix first and second artifact
  133. end
  134. for art = 1:nArt % once for each artifact per stimulus
  135. for r = 1:nResp % once for each stimulus in the block
  136. switch art
  137. case 1
  138. artStart = 0+SOA*(r-1); % start of trigger artifact in s
  139. case 2
  140. artStart = 0.0107+SOA*(r-1); % start of trigger artifact in s
  141. end
  142. if art==1&&r==1 % for the very first artifact per block, add 1 point to not start at 0
  143. artStartPts = round(artStart*fs)+1; % convert start of trigger artifact to points
  144. else
  145. artStartPts = round(artStart*fs); % convert start of trigger artifact to points
  146. end
  147. artDur = 0.0015; % duration of trigger artifact in s
  148. artDurPts = round(artDur*fs); % convert duration of trigger artifact to points
  149. artEndPts = artStartPts+artDurPts; % calculate end of trigger artifact in points
  150. for t = 1:nBlcks
  151. recRawCut(artStartPts:artEndPts,t,f) = linspace(recRawCut(artStartPts,t,f),recRawCut(artEndPts,t,f),artDurPts+1); % replace artifact by linear vector from start to end
  152. end
  153. end
  154. end
  155. end
  156. end
  157. % process data
  158. recPro = recRawCut; % rename
  159. recFilt = zeros(pUnit*nBlcks,nFiles,nFilt-1); % preallocate
  160. for f = 1:nFiles
  161. % detrending
  162. if detrendI==1
  163. recPro(:,1:nBlcksAcc(f),f) = detrend(recPro(:,1:nBlcksAcc(f),f));
  164. end
  165. % z score normalisation
  166. if zsNormI==1
  167. recPro(:,1:nBlcksAcc(f),f) = zscoreJo(recPro(:,1:nBlcksAcc(f),f),pUnit);
  168. end
  169. % demeaning
  170. if demeanI==1
  171. recPro(:,1:nBlcksAcc(f),f) = demean(recPro(:,1:nBlcksAcc(f),f));
  172. end
  173. % filtering
  174. recProRS = reshape(recPro,nBlcks*pUnit,nFiles);
  175. % recProRS(1:nBlcksAcc(f)*pUnit,f) = Filter_Butter(recProRS(1:nBlcksAcc(f)*pUnit,f),20,45,55,"stop",fs); % apply 50 Hz notch filter to the data to get rid of electrical noise
  176. for ft = 1:nFilt-1 % "-1" because "nFilt" includes raw-array which must be excluded here
  177. recFilt(1:nBlcksAcc(f)*pUnit,f,ft) = Filter_Butter(recProRS(1:nBlcksAcc(f)*pUnit,f),order,lowc(ft),hic,"bandpass",fs);
  178. end
  179. end
  180. recProFilt = cat(3,recProRS,recFilt); % concatenate unfiltered and filtered data in 4th dimension
  181. recProFilt = reshape(recProFilt,pUnit,nBlcks,nFiles,nFilt); % reshape to split raw-data into separate trials (2nd dimension)
  182. % perform baseline correction: depends on processed stimulus (different to bat analysis)
  183. blcStartPtsAll = round(pts2begin(1)+(blcEnd-blcWin)*fs); % transform time window for baseline correction into points
  184. blcEndPtsAll = round(pts2begin(1)+blcEnd*fs);
  185. switch c
  186. case {1,3}
  187. blcStartPts = blcStartPtsAll(1);
  188. blcEndPts = blcEndPtsAll(1);
  189. case {2,4}
  190. blcStartPts = blcStartPtsAll(2);
  191. blcEndPts = blcEndPtsAll(2);
  192. end
  193. for f = 1:nFiles
  194. for ft = 1:nFilt
  195. recProFilt(:,1:nBlcksAcc(f),f,ft) = blCorr(recProFilt(:,1:nBlcksAcc(f),f,ft),blcStartPts,blcEndPts);
  196. end
  197. end
  198. % calculate average & grand-average of sorted responses
  199. dataAv = zeros(pUnit,nFiles,nFilt);
  200. for f = 1:nFiles
  201. dataAv(:,f,:) = mean(recProFilt(:,1:nBlcksAcc(f),f,:),2); % averaging is performed only on those vectors that contain an actual response and not only zeros (2nd dim)
  202. end
  203. % calculate grand average
  204. dataGrAv = reshape(mean(dataAv,2),pUnit,nFilt);
  205. % calculate standard deviation
  206. dataStdD = reshape(std(dataAv,0,2),pUnit,nFilt);
  207. % calculate standard error
  208. dataSe = dataStdD/sqrt(nFiles);
  209. % concatenate important data in another cell array with one cell
  210. % for each stimulation-condition
  211. dataAv_cell{c} = dataAv;
  212. dataGrAv_cell{c} = dataGrAv;
  213. dataSe_cell{c} = dataSe;
  214. filenames_stim_cell{c} = filenames_stim;
  215. recID_cell{c} = recID;
  216. timetrBlck_cell{c} = timetrBlck;
  217. timetrUnit_cell{c} = timetrUnit;
  218. pts2begin_cell{c} = pts2begin;
  219. nCh_s_cell{c} = nCh_s;
  220. nFiles_cell{c} = nFiles;
  221. nFilt_cell{c} = nFilt;
  222. nResp_cell{c} = nResp;
  223. stimDur_cell{c} = stimDur;
  224. stimDelay_cell{c} = stimDelay;
  225. fs_stim_cell{c} = fs_stim;
  226. fs_cell{c} = fs;
  227. ch_idx_cell{c} = ch_idx;
  228. nameCh_cell{c} = nameCh;
  229. chLbl_cell{c} = chLbl;
  230. nBlcksAcc_cell{c} = nBlcksAcc;
  231. pSiResp_cell{c} = pSiResp;
  232. %% calculate stimulus template to be plotted next to response
  233. % load stim data
  234. switch c
  235. case {1,3} % Low
  236. [stim] = audioread('Broadband Low.wav');
  237. case {2,4} % High
  238. [stim] = audioread('Broadband High.wav');
  239. end
  240. % add ISI after the stimulus
  241. stimLen = length(stim); % calculate length of stim
  242. stimLong = zeros(round(SOA*fs_stim),1); % create array with the length of stim + ISI (= SOA)
  243. stimLong(1:stimLen) = stim; % replace the first points by the actual stimulus
  244. stimLongLen = length(stimLong); % calculate length of stim + ISI
  245. stimCat_cell{c} = zeros(round((stimLongLen*nResp)+(IBI*fs_stim)),1); % preallocate
  246. % create concatenated stimulus of block-stimulation
  247. for r = 1:nResp
  248. stimCat_cell{c}(1+(r-1)*stimLongLen:r*stimLongLen) = stimLong;
  249. stimLong = -stimLong; % inverse stimulus for the next concatenation
  250. end
  251. end
  252. save(fileName,'dataAv_cell','dataGrAv_cell','dataSe_cell','filenames_stim_cell','recID_cell',...
  253. 'timetrBlck_cell','timetrUnit_cell','pts2begin_cell','combName',...
  254. 'nComb','nCh_s_cell','nFiles_cell','nFilt_cell','nResp_cell','nBlcksAcc_cell',...
  255. 'stimDur_cell','stimDelay_cell','fs_cell','ch_idx_cell','nameCh_cell',...
  256. 'chLbl_cell','artRejI','zsNormI','detrendI','demeanI','blcEnd','SOAName','stimCat_cell',...
  257. 'lowc','fs_stim_cell','pSiResp_cell')
  258. end
  259. beep