OSCR

Tracing the neural trajectories of evidence accumulation and motor preparation processes during voluntary decisions.

Code ↔ Paper

16 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 16 matches · 1 of them tie a paragraph to a whole file without given lines: a weak match, whose lines are not tinted
  1. [1] § Method › EEG analyses ↔ EEG Processing/wavelet_convolution.m, lines 1 to 96 · score 0.89 · complex Morlet wavelet, wavelet cycles, baseline corrected, convolution, stimulus onset, dB · Report a mismatch
  2. [2] § Method › EEG data acquisition and processing ↔ EEG Processing/eegca_3_preprocessing_step2.m, lines 130 to 140 · score 0.88 · rank deficiency, high pass filtered, removed channel, bad channels, compensate, stationarity · Report a mismatch
  3. [3] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /RT and Fixed Window Analyses/eegca_ERP_LMM.Rmd, lines 352 to 395 · score 0.81 · random intercept models, likelihood ratio, random slope models, model comparisons, RT · Report a mismatch
  4. [4] § Method › EEG data acquisition and processing ↔ EEG Processing/eegca_4_preprocessing_step3.m, lines 139 to 150 · score 0.80 · spherical spline interpolation, scalp channel, bad channels, EEGLAB, noisy · Report a mismatch
  5. [5] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_massuni_ERP_stimlocked.m, lines 1274 to 1398 · score 0.59 · Bayes Factors, Bayesian, permutation, cluster · Report a mismatch
  6. [6] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_massuni_ERP_resplocked.m, lines 1317 to 1433 · score 0.59 · Bayes Factors, Bayesian, permutation, cluster · Report a mismatch
  7. [7] § Results › MB amplitudes exhibit accumulation-to-bound dynamics in voluntary decisions ↔ RT and EEG Analyses /RT and Fixed Window Analyses/eegca_derive_MB_measures.m, lines 11 to 21 · score 0.59 · slope window, amplitude window, fixed window, MB amplitudes, Mu, Beta · Report a mismatch
  8. [8] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /RT and Fixed Window Analyses/eegca_ERP_LMM.Rmd, lines 8 to 76 · score 0.58 · log transformed RTs, LMMs, scored, slope, amplitude, EEG · Report a mismatch
  9. [9] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_multcomp_cluster_permtest.m, lines 1 to 121 · score 0.57 · cluster mass, summed, uncorrected, zero, tailed, iterations · Report a mismatch
  10. [10] § Method › Procedure ↔ Experiment Code/Functions Library/eegca_experiment_parameters.m, the whole file · a weak match · score 0.57 · paced break, practice block, decision phase, EEG · Report a mismatch
  11. [11] § Results › MB amplitudes exhibit accumulation-to-bound dynamics in voluntary decisions ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_massuni_MB.m, lines 550 to 666 · score 0.57 · 8–30 Hz, slope window, MB amplitudes, response locked, sliding, Mu · Report a mismatch
  12. [12] § Method › Procedure ↔ Experiment Code/RUN_eegca_practice_session.m, lines 666 to 713 · score 0.54 · paced break, practice block, phase · Report a mismatch
  13. [13] § Results ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_massuni_MB.m, lines 812 to 935 · score 0.53 · 8–30 Hz, shaded standard error, waves, Mu, Beta, maps · Report a mismatch
  14. [14] § Results › The CPP exhibits accumulation-to-bound dynamics in voluntary decisions ↔ RT and EEG Analyses /RT and Fixed Window Analyses/eegca_derive_ERP_measures.m, lines 20 to 59 · score 0.52 · slope window, pre response amplitude, CPP amplitudes, electrode, ERP, RT · Report a mismatch
  15. [15] § Results › The CPP exhibits accumulation-to-bound dynamics in voluntary decisions ↔ RT and EEG Analyses /Mass Univariate Analyses/eegca_massuni_MB.m, lines 1009 to 1147 · score 0.50 · Bayes factors, standard errors, BF, smoothed, Gaussian, forced decisions · Report a mismatch
  16. [16] § Method › EEG analyses › Characterising evidence accumulation and motor preparation signatures of voluntary decisions ↔ RT and EEG Analyses /RT and Fixed Window Analyses/eegca_derive_ERP_measures.m, lines 361 to 431 · score 0.50 · linear regression, pre response amplitudes, model, epoch, slopes · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

