DD_OrgData.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. %% Subscript: Organises data from datasets in multiple variables
  2. % subdivide dataset into its components
  3. if remI==1
  4. data(remRec{repDaSe},:) = []; % remove certain recordings from analysis
  5. end
  6. filenames_stim = cat(1,data{:,1});
  7. bsPos = cell2mat(strfind(filenames_stim,'\')); % find positions of back slashes in filename
  8. % bsPos = strfind(filenames_stim,'\'); % find positions of back slashes in filename
  9. startPos = bsPos(:,end); % use last back slash position as starting point
  10. ptPos = cell2mat(strfind(filenames_stim,'.')); % find positions of points in filename (here only one)
  11. % ptPos = strfind(filenames_stim,'.'); % find positions of points in filename (here only one)
  12. endPos = ptPos; % use point position as ending point
  13. recID = extractBetween(filenames_stim,startPos,endPos,'Boundaries','Exclusive'); % extract between Positions
  14. switch runType
  15. case {1,5,6}
  16. recID_oddb{c} = recID; % save recIDs for each oddball stimulus-combination
  17. fileI_Oddb = 0; % file index is empty for runType 1 (oddball)
  18. fileI_Ctrl = 0; % file index is empty for runType 1 (oddball)
  19. case {2,3,4}
  20. insect = intersect(recID_oddb{c},recID); % create array containing only those recordings that are available for both the oddball and the respective control paradigm
  21. fileI_Oddb = ismember(recID_oddb{c},insect); % create logical array containing those oddball recordings that have a matching control recording
  22. fileI_Ctrl = ismember(recID,insect);% create logical array containing those control recordings that have a matching oddball recording
  23. data = data(fileI_Ctrl,:); % use only those control responses that have a matching oddball response
  24. filenames_stim = filenames_stim(fileI_Ctrl); % use only those control filenames that have a matching oddball response
  25. end
  26. param_stim = cat(1,data{:,2});
  27. date = cat(1,data{:,8});
  28. artDateI = date<datetime(trArtDate,'Format','yyyyMMdd'); % logical array that identifies recordings with artefact
  29. seq = cat(1,data{:,3});
  30. filenames_rec = cat(1,data{:,4});
  31. param_rec = struct2cell(cat(1,(data{:,5}))); % concatenate struct arrays, then convert to cell arrays
  32. rec_raw = cat(1,data(:,7)); % concatenate recorded raw data
  33. rec_raw = cellfun(@(x) x/100,rec_raw,'un',0); % divide data by 100 because data from EP-Preamp are amplified by factor 100
  34. nFiles = size(data,1); % number of files within the variable
  35. %% define some additional parameters that are needed for calculations
  36. % stimulation-parameters; ATTENTION: always uses the parameters of first
  37. % file --> parameters must be consistent across all files!
  38. fs_stim = param_stim(1,4);
  39. fdown_stim = param_stim(1,17);
  40. fIndx = param_stim(1,2);
  41. Alvl = param_stim(1,9);
  42. Afrq = param_stim(1,10);
  43. Blvl = param_stim(1,26);
  44. Bfrq = param_stim(1,25);
  45. AfrqI = 999; % frequency index in MR control --> redundant but required in other runTypes
  46. BfrqI = 999;
  47. nDev = param_stim(1,23);
  48. devProb = param_stim(1,24);
  49. nTrials = param_stim(1,12);
  50. nStd = nTrials-nDev;
  51. nBlcks = 2; % number of blocks (AB and BA)
  52. pts2begin_stim = param_stim(1,41);
  53. stimDur = round(param_stim(1,7),4);
  54. trDel = spDis/343.2; % travelling delay time of stimulus in s (343.2 is the speed of sound in air)
  55. stimDelay = round(param_stim(1,13)+trDel,4); % stimulus delay in s (corrected for sound travelling time)
  56. repper = round(param_stim(1,8),4);
  57. recdur = repper;
  58. recdur = recdur*recDurMult; % use double recdur
  59. % recording-parameters
  60. fs = cat(2,param_rec{1,1})';
  61. chLbl = string(cat(2,param_rec{3,:}))';
  62. % down sample data if activated
  63. switch dwnSmpleI
  64. case 0
  65. dwnSmplF = 1; % down sampling factor is 1 if no down sampling is performed
  66. case 1
  67. dwnSmplF = dwnSmplRate/fs(1); % down sampling factor
  68. for f = 1:nFiles
  69. rec_raw{f} = resample(rec_raw{f},dwnSmplRate/1000,fs(1)/1000); % down sample data
  70. end
  71. fs = dwnSmplRate; % change sampling rate to down sampling rate
  72. end
  73. % additional parameters
  74. nCh = zeros(1,nFiles); % preallocate
  75. rawLen = zeros(1,nFiles); % preallocate
  76. for f = 1:nFiles
  77. nCh(f) = size(rec_raw{f},1); % number of channes in raw file
  78. rawLen(f) = size(rec_raw{f},2); % number of samples in each channel of raw file
  79. end
  80. blockLen = round(recdur.*nTrials.*fs); % length of one block (AB or BA) in samples
  81. pSmpl = blockLen(1)/nTrials(1); % number of samples of each single response
  82. if channels=="all"
  83. nameCh = chLbl;
  84. nCh_s = nCh;
  85. else
  86. nameCh = channels;
  87. nCh_s = size(channels,2);
  88. end
  89. pts2begin = round(stimDelay.*fs); % samples before stimulus onset
  90. timetr = (0:pSmpl-1)/fs(1); % time trace of one trial
  91. % triggers
  92. nTrigsE = 20000; % number of expected triggers
  93. trigs_all = zeros(nFiles,nBlcks,nTrials); % preallocate
  94. for f = 1:nFiles % extract trigger events for each file individually
  95. eventsTemp = struct2cell(cat(1,data{f,6})); % extract all events from struct array "data" and convert it to cell array
  96. eventsTemp = eventsTemp(:,:,eventsTemp(1,1,:)=="Stimulus"); % find all triggers "Stimulus" within events array
  97. trigsIdx = eventsTemp(2,1,:)=="S 1"; % find all triggers "S 1" within events array
  98. trigsTemp = eventsTemp(3,1,trigsIdx(1,1,:)); % apply logical array on events array to extract triggers
  99. trigsTemp = cell2mat(trigsTemp); % convert trigger array to matrix
  100. trigsDiff = diff(trigsTemp,1,3); % calculate differences between adjacent triggers to find too small gaps (additional triggers that must be removed)
  101. corTrIdx = trigsDiff>(pSmpl/recDurMult*0.8); % find indices of correct triggers; those with a distance of at least 80 % of the expected distance
  102. corTrIdx = logical(cat(3,1,corTrIdx)); % add "1" at the beginning of the indexing array (since diff has one value less than original array) and make it logical
  103. trigsTemp = trigsTemp(corTrIdx); % select only those triggers that have the correct distance to the adjacent ones
  104. nTrigs = size(trigsTemp,3); % determine number of recorded triggers
  105. trigsTempRs = reshape(trigsTemp,1,nTrigs); % reshape trigger array to 2 dimensional array
  106. if nTrigs>nTrigsE % if more triggers were recorded than expected, stop and print error
  107. error("At least one file contains too many trigger events. Please check and remove those files.")
  108. end
  109. % if less triggers were recorded than expected, go on with the
  110. % following routine to add missing triggers
  111. while nTrigs<nTrigsE % repeat loop as long as number of recorded triggers is lower than number of expected triggers (only if 2 or more consecutive triggers are missing)
  112. trigsDiff = diff(trigsTempRs); % calculate difference-array of trigger array
  113. mTrigIdx = find(trigsDiff>1000&trigsDiff<100000)+1; % find indices of missing trigger events ("<100000" because gap between sequences must be excluded)
  114. nMTrigs = numel(mTrigIdx);
  115. if isempty(mTrigIdx) % if no indices were found, either first or last trigger is missing. In this case it is not possible to reconstruct trigger array. File must be excluded
  116. error("Either the first or last trigger is missing in at least one file. Please check and remove those files.")
  117. end
  118. valPreTrig = trigsTempRs(mTrigIdx-1); % check if this works for more than one missing trigger; determine trigger value preceding the missing trigger
  119. valTrig = valPreTrig+pSmpl; % calculate value for missing trigger
  120. for t = 1:nMTrigs % insert missing triggers in trigger array
  121. trigsTempRs = [trigsTempRs(1:mTrigIdx(t)+(t-2)),valTrig(t),trigsTempRs(mTrigIdx(t)+(t-1):end)]; % "(t-2)" and "(t-1)" because every added trigger shifts next trigger index one the the right
  122. end
  123. nTrigs = size(trigsTempRs,2); % count number of triggers again
  124. end % repeat loop if number of triggers is still less than number of expected triggers
  125. for b = 0:nBlcks-1
  126. trigs_all(f,b+1,:) = trigsTempRs(b*nTrials+1:b*nTrials+nTrials); % after all missing triggers are added, concatenate triggers of all files
  127. end
  128. end
  129. trigs_all = round(trigs_all*dwnSmplF); % multiply triggers with down sampling factor (which is 1 if no down sampling is performed)