MATLAB · 1,148 lines · 48 KB · no license · 3 matches

  1. %% Housekeeping
  2. % Clear all variables in the workspace, and close all windows
  3. clear all;
  4. %close all;
  5. % Change working directory to that which contains this script
  6. mfile_name = mfilename('fullpath');
  7. [pathstring, nameOfFile, extensionString] = fileparts(mfile_name);
  8. cd(pathstring);
  9. %% Setting Parameters
  10. % IDs to process
  11. participantIDs = [1:29,31:50];
  12. % Choose experiment name
  13. experimentName = 'eegca_p';
  14. %% Analysis Options
  15. % Cluster-based permutation test options
  16. cluster_permtest_criticalAlpha = 0.05; % Critical cluster-level alpha
  17. cluster_permtest_clusteringAlpha = 0.01; % Cluster-forming alpha level
  18. cluster_permtest_iterations = 10000; % Number of permutation samples
  19. % Define sliding window parameters
  20. win_ms = 300; % your chosen window
  21. polyord = 2;
  22. MB_freq = 8:30;
  23. fs = 512;
  24. min_trials_for_reg = 20; % guardrail: need at least this many trials/condition for OLS
  25. min_obs_for_OLS = 10; % guardrail: at each timepoint, need >= this many finite values
  26. % Preallocate β matrices
  27. mb_slope_beta_RT.free = []; % slope β(t) in Free
  28. mb_slope_beta_RT.forced = []; % slope β(t) in Forced
  29. mb_amp_beta_RT.free = []; % amp β(t) in Free
  30. mb_amp_beta_RT.forced = []; % amp β(t) in Forced
  31. group_time_valid = []; % time axis (ms) for the "valid" interior samples
  32. %% Preallocate matrices to store trial by trial RT data across all participants
  33. % Group.DecPhaseRT = [];
  34. % Group.CoMPhaseRT = [];
  35. Group.DecFreeRT = [];
  36. % Group.DecFreeFast = [];
  37. % Group.DecFreeMedium = [];
  38. % Group.DecFreeSlow = [];
  39. Group.DecForcedRT = [];
  40. % Group.DecForcedFast = [];
  41. % Group.DecForcedMedium = [];
  42. % Group.DecForcedMedSlow = [];
  43. % Group.DecForcedSlow = [];
  44. %% EEG Data Processing
  45. for datasetNo = 1:length(participantIDs)
  46. % Announce the ID number we are processing
  47. fprintf(['-----------------------------------------------------', ...
  48. '\n\nProcessing participant ID ' int2str(participantIDs(datasetNo)), ' ****** Averaging ERPs\n\n', ...
  49. '-----------------------------------------------------\n\n']);
  50. %% -- Load EEG + Behavioural Data Files
  51. % Epoched EEG data file
  52. load(['EEG Data/Epoched Data/', experimentName, int2str(participantIDs(datasetNo)), '_MuBeta_CSD.mat']);
  53. % Behavioural data file
  54. %load(['Behavioural Data/Cleaned Behavioural Data/p' int2str(participantIDs(datasetNo)), '_cleaned.mat']);
  55. load(['Channel Locations/channel_information.mat'], 'chanlocs');
  56. %% -- Calculate Mean and SD
  57. % - Decision Phase RTs
  58. % Remove trials with RTs less than 200ms
  59. decBadTrials = [];
  60. for trialNo = 1:numel(TC_Resp_DecPhase.DecPhaseRT)
  61. if TC_Resp_DecPhase.DecPhaseRT(trialNo) < 0.2
  62. decBadTrials = [decBadTrials, trialNo];
  63. end
  64. end
  65. variables_TC_Resp_DecPhase = fieldnames(TC_Resp_DecPhase);
  66. for variable_index = 1:numel(variables_TC_Resp_DecPhase)
  67. TC_Resp_DecPhase.(variables_TC_Resp_DecPhase{variable_index})(:, decBadTrials) = [];
  68. end
  69. MuBeta_Resp{1,1}(:,:,decBadTrials) = [];
  70. % Calculate mean, median, and standard deviation
  71. mean_DecPhaseRTs = mean(TC_Resp_DecPhase.DecPhaseRT);
  72. median_DecPhaseRTs = median(TC_Resp_DecPhase.DecPhaseRT);
  73. std_DecPhaseRTs = std(TC_Resp_DecPhase.DecPhaseRT);
  74. DecPhaseMaxCutoff = 20;
  75. DecPhaseFreeRTs = TC_Resp_DecPhase.DecPhaseRT(TC_Resp_DecPhase.DecPhaseCondition == "free");
  76. DecPhaseFreeRTs = DecPhaseFreeRTs(DecPhaseFreeRTs <= DecPhaseMaxCutoff);
  77. DecPhaseForcedRTs = TC_Resp_DecPhase.DecPhaseRT(TC_Resp_DecPhase.DecPhaseCondition == "forced");
  78. DecPhaseForcedRTs = DecPhaseForcedRTs(DecPhaseForcedRTs < DecPhaseMaxCutoff);
  79. DecPhaseFreeRT_bins = prctile(DecPhaseFreeRTs, [33.33,66.67]);
  80. DecPhaseForcedRT_bins = prctile(DecPhaseForcedRTs, [33.33,66.67]);
  81. % Preallocate tertile matrices
  82. usableDecTrials = length(TC_Resp_DecPhase.DecPhaseRT);
  83. TC_Resp_DecPhase.FreeFast(1:usableDecTrials) = nan;
  84. TC_Resp_DecPhase.FreeMedium(1:usableDecTrials) = nan;
  85. TC_Resp_DecPhase.FreeSlow(1:usableDecTrials) = nan;
  86. TC_Resp_DecPhase.ForcedFast(1:usableDecTrials) = nan;
  87. TC_Resp_DecPhase.ForcedMedium(1:usableDecTrials) = nan;
  88. TC_Resp_DecPhase.ForcedSlow(1:usableDecTrials) = nan;
  89. clear trialNo
  90. for trialNo = 1:length(TC_Resp_DecPhase.DecPhaseRT)
  91. if TC_Resp_DecPhase.DecPhaseCondition{trialNo} == "free"
  92. TC_Resp_DecPhase.FreeRT(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  93. % FREE FASTEST Quartile
  94. if TC_Resp_DecPhase.DecPhaseRT(trialNo) < DecPhaseFreeRT_bins(1)
  95. TC_Resp_DecPhase.FreeFast(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  96. TC_Resp_DecPhase.FreeMedium(trialNo) = nan;
  97. TC_Resp_DecPhase.FreeSlow(trialNo) = nan;
  98. Tertile.DecIndex(datasetNo,trialNo) = 1;
  99. % FREE MEDIUM Quartile
  100. elseif TC_Resp_DecPhase.DecPhaseRT(trialNo) >= DecPhaseFreeRT_bins(1) && TC_Resp_DecPhase.DecPhaseRT(trialNo) < DecPhaseFreeRT_bins(2)
  101. TC_Resp_DecPhase.FreeMedium(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  102. TC_Resp_DecPhase.FreeFast(trialNo) = nan;
  103. TC_Resp_DecPhase.FreeSlow(trialNo) = nan;
  104. Tertile.DecIndex(datasetNo,trialNo) = 2;
  105. % FREE SLOWEST Quartile
  106. else
  107. TC_Resp_DecPhase.FreeSlow(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  108. TC_Resp_DecPhase.FreeFast(trialNo) = nan;
  109. TC_Resp_DecPhase.FreeMedium(trialNo) = nan;
  110. Tertile.DecIndex(datasetNo,trialNo) = 3;
  111. end
  112. elseif TC_Resp_DecPhase.DecPhaseCondition{trialNo} == "forced"
  113. TC_Resp_DecPhase.ForcedRT(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  114. % FORCED FASTEST Quartile
  115. if TC_Resp_DecPhase.DecPhaseRT(trialNo) < DecPhaseForcedRT_bins(1)
  116. TC_Resp_DecPhase.ForcedFast(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  117. TC_Resp_DecPhase.ForcedMedium(trialNo) = nan;
  118. TC_Resp_DecPhase.ForcedSlow(trialNo) = nan;
  119. Tertile.DecIndex(datasetNo, trialNo) = 4;
  120. % FORCED MEDIUM FAST Quartile
  121. elseif TC_Resp_DecPhase.DecPhaseRT(trialNo) >= DecPhaseForcedRT_bins(1) && TC_Resp_DecPhase.DecPhaseRT(trialNo) < DecPhaseForcedRT_bins(2)
  122. TC_Resp_DecPhase.ForcedMedium(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  123. TC_Resp_DecPhase.ForcedFast(trialNo) = nan;
  124. TC_Resp_DecPhase.ForcedSlow(trialNo) = nan;
  125. Tertile.DecIndex(datasetNo, trialNo) = 5;
  126. % FORCED SLOWEST Quartile
  127. else
  128. TC_Resp_DecPhase.ForcedSlow(trialNo) = TC_Resp_DecPhase.DecPhaseRT(trialNo);
  129. TC_Resp_DecPhase.ForcedFast(trialNo) = nan;
  130. TC_Resp_DecPhase.ForcedMedium(trialNo) = nan;
  131. Tertile.DecIndex(datasetNo, trialNo) = 6;
  132. end
  133. end
  134. end
  135. % % - CoM Phase RTs
  136. % % Remove trials with RTs less than 200ms
  137. % comBadTrials = [];
  138. % for trialNo = 1:numel(TC_Resp_CoMPhase.CoMPhaseRT)
  139. % if TC_Resp_CoMPhase.CoMPhaseRT(trialNo) < 0.2
  140. % comBadTrials = [comBadTrials, trialNo];
  141. % end
  142. % end
  143. %
  144. % variables_TC_Resp_CoMPhase = fieldnames(TC_Resp_CoMPhase);
  145. %
  146. % for variable_index = 1:numel(variables_TC_Resp_CoMPhase)
  147. % TC_Resp_CoMPhase.(variables_TC_Resp_CoMPhase{variable_index})(:, comBadTrials) = [];
  148. % end
  149. %
  150. % EEG_Data_Resp_CoMPhase(:,:,comBadTrials) = [];
  151. %
  152. % % Calculate mean, median, and standard deviation
  153. % mean_CoMPhaseRTs = mean(TC_Resp_CoMPhase.CoMPhaseRT);
  154. % median_CoMPhaseRTs = median(TC_Resp_CoMPhase.CoMPhaseRT);
  155. % std_CoMPhaseRTs = std(TC_Resp_CoMPhase.CoMPhaseRT);
  156. % CoMPhaseRTMaxCutoff = 10;
  157. %
  158. % CoMPhaseFreeRTs = TC_Resp_CoMPhase.CoMPhaseRT(TC_Resp_CoMPhase.CoMPhaseCondition == "free");
  159. % CoMPhaseFreeRTs = CoMPhaseFreeRTs(CoMPhaseFreeRTs < CoMPhaseRTMaxCutoff);
  160. % CoMPhaseFreeSwitch = TC_Resp_CoMPhase.CoMPhaseRT(strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, "free") & TC_Resp_CoMPhase.SwitchStay_Numeric == 1);
  161. % CoMPhaseFreeSwitch = CoMPhaseFreeSwitch(CoMPhaseFreeSwitch < CoMPhaseRTMaxCutoff);
  162. % CoMPhaseFreeStayed = TC_Resp_CoMPhase.CoMPhaseRT(strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & TC_Resp_CoMPhase.SwitchStay_Numeric == 2);
  163. % CoMPhaseFreeStayed = CoMPhaseFreeStayed(CoMPhaseFreeStayed < CoMPhaseRTMaxCutoff);
  164. %
  165. % CoMPhaseForcedRTs = TC_Resp_CoMPhase.CoMPhaseRT(TC_Resp_CoMPhase.CoMPhaseCondition == "forced");
  166. % CoMPhaseForcedRTs = CoMPhaseForcedRTs(CoMPhaseForcedRTs < CoMPhaseRTMaxCutoff);
  167. % CoMPhaseForcedSwitch = TC_Resp_CoMPhase.CoMPhaseRT(strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & TC_Resp_CoMPhase.SwitchStay_Numeric == 1);
  168. % CoMPhaseForcedSwitch = CoMPhaseForcedSwitch(CoMPhaseForcedSwitch < CoMPhaseRTMaxCutoff);
  169. % CoMPhaseForcedStayed = TC_Resp_CoMPhase.CoMPhaseRT(strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & TC_Resp_CoMPhase.SwitchStay_Numeric == 2);
  170. % CoMPhaseForcedStayed = CoMPhaseForcedStayed(CoMPhaseForcedStayed < CoMPhaseRTMaxCutoff);
  171. %
  172. % CoMPhaseFreeRT_bins = prctile(CoMPhaseFreeRTs, [33.33,66.67]);
  173. % CoMPhaseForcedRT_bins = prctile(CoMPhaseForcedRTs, [33.33,66.67]);
  174. %
  175. % % Preallocate tertile matrices
  176. % usableCoMTrials = length(TC_Resp_CoMPhase.CoMPhaseRT);
  177. % TC_Resp_CoMPhase.FreeFast(1:usableCoMTrials) = nan;
  178. % TC_Resp_CoMPhase.FreeMedium(1:usableCoMTrials) = nan;
  179. % TC_Resp_CoMPhase.FreeSlow(1:usableCoMTrials) = nan;
  180. % TC_Resp_CoMPhase.ForcedFast(1:usableCoMTrials) = nan;
  181. % TC_Resp_CoMPhase.ForcedMedium(1:usableCoMTrials) = nan;
  182. % TC_Resp_CoMPhase.ForcedSlow(1:usableCoMTrials) = nan;
  183. %
  184. % clear trialNo
  185. %
  186. % for trialNo = 1:length(TC_Resp_CoMPhase.CoMPhaseRT)
  187. % if TC_Resp_CoMPhase.CoMPhaseCondition{trialNo} == "free"
  188. %
  189. % TC_Resp_CoMPhase.FreeRT(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  190. %
  191. % if TC_Resp_CoMPhase.SwitchStay_Numeric(trialNo) == 1
  192. %
  193. % TC_Resp_CoMPhase.FreeSwitch(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  194. %
  195. % elseif TC_Resp_CoMPhase.SwitchStay_Numeric(trialNo) == 2
  196. %
  197. % TC_Resp_CoMPhase.FreeStay(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  198. % end
  199. %
  200. %
  201. % % FREE FAST Tertile
  202. % if TC_Resp_CoMPhase.CoMPhaseRT(trialNo) < CoMPhaseFreeRT_bins(1)
  203. %
  204. % TC_Resp_CoMPhase.FreeFast(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  205. % TC_Resp_CoMPhase.FreeMedium(trialNo) = nan;
  206. % TC_Resp_CoMPhase.FreeSlow(trialNo) = nan;
  207. % Tertile.CoMIndex(datasetNo,trialNo)= 1;
  208. %
  209. % % FREE SLOW Tertile
  210. % elseif TC_Resp_CoMPhase.CoMPhaseRT(trialNo) > CoMPhaseFreeRT_bins(2)
  211. %
  212. % TC_Resp_CoMPhase.FreeSlow(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  213. % TC_Resp_CoMPhase.FreeMedium(trialNo) = nan;
  214. % TC_Resp_CoMPhase.FreeFast(trialNo) = nan;
  215. % Tertile.CoMIndex(datasetNo,trialNo)= 3;
  216. %
  217. % else
  218. % % FREE MEDIUM Tertile
  219. % TC_Resp_CoMPhase.FreeMedium(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  220. % TC_Resp_CoMPhase.FreeFast(trialNo) = nan;
  221. % TC_Resp_CoMPhase.FreeSlow(trialNo) = nan;
  222. % Tertile.CoMIndex(datasetNo,trialNo)= 2;
  223. % end
  224. % elseif TC_Resp_CoMPhase.CoMPhaseCondition{trialNo} == "forced"
  225. %
  226. % TC_Resp_CoMPhase.ForcedRT(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  227. %
  228. % if TC_Resp_CoMPhase.SwitchStay_Numeric(trialNo) == 1
  229. %
  230. % TC_Resp_CoMPhase.ForcedSwitch(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  231. %
  232. % elseif TC_Resp_CoMPhase.SwitchStay_Numeric(trialNo) == 2
  233. %
  234. % TC_Resp_CoMPhase.ForcedStay(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  235. % end
  236. %
  237. %
  238. % % FORCED FAST Tertile
  239. % if TC_Resp_CoMPhase.CoMPhaseRT(trialNo) < CoMPhaseForcedRT_bins(1)
  240. %
  241. % TC_Resp_CoMPhase.ForcedFast(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  242. % TC_Resp_CoMPhase.ForcedMedium(trialNo) = nan;
  243. % TC_Resp_CoMPhase.ForcedSlow(trialNo) = nan;
  244. % Tertile.CoMIndex(datasetNo,trialNo)= 4;
  245. %
  246. % % FORCED SLOW Tertile
  247. % elseif TC_Resp_CoMPhase.CoMPhaseRT(trialNo) > CoMPhaseForcedRT_bins(2)
  248. %
  249. % TC_Resp_CoMPhase.ForcedSlow(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  250. % TC_Resp_CoMPhase.ForcedMedium(trialNo) = nan;
  251. % TC_Resp_CoMPhase.ForcedFast(trialNo) = nan;
  252. % Tertile.CoMIndex(datasetNo,trialNo)= 6;
  253. %
  254. % else
  255. % % FORCED MEDIUM Tertile
  256. % TC_Resp_CoMPhase.ForcedMedium(trialNo) = TC_Resp_CoMPhase.CoMPhaseRT(trialNo);
  257. % TC_Resp_CoMPhase.ForcedFast(trialNo) = nan;
  258. % TC_Resp_CoMPhase.ForcedSlow(trialNo) = nan;
  259. % Tertile.CoMIndex(datasetNo,trialNo)= 5;
  260. % end
  261. %
  262. % end
  263. % end
  264. %
  265. % % - Choice Phase RTs
  266. % ChoicePhaseRTs = Res.Timing.choiceReportRTs(~isnan(Res.Timing.choiceReportRTs));
  267. % ChoicePhaseRTs = ChoicePhaseRTs(:); % Flatten matrix into single vector
  268. %
  269. % % Calculate mean, median, and standard deviation
  270. % mean_ChoicePhaseRTs = mean(ChoicePhaseRTs);
  271. % median_ChoicePhaseRTs = median(ChoicePhaseRTs);
  272. % std_ChoicePhaseRTs = std(ChoicePhaseRTs);
  273. % ChoicePhaseRTsCutoff = median_ChoicePhaseRTs + 3 * std_ChoicePhaseRTs;
  274. %
  275. % CoMReportRTs = Res.Timing.CoMSwitchReportRTs(~isnan(Res.Timing.CoMSwitchReportRTs));
  276. % CoMReportRTs = CoMReportRTs(:); % Flatten matrix into single vector
  277. %
  278. % % Calculate mean, median, and standard deviation
  279. % mean_CoMReportRTs = mean(CoMReportRTs);
  280. % median_CoMReportRTs = median(CoMReportRTs);
  281. % std_CoMReportRTs = std(CoMReportRTs);
  282. % CoMReportRTsCutoff = median_CoMReportRTs + 3 * std_CoMReportRTs;
  283. %% Remove zeros from TC RT structures to calculate means
  284. % Filter out zero elements
  285. TC_Resp_DecPhase.FreeRT = TC_Resp_DecPhase.FreeRT(TC_Resp_DecPhase.FreeRT ~= 0);
  286. TC_Resp_DecPhase.FreeFast = TC_Resp_DecPhase.FreeFast(TC_Resp_DecPhase.FreeFast ~= 0);
  287. TC_Resp_DecPhase.FreeMedium = TC_Resp_DecPhase.FreeMedium(TC_Resp_DecPhase.FreeMedium ~= 0);
  288. TC_Resp_DecPhase.FreeSlow = TC_Resp_DecPhase.FreeSlow(TC_Resp_DecPhase.FreeSlow ~= 0);
  289. TC_Resp_DecPhase.ForcedRT = TC_Resp_DecPhase.ForcedRT(TC_Resp_DecPhase.ForcedRT ~= 0);
  290. TC_Resp_DecPhase.ForcedFast = TC_Resp_DecPhase.ForcedFast(TC_Resp_DecPhase.ForcedFast ~= 0);
  291. TC_Resp_DecPhase.ForcedMedium = TC_Resp_DecPhase.ForcedMedium(TC_Resp_DecPhase.ForcedMedium ~= 0);
  292. TC_Resp_DecPhase.ForcedSlow = TC_Resp_DecPhase.ForcedSlow(TC_Resp_DecPhase.ForcedSlow ~= 0);
  293. % TC_Resp_CoMPhase.FreeRT = TC_Resp_CoMPhase.FreeRT(TC_Resp_CoMPhase.FreeRT ~= 0);
  294. % TC_Resp_CoMPhase.FreeSwitch = TC_Resp_CoMPhase.FreeSwitch(TC_Resp_CoMPhase.FreeSwitch~=0);
  295. % TC_Resp_CoMPhase.FreeStay = TC_Resp_CoMPhase.FreeStay(TC_Resp_CoMPhase.FreeStay ~= 0);
  296. % TC_Resp_CoMPhase.FreeFast = TC_Resp_CoMPhase.FreeFast(TC_Resp_CoMPhase.FreeFast ~= 0);
  297. % TC_Resp_CoMPhase.FreeMedium = TC_Resp_CoMPhase.FreeMedium(TC_Resp_CoMPhase.FreeMedium ~= 0);
  298. % TC_Resp_CoMPhase.FreeSlow = TC_Resp_CoMPhase.FreeSlow(TC_Resp_CoMPhase.FreeSlow ~= 0);
  299. % TC_Resp_CoMPhase.ForcedRT = TC_Resp_CoMPhase.ForcedRT(TC_Resp_CoMPhase.ForcedRT ~= 0);
  300. % TC_Resp_CoMPhase.ForcedSwitch = TC_Resp_CoMPhase.ForcedSwitch(TC_Resp_CoMPhase.ForcedSwitch ~= 0);
  301. % TC_Resp_CoMPhase.ForcedStay = TC_Resp_CoMPhase.ForcedStay(TC_Resp_CoMPhase.ForcedStay ~= 0);
  302. % TC_Resp_CoMPhase.ForcedFast = TC_Resp_CoMPhase.ForcedFast(TC_Resp_CoMPhase.ForcedFast ~= 0);
  303. % TC_Resp_CoMPhase.ForcedMedium = TC_Resp_CoMPhase.ForcedMedium(TC_Resp_CoMPhase.ForcedMedium ~= 0);
  304. % TC_Resp_CoMPhase.ForcedSlow = TC_Resp_CoMPhase.ForcedSlow(TC_Resp_CoMPhase.ForcedSlow ~= 0);
  305. %
  306. Group.DecFreeRT = [Group.DecFreeRT; TC_Resp_DecPhase.FreeRT'];
  307. Group.DecForcedRT = [Group.DecForcedRT; TC_Resp_DecPhase.ForcedRT'];
  308. %% Calculate Individual Level Tertile Means and Medians
  309. clear tertileNo
  310. for tertileNo = 1:length(participantIDs)
  311. Tertile.MeanDecFreeRT(datasetNo) = nanmean(TC_Resp_DecPhase.FreeRT);
  312. Tertile.MeanDecFreeFast(datasetNo) = nanmean(TC_Resp_DecPhase.FreeFast);
  313. Tertile.MeanDecFreeMedium(datasetNo) = nanmean(TC_Resp_DecPhase.FreeMedium);
  314. Tertile.MeanDecFreeSlow(datasetNo) = nanmean(TC_Resp_DecPhase.FreeSlow);
  315. Tertile.MeanDecForcedRT(datasetNo) = nanmean(TC_Resp_DecPhase.ForcedRT);
  316. Tertile.MeanDecForcedFast(datasetNo) = nanmean(TC_Resp_DecPhase.ForcedFast);
  317. Tertile.MeanDecForcedMedium(datasetNo) = nanmean(TC_Resp_DecPhase.ForcedMedium);
  318. Tertile.MeanDecForcedSlow(datasetNo) = nanmean(TC_Resp_DecPhase.ForcedSlow);
  319. % Tertile.MeanCoMFreeRT(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeRT);
  320. % Tertile.MeanCoMFreeSwitch(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeSwitch);
  321. % Tertile.MeanCoMFreeStay(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeStay);
  322. % Tertile.MeanCoMFreeFast(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeFast);
  323. % Tertile.MeanCoMFreeMedium(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeMedium);
  324. % Tertile.MeanCoMFreeSlow(datasetNo) = nanmean(TC_Resp_CoMPhase.FreeSlow);
  325. % Tertile.MeanCoMForcedRT(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedRT);
  326. % Tertile.MeanCoMForcedSwitch(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedSwitch);
  327. % Tertile.MeanCoMForcedStay(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedStay);
  328. % Tertile.MeanCoMForcedFast(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedFast);
  329. % Tertile.MeanCoMForcedMedium(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedMedium);
  330. % Tertile.MeanCoMForcedSlow(datasetNo) = nanmean(TC_Resp_CoMPhase.ForcedSlow);
  331. end
  332. %% -- Average ERPs by Condition
  333. % Free Trials
  334. Epoch.FreeStandaloneAll(:, :, datasetNo) = ...
  335. nanmean(MuBeta_Resp{1,1}(:, :, ...
  336. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'free') & ...
  337. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  338. TC_Resp_DecPhase.DecPhaseRT < DecPhaseMaxCutoff & ...
  339. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  340. Epoch.FreeStandaloneFast(:, :, datasetNo) = ...
  341. nanmean(MuBeta_Resp{1,1}(:, :, ...
  342. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'free') & ...
  343. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  344. TC_Resp_DecPhase.DecPhaseRT < DecPhaseFreeRT_bins(1) & ...
  345. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  346. Epoch.FreeStandaloneMedium(:, :, datasetNo) = ...
  347. nanmean(MuBeta_Resp{1,1}(:, :, ...
  348. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'free') & ...
  349. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  350. TC_Resp_DecPhase.DecPhaseRT >= DecPhaseFreeRT_bins(1) & ...
  351. TC_Resp_DecPhase.DecPhaseRT < DecPhaseFreeRT_bins(2) & ...
  352. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  353. Epoch.FreeStandaloneSlow(:, :, datasetNo) = ...
  354. nanmean(MuBeta_Resp{1,1}(:, :, ...
  355. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'free') & ...
  356. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  357. TC_Resp_DecPhase.DecPhaseRT >= DecPhaseFreeRT_bins(2) & ...
  358. TC_Resp_DecPhase.DecPhaseRT < DecPhaseMaxCutoff & ...
  359. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  360. % Epoch.FreeSubsequentAll(:, :, datasetNo) = ...
  361. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  362. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  363. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  364. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  365. %
  366. % Epoch.FreeSubsequentFast(:, :, datasetNo) = ...
  367. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  368. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  369. % TC_Resp_CoMPhase.CoMPhaseRT <= CoMPhaseFreeRT_bins(1) & ...
  370. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  371. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  372. %
  373. % Epoch.FreeSubsequentMedium(:, :, datasetNo) = ...
  374. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  375. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  376. % TC_Resp_CoMPhase.CoMPhaseRT > CoMPhaseFreeRT_bins(1) & ...
  377. % TC_Resp_CoMPhase.CoMPhaseRT <= CoMPhaseFreeRT_bins(2) & ...
  378. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  379. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  380. %
  381. % Epoch.FreeSubsequentSlow(:, :, datasetNo) = ...
  382. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  383. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  384. % TC_Resp_CoMPhase.CoMPhaseRT > CoMPhaseFreeRT_bins(2) & ...
  385. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  386. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  387. %
  388. % Epoch.FreeStayed(:, :, datasetNo) = ...
  389. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  390. % TC_Resp_CoMPhase.SwitchStay_Numeric == 2 & ...
  391. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  392. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  393. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  394. %
  395. % Epoch.FreeSwitched(:, :, datasetNo) = ...
  396. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'free') & ...
  397. % TC_Resp_CoMPhase.SwitchStay_Numeric == 1 & ...
  398. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  399. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  400. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  401. % Forced Trials
  402. Epoch.ForcedStandaloneAll(:, :, datasetNo) = ... % Forced Decision Phase
  403. nanmean(MuBeta_Resp{1,1}(:, :, strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'forced') & ...
  404. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  405. TC_Resp_DecPhase.DecPhaseRT > 0.2 & ...
  406. TC_Resp_DecPhase.DecPhaseRT < DecPhaseMaxCutoff & ...
  407. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  408. Epoch.ForcedStandaloneFast(:, :, datasetNo) = ...
  409. nanmean(MuBeta_Resp{1,1}(:, :, ...
  410. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'forced') & ...
  411. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  412. TC_Resp_DecPhase.DecPhaseRT > 0.2 & ...
  413. TC_Resp_DecPhase.DecPhaseRT <= DecPhaseForcedRT_bins(1) & ...
  414. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  415. Epoch.ForcedStandaloneMedium(:, :, datasetNo) = ...
  416. nanmean(MuBeta_Resp{1,1}(:, :, ...
  417. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'forced') & ...
  418. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  419. TC_Resp_DecPhase.DecPhaseRT > 0.2 & ...
  420. TC_Resp_DecPhase.DecPhaseRT >= DecPhaseForcedRT_bins(1) & ...
  421. TC_Resp_DecPhase.DecPhaseRT < DecPhaseForcedRT_bins(2) & ...
  422. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  423. Epoch.ForcedStandaloneSlow(:, :, datasetNo) = ...
  424. nanmean(MuBeta_Resp{1,1}(:, :, ...
  425. strcmp(TC_Resp_DecPhase.DecPhaseCondition, 'forced') & ...
  426. TC_Resp_DecPhase.ChoiceMade == 1 & ...
  427. TC_Resp_DecPhase.DecPhaseRT > 0.2 & ...
  428. TC_Resp_DecPhase.DecPhaseRT >= DecPhaseForcedRT_bins(2) & ...
  429. TC_Resp_DecPhase.ChoicePhaseRT < 5), 3);
  430. % Epoch.ForcedSubsequentAll(:, :, datasetNo) = ... % Forced CoM Phase
  431. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  432. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  433. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  434. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  435. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  436. %
  437. % Epoch.ForcedSubsequentFast(:, :, datasetNo) = ...
  438. % mean(EEG_Data_Resp_CoMPhase(:, :, ...
  439. % strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  440. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  441. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  442. % TC_Resp_CoMPhase.CoMPhaseRT <= CoMPhaseForcedRT_bins(1) & ...
  443. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  444. %
  445. % Epoch.ForcedSubsequentMedium(:, :, datasetNo) = ...
  446. % mean(EEG_Data_Resp_CoMPhase(:, :, ...
  447. % strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  448. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  449. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  450. % TC_Resp_CoMPhase.CoMPhaseRT > CoMPhaseForcedRT_bins(1) & ...
  451. % TC_Resp_CoMPhase.CoMPhaseRT <= CoMPhaseForcedRT_bins(2) & ...
  452. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  453. %
  454. % Epoch.ForcedSubsequentSlow(:, :, datasetNo) = ...
  455. % mean(EEG_Data_Resp_CoMPhase(:, :, ...
  456. % strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  457. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  458. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  459. % TC_Resp_CoMPhase.CoMPhaseRT > CoMPhaseForcedRT_bins(2) & ...
  460. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  461. %
  462. % Epoch.ForcedStayed(:, :, datasetNo) = ... % Forced Stayed
  463. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  464. % TC_Resp_CoMPhase.SwitchStay_Numeric == 2 & ...
  465. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  466. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  467. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  468. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  469. %
  470. % Epoch.ForcedSwitched(:, :, datasetNo) = ... % Forced Switched
  471. % mean(EEG_Data_Resp_CoMPhase(:, :, strcmp(TC_Resp_CoMPhase.CoMPhaseCondition, 'forced') & ...
  472. % TC_Resp_CoMPhase.SwitchStay_Numeric == 1 & ...
  473. % TC_Resp_CoMPhase.ChoiceMade == 1 & ...
  474. % TC_Resp_CoMPhase.CoMPhaseRT > 0.2 & ...
  475. % TC_Resp_CoMPhase.CoMPhaseRT < CoMPhaseRTMaxCutoff & ...
  476. % TC_Resp_CoMPhase.ChoicePhaseRT < 5), 3);
  477. %% Derive sliding-window slope & amplitude & regress β(t) ~ zlogRT per condition
  478. % ---------------------------------------------------------------------
  479. % 1) Build trial × time waveform from Mu/Beta TF by averaging 8–30 Hz
  480. % Result: mb_trials is [nTrials × nTime], in dB or whatever your TF units are.
  481. % ---------------------------------------------------------------------
  482. mb_trials = squeeze(mean(MuBeta_Resp{1,1}(MB_freq, :, :), 1)).'; % [trials x time]
  483. [nTrials, nTime] = size(mb_trials);
  484. t_ms = timepts_struct.resp(:).'; % time axis (ms), response-locked
  485. % ---------------------------------------------------------------------
  486. % 2) Compute sliding-window slope & window-mean amplitude at each sample
  487. % Using the polyfit version (true OLS slope over each window).
  488. % Returns:
  489. % slope_ps: [nTrials x nTime], NaN at edges
  490. % amp_win : [nTrials x nTime], NaN at edges (mean within window)
  491. % valid_mask: 1 x nTime, logical, where full window is available
  492. % ---------------------------------------------------------------------
  493. [slope_ps, amp_win, valid_mask] = eegca_sliding_slope(mb_trials, fs, win_ms);
  494. t_valid = t_ms(valid_mask);
  495. % ---------------------------------------------------------------------
  496. % 3) Trial-level covariates: RT (z-scored log RT) and condition
  497. % We use log to reduce positive skew, then z-score within participant
  498. % so β reflects change per 1 SD of logRT (participant-normalised).
  499. % ---------------------------------------------------------------------
  500. RT_sec = TC_Resp_DecPhase.DecPhaseRT(:); % seconds
  501. cond_str = string(TC_Resp_DecPhase.DecPhaseCondition(:)); % "free"/"forced"
  502. logRT = log(RT_sec);
  503. % guard against zero/negative RTs (shouldn't happen after 0.2 s cut)
  504. logRT(~isfinite(logRT)) = NaN;
  505. zlogRT = (logRT - nanmean(logRT)) ./ nanstd(logRT);
  506. % ---------------------------------------------------------------------
  507. % 4) OLS per time sample: slope(t) ~ [1 zlogRT], amp(t) ~ [1 zlogRT]
  508. % Done separately for Free and Forced trials within participant.
  509. % We only keep β for zlogRT (2nd column).
  510. % ---------------------------------------------------------------------
  511. conds = ["free","forced"];
  512. beta_slope_free = nan(1,sum(valid_mask));
  513. beta_slope_forced = nan(1,sum(valid_mask));
  514. beta_amp_free = nan(1,sum(valid_mask));
  515. beta_amp_forced = nan(1,sum(valid_mask));
  516. for ci = 1:numel(conds)
  517. c = conds(ci);
  518. keep_tr = cond_str == c & isfinite(zlogRT);
  519. if nnz(keep_tr) < min_trials_for_reg
  520. fprintf(' [%s] too few trials (%d) → skipping β(t) this participant.\n', c, nnz(keep_tr));
  521. continue;
  522. end
  523. X = [ones(nnz(keep_tr),1), zlogRT(keep_tr)]; % design matrix
  524. Y_slope = slope_ps(keep_tr, valid_mask); % slopes, valid time only
  525. Y_amp = amp_win(keep_tr, valid_mask); % window-mean amplitude
  526. b_slope = nan(1,size(Y_slope,2));
  527. b_amp = nan(1,size(Y_amp,2));
  528. for tt = 1:size(Y_slope,2)
  529. ys = Y_slope(:,tt);
  530. ya = Y_amp(:,tt);
  531. oks = isfinite(ys);
  532. oka = isfinite(ya);
  533. if nnz(oks) >= min_obs_for_OLS
  534. betaS = X(oks,:) \ ys(oks); % OLS → β = (X'X)^-1 X'y
  535. b_slope(tt) = betaS(2); % β for zlogRT
  536. end
  537. if nnz(oka) >= min_obs_for_OLS
  538. betaA = X(oka,:) \ ya(oka);
  539. b_amp(tt) = betaA(2); % β for zlogRT
  540. end
  541. end
  542. if c == "free"
  543. beta_slope_free = b_slope;
  544. beta_amp_free = b_amp;
  545. else
  546. beta_slope_forced = b_slope;
  547. beta_amp_forced = b_amp;
  548. end
  549. end
  550. % ---------------------------------------------------------------------
  551. % 5) Stack β(t) rows for this participant (and align time if needed)
  552. % First participant sets the master time vector (t_valid).
  553. % Subsequent participants are truncated to the minimum overlapping
  554. % length to keep alignment perfect for group stats.
  555. % ---------------------------------------------------------------------
  556. if isempty(group_time_valid)
  557. group_time_valid = t_valid;
  558. end
  559. L = min(numel(group_time_valid), numel(t_valid));
  560. if L ~= numel(group_time_valid)
  561. group_time_valid = group_time_valid(1:L);
  562. end
  563. % Truncate participant vectors if their valid time differs
  564. beta_slope_free = beta_slope_free(1:L);
  565. beta_slope_forced = beta_slope_forced(1:L);
  566. beta_amp_free = beta_amp_free(1:L);
  567. beta_amp_forced = beta_amp_forced(1:L);
  568. % Append to group matrices
  569. mb_slope_beta_RT.free = [mb_slope_beta_RT.free; beta_slope_free];
  570. mb_slope_beta_RT.forced = [mb_slope_beta_RT.forced; beta_slope_forced];
  571. mb_amp_beta_RT.free = [mb_amp_beta_RT.free; beta_amp_free];
  572. mb_amp_beta_RT.forced = [mb_amp_beta_RT.forced; beta_amp_forced];
  573. end % of for datasetNo
  574. %% Calculate Group Means and Medians by Tertile
  575. Tertile.GroupMean.DecFreeRT = mean(Tertile.MeanDecFreeRT)*1000;
  576. Tertile.GroupMean.DecFreeFast = mean(Tertile.MeanDecFreeFast)*1000;
  577. Tertile.GroupMean.DecFreeMedium = mean(Tertile.MeanDecFreeMedium)*1000;
  578. Tertile.GroupMean.DecFreeSlow = mean(Tertile.MeanDecFreeSlow)*1000;
  579. Tertile.GroupMean.DecForcedRT = mean(Tertile.MeanDecForcedRT)*1000;
  580. Tertile.GroupMean.DecForcedFast = mean(Tertile.MeanDecForcedFast)*1000;
  581. Tertile.GroupMean.DecForcedMedium = mean(Tertile.MeanDecForcedMedium)*1000;
  582. Tertile.GroupMean.DecForcedSlow = mean(Tertile.MeanDecForcedSlow)*1000;
  583. % Tertile.GroupMean.CoMFreeRT = mean(Tertile.MeanCoMFreeRT)*1000;
  584. % Tertile.GroupMean.CoMFreeSwitch = mean(Tertile.MeanCoMFreeSwitch)*1000;
  585. % Tertile.GroupMean.CoMFreeStay = mean(Tertile.MeanCoMFreeStay)*1000;
  586. % Tertile.GroupMean.CoMFreeFast = mean(Tertile.MeanCoMFreeFast)*1000;
  587. % Tertile.GroupMean.CoMFreeMedium = mean(Tertile.MeanCoMFreeMedium)*1000;
  588. % Tertile.GroupMean.CoMFreeSlow = mean(Tertile.MeanCoMFreeSlow)*1000;
  589. % Tertile.GroupMean.CoMForcedRT = mean(Tertile.MeanCoMForcedRT)*1000;
  590. % Tertile.GroupMean.CoMForcedSwitch = mean(Tertile.MeanCoMForcedSwitch)*1000;
  591. % Tertile.GroupMean.CoMForcedStay = mean(Tertile.MeanCoMForcedStay)*1000;
  592. % Tertile.GroupMean.CoMForcedFast = mean(Tertile.MeanCoMForcedFast)*1000;
  593. % Tertile.GroupMean.CoMForcedMedium = mean(Tertile.MeanCoMForcedMedium)*1000;
  594. % Tertile.GroupMean.CoMForcedSlow = mean(Tertile.MeanCoMForcedSlow)*1000;
  595. %% Save Epochs
  596. %
  597. % save(['EEG Data/Epoched Data/eegca_GROUP_MB'], ...
  598. % 'Epoch', ...
  599. % 'TC_Resp_DecPhase', ...
  600. % 'Tertile', ...
  601. % 'Group', ...
  602. % 'timepts_struct');
  603. % %
  604. % %% Load Epochs
  605. %
  606. % load(['EEG Data/Epoched Data/eegca_GROUP', plottingData]);
  607. %% Create MB Plots
  608. % Define colours for different transparencies of blue
  609. t1_opacity = [0, 0.4470, 0.7410, 1]; % Dark blue with high opacity
  610. t2_opacity = [0.576, 0.439, 0.859, 1]; % Medium blue with medium opacity
  611. t3_opacity = [1, 0.773, 0, 1]; % Light blue with low opacity
  612. blue_t1_opacity = [0, 0.4470, 0.7410, 1]; % Dark blue with high opacity
  613. blue_t2_opacity = [0, 0.4470, 0.7410, 0.7]; % Medium blue with medium opacity
  614. blue_t3_opacity = [0, 0.4470, 0.7410, 0.3]; % Light blue with low opacity
  615. blue_q1_opacity = [0, 0.4470, 0.7410, 1]; % Dark blue with high opacity
  616. blue_q2_opacity = [0, 0.4470, 0.7410, 0.8]; % Medium blue with medium opacity
  617. blue_q3_opacity = [0, 0.4470, 0.7410, 0.6]; % Light blue with low opacity
  618. blue_q4_opacity = [0, 0.4470, 0.7410, 0.4]; % Light blue with low opacity
  619. red_t1_opacity = [1, 0.1, 0, 1]; % Dark blue with high opacity
  620. red_t2_opacity = [1, 0.1, 0, 0.7]; % Medium blue with medium opacity
  621. red_t3_opacity = [1, 0.1, 0, 0.3]; % Light blue with low opacity
  622. red_q1_opacity = [1, 0.1, 0, 1]; % Dark blue with high opacity
  623. red_q2_opacity = [1, 0.1, 0, 0.8]; % Medium blue with medium opacity
  624. red_q3_opacity = [1, 0.1, 0, 0.6]; % Light blue with low opacity
  625. red_q4_opacity = [1, 0.1, 0, 0.4]; % Light blue with low opacity
  626. ERP_smoothing_constant = 1;
  627. %% Run Bayesian and Frequentist T Tests on
  628. % Frequency bands to average over within ROI
  629. MuBeta_Freq_ttests = [8:30];
  630. % Alpha level for shading
  631. shadingAlpha = 0.2;
  632. % Default from other projects = 0.3
  633. % Run Bayesian t tests and get SD estimates for plotting
  634. % ---MB ---
  635. for timePoint = 1:size(Epoch.FreeStandaloneAll, 2)
  636. % Use Bayesian paired-samples t test from MATLAB bayesFactor
  637. % toolbox (https://klabhub.github.io/bayesFactor/#1)
  638. % Toolbox by Bart Krekelberg adapted from code by Rouder
  639. [MB.bf10(timePoint), MB.p(timePoint)] = ttest_bayes_df( ...
  640. mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, timePoint, :), 1), ...
  641. mean(Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, timePoint, :), 1));
  642. % Frequentist paired-samples t tests
  643. [~, ~, ~, temp_tstats] = ttest( ...
  644. mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, timePoint, :), 1), ...
  645. mean(Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, timePoint, :), 1));
  646. MB.diff_SD(timePoint) = temp_tstats.sd;
  647. end % of for timePoint
  648. % Copy Standalone Results into ERP_Results structure
  649. MB_Results.Standalone.bf10 = MB.bf10;
  650. MB_Results.Standalone.differenceWave_SD = MB.diff_SD;
  651. MB_Results.Standalone.channelsUsed = MuBeta_Freq_ttests;
  652. % Prepare data for cluster-based permutation test
  653. MB_freestandalone = squeeze(mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :), 1));
  654. MB_freestandalone = MB_freestandalone'; % Transpose
  655. MB_forcedstandalone = squeeze(mean(Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :), 1));
  656. MB_forcedstandalone = MB_forcedstandalone'; % Transpose
  657. % Run cluster-based permutation test for Standalone Decisions using function from DDTBOX
  658. [MB_Results.Standalone.cluster_permtest_outputs] =...
  659. eegca_multcomp_cluster_permtest(...
  660. MB_freestandalone, ...
  661. MB_forcedstandalone, ...
  662. 'alpha', cluster_permtest_criticalAlpha, ...
  663. 'iterations', cluster_permtest_iterations, ...
  664. 'clusteringalpha', cluster_permtest_clusteringAlpha, ...
  665. 'use_yuen', 0, ...
  666. 'tail', 'both');
  667. % Save Standalone Results from cluster-based permutation test
  668. MB_Results.Standalone.cluster_permtest_criticalAlpha = cluster_permtest_criticalAlpha;
  669. MB_Results.Standalone.cluster_permtest_clusteringAlpha = cluster_permtest_clusteringAlpha;
  670. MB_Results.Standalone.cluster_permtest_iterations = cluster_permtest_iterations;
  671. % Add timepoints information and info about EEG data
  672. MB_Results.Standalone.timepoints = timepts_struct.resp;
  673. MB_Results.Standalone.chanlocs = chanlocs;
  674. % Y Offset for statistical significance markers in plot
  675. sigMarkers_Y_Offset = 3; % Add extra one to account for 1/0 h test coding
  676. % E.g., A value of 2 means sig. timepoints will appear at Y value -1
  677. %% Plot MB and Diffs Below
  678. figure('Name', 'Free vs Forced Initial MB');
  679. subplot(6, 1, 1:3);
  680. plot(timepts_struct.resp, ...
  681. mean(mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :), ...
  682. 1), ...
  683. 3), ...
  684. 'linewidth', 2);
  685. hold on;
  686. plot(timepts_struct.resp, ...
  687. mean(mean(Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :), ...
  688. 1), ...
  689. 3), ...
  690. 'linewidth', 2);
  691. % Plot statistical significance markers from cluster-based permutation test
  692. tempSigMarkers = MB_Results.Standalone.cluster_permtest_outputs.corrected_h;
  693. tempSigMarkers(tempSigMarkers == 0) = nan;
  694. plot(timepts_struct.resp, ...
  695. tempSigMarkers - sigMarkers_Y_Offset, ...
  696. 'linewidth', 2);
  697. xlim([-1000, 100]);
  698. ylim([-2.5, -0.5]);
  699. x_patch = [-130, -70, -70, -130];
  700. y_patch = [-14, -14, 6, 6];
  701. fill(x_patch, y_patch, [0.8 0.8 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.4);
  702. xline(0, 'k', 'LineWidth', 1.5);
  703. line([timepts_struct.resp(1), timepts_struct.resp(end)], [0, 0], 'color', 'k');
  704. ylabel('dB');
  705. %legend({'Free', 'Forced'}, 'location', 'southwest');
  706. title('Motor Preparation Mu/Beta (8-30Hz)');
  707. % Mean Difference and SEMs
  708. subplot(6, 1, 4);
  709. plot(timepts_struct.resp, ...
  710. mean(mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :) - Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :), ...
  711. 1), ...
  712. 3), ...
  713. 'linewidth', 2);
  714. hold on;
  715. xlim([-1000, 100]);
  716. line([timepts_struct.resp(1), timepts_struct.resp(end)], [0, 0], 'color', 'k');
  717. % Make shaded standard error regions (using functions from DDTBOX v1.0.5)
  718. % First, calculate mean values and standard errors
  719. avg_y_vals = mean(mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :) - Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :), 1), 3);
  720. % Calculate standard errors of the mean
  721. standard_error_vals = ...
  722. std( ...
  723. squeeze( ...
  724. mean( ...
  725. Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :) - Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :) ...
  726. , 1) ...
  727. )' ...
  728. ) ...
  729. ./ sqrt(size(Epoch.FreeStandaloneAll, 3));
  730. % Create shaded error regions
  731. [patch_x, patch_y] = dd_make_error_bar_object(timepts_struct.resp, ...
  732. avg_y_vals, ...
  733. standard_error_vals);
  734. SE_shading = patch('xdata', patch_x, 'ydata', patch_y);
  735. SE_shading.FaceAlpha = shadingAlpha; % Transparency
  736. % SE_shading.FaceColor = spectra_plots_colour_map(1, :);
  737. SE_shading.EdgeColor = 'none';
  738. xlim([-1000, 100]);
  739. ylim([-0.5, 0.5]);
  740. ylabel('Diff [µV]');
  741. % Effect Sizes (Cohen's d)
  742. subplot(6, 1, 5);
  743. plot(timepts_struct.resp, ...
  744. mean(mean(Epoch.FreeStandaloneAll(MuBeta_Freq_ttests, :, :) - Epoch.ForcedStandaloneAll(MuBeta_Freq_ttests, :, :), ...
  745. 1), ...
  746. 3) ...
  747. ./ MB_Results.Standalone.differenceWave_SD, ...
  748. 'linewidth', 2);
  749. ylabel('Cohen''s d');
  750. ylim([-1, 0.5]);
  751. xlim([-1000, 100]);
  752. line([timepts_struct.resp(1), timepts_struct.resp(end)], [0, 0], 'color', 'k');
  753. % Bayes Factors BF10
  754. subplot(6, 1, 6);
  755. semilogy(timepts_struct.resp, ...
  756. MB_Results.Standalone.bf10, ...
  757. 'linewidth', 2);
  758. ylim([0, 1500]);
  759. xlim([-1000, 100]);
  760. line([timepts_struct.resp(1), timepts_struct.resp(end)], [1, 1], 'color', 'k');
  761. ylabel('BF10');
  762. yticks([0, 1, 100, 1000]);
  763. % Save plot
  764. %saveas(gcf, 'ERP Plots/no RIDE Mass Uni MB Resp.png');
  765. % subplot(7, 1, 7);
  766. % plot(timepts_struct.resp, ...
  767. % ROI.p, ...
  768. % 'linewidth', 2);
  769. % ylim([0, 1]);
  770. %
  771. % line([timepts_struct.resp(1), timepts_struct.resp(end)], [0.05, 0.05], 'color', 'k');
  772. % ylabel('p');
  773. %% Cluster-based permutation tests for Slope and Amplitude Regressions
  774. % Assumptions:
  775. % - mb_slope_beta_RT.free / .forced: [nSubjects x nTimeValid]
  776. % - mb_amp_beta_RT.free / .forced: [nSubjects x nTimeValid] if you used the SAME window;
  777. % otherwise mask amplitude to the same valid region first.
  778. % - timepts_struct.resp: 1 x nTime (ms) for the full epoch
  779. % - time_valid: 1 x nTimeValid (ms) for the valid interior samples
  780. % - eegca_multcomp_cluster_permtest: your cluster test util; accepts (data, null, ...)
  781. % - ttest_bayes_df: your helper returning (bf10, p)
  782. measures = { ...
  783. struct('name','Slope','data', mb_slope_beta_RT,'time',group_time_valid), ...
  784. struct('name','Amp', 'data', mb_amp_beta_RT, 'time',group_time_valid) ...
  785. };
  786. conds_out = {'Free','Forced'};
  787. MB_RT_Results = struct();
  788. for m = 1:numel(measures)
  789. meas_name = measures{m}.name;
  790. meas_data = measures{m}.data;
  791. meas_time = measures{m}.time;
  792. for ci = 1:numel(conds_out)
  793. cname = lower(conds_out{ci});
  794. if ~isfield(meas_data, cname) || isempty(meas_data.(cname))
  795. warning('%s/%s: beta matrix missing or empty.', meas_name, cname);
  796. continue
  797. end
  798. betas = meas_data.(cname);
  799. keep_subj = any(isfinite(betas),2);
  800. betas = betas(keep_subj,:);
  801. keep_time = any(isfinite(betas),1);
  802. betas = betas(:,keep_time);
  803. time_use = meas_time(keep_time);
  804. if isempty(betas) || size(betas,1) < 5
  805. warning('%s/%s: not enough usable data after NaN filtering.', meas_name, cname);
  806. continue
  807. end
  808. MB_RT_Results.(meas_name).(conds_out{ci}).cluster_permtest_outputs = ...
  809. eegca_multcomp_cluster_permtest( ...
  810. betas, zeros(size(betas)), ...
  811. 'alpha', cluster_permtest_criticalAlpha, ...
  812. 'iterations', cluster_permtest_iterations, ...
  813. 'clusteringalpha', cluster_permtest_clusteringAlpha, ...
  814. 'use_yuen', 0, ...
  815. 'tail', 'both');
  816. MB_RT_Results.(meas_name).(conds_out{ci}).time = time_use;
  817. MB_RT_Results.(meas_name).(conds_out{ci}).nSubjects = size(betas,1);
  818. Tuse = size(betas,2);
  819. bf10 = nan(1,Tuse); pval = nan(1,Tuse); sd_b = nan(1,Tuse);
  820. for tt = 1:Tuse
  821. x = betas(:,tt); x = x(isfinite(x));
  822. if numel(x) < 5, continue, end
  823. [bf10(tt), pval(tt)] = ttest_bayes_df(x, 0);
  824. [~, ~, ~, stats] = ttest(x, 0);
  825. if isfield(stats,'sd'), sd_b(tt) = stats.sd; end
  826. end
  827. MB_RT_Results.(meas_name).(conds_out{ci}).bf10 = bf10;
  828. MB_RT_Results.(meas_name).(conds_out{ci}).p = pval;
  829. MB_RT_Results.(meas_name).(conds_out{ci}).diff_SD = sd_b;
  830. end
  831. end
  832. %% -------- TOP: FREE --------
  833. figure;
  834. subplot(6,1,1:2);
  835. hold on;
  836. % Define colours and labels for different tertiles
  837. colors = {t1_opacity, t2_opacity, t3_opacity};
  838. labels = {'Fast', 'Medium', 'Slow'};
  839. dataFieldsFree = {'FreeStandaloneFast', 'FreeStandaloneMedium', 'FreeStandaloneSlow'};
  840. for i = 1:3
  841. % Extract the current tertile data for Free condition
  842. data = Epoch.(dataFieldsFree{i})(MB_freq, :, :);
  843. % Calculate mean and SEM for the current tertile
  844. avg_y_vals = mean(mean(data, 1), 3);
  845. standard_error_vals = std(squeeze(mean(data, 1))') ./ sqrt(size(data, 3));
  846. % Plot mean line
  847. plot(timepts_struct.resp, smoothdata(avg_y_vals, 'gaussian', ERP_smoothing_constant), ...
  848. 'Color', colors{i}(1:4), 'LineWidth', 2, 'DisplayName', labels{i});
  849. % Shaded error
  850. [patch_x, patch_y] = dd_make_error_bar_object(timepts_struct.resp, avg_y_vals, standard_error_vals);
  851. SE_shading = patch('xdata', patch_x, 'ydata', patch_y);
  852. SE_shading.FaceAlpha = 0.2;
  853. SE_shading.FaceColor = colors{i}(1:3);
  854. SE_shading.EdgeColor = 'none';
  855. end
  856. % ----- Cluster permutation markers -----
  857. % Slope
  858. sigMaskSlopeFree = MB_RT_Results.Slope.Free.cluster_permtest_outputs.corrected_h;
  859. sigMaskSlopeFree(sigMaskSlopeFree==0) = NaN;
  860. y_mark_slope = -2.4;
  861. plot(MB_RT_Results.Slope.Free.time, sigMaskSlopeFree * y_mark_slope, 'k-', 'LineWidth', 2);
  862. % Amplitude
  863. sigMaskAmpFree = MB_RT_Results.Amp.Free.cluster_permtest_outputs.corrected_h;
  864. sigMaskAmpFree(sigMaskAmpFree==0) = NaN;
  865. y_mark_amp = -2.2; % offset so lines don't overlap
  866. plot(MB_RT_Results.Amp.Free.time, sigMaskAmpFree * y_mark_amp, 'r-', 'LineWidth', 2);
  867. xlim([-1000, 50]);
  868. ylim([-2.5, 0]);
  869. x_patch = [-130, -70, -70, -130];
  870. x2_patch = [-300, -70, -70, -300];
  871. y_patch = [-2.5, -2.5, 0, 0];
  872. fill(x_patch, y_patch, [0.8 0.8 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.4);
  873. fill(x2_patch, y_patch, [0.8 0.8 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.2);
  874. xline(0, 'k', 'LineWidth', 1.5);
  875. ylabel('µV/m^2');
  876. title('MB - Voluntary Decisions');
  877. % BF
  878. subplot(6,1,3);
  879. % Slope BF10
  880. semilogy(MB_RT_Results.Slope.Free.time, MB_RT_Results.Slope.Free.bf10, 'k-', 'LineWidth', 1.8, 'DisplayName', 'Free Slope BF_{10}');
  881. hold on;
  882. % Amplitude BF10
  883. semilogy(MB_RT_Results.Amp.Free.time, MB_RT_Results.Amp.Free.bf10, 'r-', 'LineWidth', 1.8, 'DisplayName', 'Free Amp BF_{10}');
  884. % Reference lines
  885. xline(0, 'k', 'LineWidth', 1.5);
  886. yline(1, 'k', 'LineWidth', 1); % BF=1 reference
  887. % yline(3, 'k--', 'LineWidth', 1); % optional: "moderate evidence" threshold
  888. xlim([-1000, 50]);
  889. ylim([0, 150])
  890. yticks([0,1, 100]);
  891. ylabel('BF_{10}');
  892. xlabel('Time (ms)');
  893. title('BF (Slope & Amplitude)');
  894. % -------- MIDDLE: FORCED --------
  895. subplot(6,1,4:5);
  896. hold on;
  897. dataFieldsForced = {'ForcedStandaloneFast', 'ForcedStandaloneMedium', 'ForcedStandaloneSlow'};
  898. for i = 1:3
  899. data = Epoch.(dataFieldsForced{i})(MB_freq, :, :);
  900. avg_y_vals = mean(mean(data, 1), 3);
  901. standard_error_vals = std(squeeze(mean(data, 1))') ./ sqrt(size(data, 3));
  902. plot(timepts_struct.resp, smoothdata(avg_y_vals, 'gaussian', ERP_smoothing_constant), ...
  903. 'Color', colors{i}(1:4), 'LineWidth', 2, 'DisplayName', labels{i});
  904. [patch_x, patch_y] = dd_make_error_bar_object(timepts_struct.resp, avg_y_vals, standard_error_vals);
  905. SE_shading = patch('xdata', patch_x, 'ydata', patch_y);
  906. SE_shading.FaceAlpha = 0.2;
  907. SE_shading.FaceColor = colors{i}(1:3);
  908. SE_shading.EdgeColor = 'none';
  909. end
  910. % Slope
  911. sigMaskSlopeForced = MB_RT_Results.Slope.Forced.cluster_permtest_outputs.corrected_h;
  912. sigMaskSlopeForced(sigMaskSlopeForced==0) = NaN;
  913. plot(MB_RT_Results.Slope.Forced.time, sigMaskSlopeForced * y_mark_slope, 'k-', 'LineWidth', 2);
  914. % Amplitude
  915. sigMaskAmpForced = MB_RT_Results.Amp.Forced.cluster_permtest_outputs.corrected_h;
  916. sigMaskAmpForced(sigMaskAmpForced==0) = NaN;
  917. plot(MB_RT_Results.Amp.Forced.time, sigMaskAmpForced * y_mark_amp, 'r-', 'LineWidth', 2);
  918. xlim([-1000, 50]);
  919. ylim([-2.5, 0]);
  920. x_patch = [-130, -70, -70, -130];
  921. x2_patch = [-300, -70, -70, -300];
  922. y_patch = [-3, -3, 0, 0];
  923. fill(x_patch, y_patch, [0.8 0.8 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.4);
  924. fill(x2_patch, y_patch, [0.8 0.8 0.8], 'EdgeColor', 'none', 'FaceAlpha', 0.2);
  925. xline(0, 'k', 'LineWidth', 1.5);
  926. ylabel('µV/m^2');
  927. title('MB - Forced Decisions');
  928. hold off;
  929. % -------- BOTTOM: BAYES FACTORS (correct .bf10 fields) --------
  930. subplot(6,1,6);
  931. % Slope BF10
  932. semilogy(MB_RT_Results.Slope.Forced.time, MB_RT_Results.Slope.Forced.bf10, 'k-', 'LineWidth', 1.8, 'DisplayName', 'Forced Slope BF_{10}');
  933. hold on;
  934. % Amplitude BF10
  935. semilogy(MB_RT_Results.Amp.Forced.time, MB_RT_Results.Amp.Forced.bf10, 'r-', 'LineWidth', 1.8, 'DisplayName', 'Forced Amp BF_{10}');
  936. % Reference lines
  937. xline(0, 'k', 'LineWidth', 1.5);
  938. yline(1, 'k', 'LineWidth', 1); % BF=1 reference
  939. xlim([-1000, 50]);
  940. ylim([0, 110000]);
  941. yticks([0,1, 150, 10^5]);
  942. ylabel('BF_{10}');
  943. xlabel('Time (ms)');
  944. title('BF (Slope & Amplitude)');

eegca_massuni_MB.m, no license · at the source

Overview

  1. Melbourne School of Psychological Sciences, The University of Melbourne, Melbourne, Australia
  2. Division of Science, New York University Abu Dhabi, Abu Dhabi, United Arab Emirates
Institutions: The University of Melbourne (Australia); New York University Abu Dhabi (United Arab Emirates)
Journal: Imaging neuroscience (Cambridge, Mass.), volume 4, article IMAG.a.1184
Dates: received 3 November 2025; accepted 27 February 2026; published online 30 March 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1162/imag.a.1184 · PMID 41924032 · PMCID PMC13037662 · OpenAlex W7134814849
Open access: diamond, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: cognitive (subfield)
Methods: Statistics, Smoothing, state filtering, decompositions, Preprocessing, Spectral & time-frequency, Evoked potentials, Physiology & signal measures, Machine learning
Keywords: CPP, RP, mu/beta, evidence accumulation, motor preparation, voluntary decisions
Topic: Neural and Behavioral Psychology Studies (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: Department of Education and Training | Australian Research Council (ARC) (DE220101508); Melbourne Research Scholarship
Citations: cited by 2 papers (Europe PMC); 97 references in the paper

Abstract

Voluntary decisions have previously been described by where they arise in the brain and how actions corresponding to one’s choice are prepared. However, the processes by which these internally guided decisions are formed and translated into action remain unclear. We tested whether neural signatures of evidence accumulation and motor preparation—established in perceptual decision-making—are also observed during voluntary decisions. Forty-nine adults made voluntary (free choice between two options) and forced (single specified choice) decisions while electroencephalography was recorded. To isolate decision formation from action selection, all responses were made with a right-handed keypress. After applying signal deconvolution and current source density transformations, we examined three signals: the centro-parietal positivity (CPP), Mu/Beta (8–30 Hz) amplitudes, and a left-hemisphere readiness potential contralateral to the response hand. For both voluntary and forced decisions, CPP and Mu/Beta amplitudes showed hallmark accumulation-to-bound dynamics—faster responses had steeper ramping signals that converged to stereotyped pre-response amplitude levels. The left-hemisphere readiness potential likewise showed convergence to a pre-response level but with less reliable evidence for response time (RT)-dependent slope scaling, resembling a late, effector-specific motor gate rather than an evolving decision variable. Waveform amplitudes across the time course of these signals also did not differ reliably between voluntary and forced decisions. Our results indicate that, like perceptual decisions, voluntary choices are also formed by a graded accumulation process that culminates in a motor action, with the CPP indexing an evolving decision variable and Mu/Beta indexing effector-specific motor readiness.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 16 matches between paragraphs and lines of code.

OSF t7z4h

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Languages: MATLAB (53), R (1)
Size: 129 files, 54 scripts
Software Heritage: not checked
Found in: “Data and Code Availability”
Holds: 1 notebook
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Psychtoolbox (17 files), EEGLAB (11 files), Statistics and Machine Learning Toolbox (7 files), afex (1 file), broom (1 file), emmeans (1 file), lme4 (1 file), lmerTest (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
  • 30 September 2026: the link answers (HTTP 200)
54 files
At the source: osf.io/t7z4h

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 54 scripts, each with its path and the digest of its content;
  • 16 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data and Code Availability

All code and data used for the experiment and analyses described in this manuscript are available at http://osf.io/t7z4h.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 30 September 2026: the first record

Recorded: type, language, journal, volume, pages, dates, 6 authors, 6 keywords, 2 funders, 96 references.

Cite

This paper

Fong, L. C., Garrett, P. M., Smith, P. L., Hester, R., Bode, S., & Feuerriegel, D. (2026). Tracing the neural trajectories of evidence accumulation and motor preparation processes during voluntary decisions. Imaging neuroscience (Cambridge, Mass.), 4, IMAG.a.1184. https://doi.org/10.1162/imag.a.1184

BibTeX

@article{fong2026tracing,
author = {Fong, Lauren C. and Garrett, Paul M. and Smith, Philip L. and Hester, Robert and Bode, Stefan and Feuerriegel, Daniel},
title = {{Tracing the neural trajectories of evidence accumulation and motor preparation processes during voluntary decisions}},
journal = {Imaging neuroscience (Cambridge, Mass.)},
year = {2026},
month = mar,
volume = {4},
pages = {IMAG.a.1184},
publisher = {MIT Press},
issn = {2837-6056},
doi = {10.1162/imag.a.1184},
url = {https://doi.org/10.1162/imag.a.1184},
pmid = {41924032},
pmcid = {PMC13037662}
}

RIS

TY - JOUR
AU - Fong, Lauren C.
AU - Garrett, Paul M.
AU - Smith, Philip L.
AU - Hester, Robert
AU - Bode, Stefan
AU - Feuerriegel, Daniel
TI - Tracing the neural trajectories of evidence accumulation and motor preparation processes during voluntary decisions
T2 - Imaging neuroscience (Cambridge, Mass.)
J2 - Imaging Neurosci (Camb)
PY - 2026
DA - 2026/03/30
VL - 4
SP - IMAG.a.1184
SN - 2837-6056
PB - MIT Press
DO - 10.1162/imag.a.1184
UR - https://doi.org/10.1162/imag.a.1184
LA - en
ER -

CSL-JSON

{
"id": "10.1162/imag.a.1184",
"type": "article-journal",
"title": "Tracing the neural trajectories of evidence accumulation and motor preparation processes during voluntary decisions",
"container-title": "Imaging neuroscience (Cambridge, Mass.)",
"author": [
{
"family": "Fong",
"given": "Lauren C."
},
{
"family": "Garrett",
"given": "Paul M."
},
{
"family": "Smith",
"given": "Philip L."
},
{
"family": "Hester",
"given": "Robert"
},
{
"family": "Bode",
"given": "Stefan"
},
{
"family": "Feuerriegel",
"given": "Daniel"
}
],
"container-title-short": "Imaging Neurosci (Camb)",
"volume": "4",
"page": "IMAG.a.1184",
"DOI": "10.1162/imag.a.1184",
"PMID": "41924032",
"PMCID": "PMC13037662",
"ISSN": "2837-6056",
"publisher": "MIT Press",
"URL": "https://doi.org/10.1162/imag.a.1184",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
30
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1523/eneuro.0316-25.2026 [code]
Neural Mechanisms of Self-Generated Action Sequences.
Journal: eNeuro
In common: EEGLAB, emmeans, lmerTest, 3 other tools, cognitive, 14 references
[2] doi:10.7554/elife.83025 [code]
Balancing true and false detection of intermittent sensory targets by adjusting the inputs to the evidence accumulation process.
Journal: eLife
In common: Psychtoolbox, EEGLAB, Statistics and Machine Learning Toolbox, cognitive, 14 references
[3] doi:10.1016/j.isci.2026.115471 [code]
Neural decision dynamics underlying reinforcement learning and working memory.
Journal: iScience
In common: cognitive, 16 references
[4] doi:10.7554/elife.82823 [code]
Quantifying decision-making in dynamic, continuously evolving environments.
Journal: eLife
In common: Psychtoolbox, EEGLAB, Statistics and Machine Learning Toolbox, cognitive, 13 references
[5] doi:10.1038/s42003-025-07646-3 [code]
Neural mechanisms of metacognitive improvement under speed pressure.
Journal: Communications biology
In common: afex, lme4, tidyverse, cognitive, 11 references
[6] doi:10.1093/cercor/bhaf318 [code]
Voluntary action as problem-solving: an functional magnetic resonance imaging study.
Journal: Cerebral cortex (New York, N.Y. : 1991)
In common: emmeans, lmerTest, lme4, 1 other tool, cognitive, 9 references
[7] doi:10.1038/s41562-024-01971-z [code]
Common neural choice signals can emerge artefactually amid multiple distinct value signals.
Journal: Nature human behaviour
In common: EEGLAB, lmerTest, lme4, 2 other tools, cognitive, 10 references
[8] doi:10.1111/psyp.70076 [code]
Limited Evidence for Probabilistic Cueing Effects on Grating-Evoked Event-Related Potentials and Orientation Decoding Performance.
Journal: Psychophysiology
In common: EEGLAB, Statistics and Machine Learning Toolbox, 9 references, author Daniel Feuerriegel
[9] doi:10.3758/s13423-022-02237-3 [code]
"Reliable organisms from unreliable components" revisited: the linear drift, linear infinitesimal variance model of decision making.
Journal: Psychonomic bulletin & review
In common: cognitive, 9 references, author Philip L. Smith
[10] doi:10.3389/fpsyg.2024.1380196 [code]
Modality-specific impacts of distractors on visual and auditory categorical decision-making: an evidence accumulation perspective.
Journal: Frontiers in psychology
In common: broom, EEGLAB, emmeans, 4 other tools, cognitive, 7 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.1162/imag.a.1184.svg)](https://openscicode.org/badge/doi/10.1162/imag.a.1184)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1162/imag.a.1184.svg
   :target: https://openscicode.org/badge/doi/10.1162/imag.a.1184
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1162/imag.a.1184"><img src="https://openscicode.org/badge/doi/10.1162/imag.a.1184.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.