feat(matlab): windowed paper-LME replication for mergeNaive (d0_10, d0_13)
Make tdcs_paper_lme window-aware (windowKey 'full'|'d0_10'|'d0_13', default 'full' -> unchanged filename). Windowed runs give the two anchor arms equal day coverage, so the stim:day interaction is not confounded by the full-range coverage imbalance; the report now states whether coverage is equal and adds an INTERPRETATION block. Add switch cases paper_mergeNaive_d0_10 / _d0_13 and include them in run_all. Finding: unlike mergeA2 (fair-window interaction n.s.), the pooled-naive control keeps the interaction significant in the fair d0_13 window (F(1)=7.07, p=0.0088, +1.80 [+0.46,+3.14]; equal on Day 1 p=0.20), reproducing the paper without the coverage confound; d0_10 is borderline (p=0.051). Tests: tLme asserts equal coverage / no warning / one full summary for both windows and a significant positive d0_13 interaction; bad windowKey errors. Suite 41/41. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,36 @@ classdef tLme < matlab.unittest.TestCase
|
||||
testCase.verifyError(@() tdcs_glm('lme_nonsense'), 'tdcs_glm:badScenario');
|
||||
end
|
||||
|
||||
function testPaperMergeNaiveWindowedFairCoverage(testCase)
|
||||
% The windowed paper_mergeNaive_* runs cap both anchor arms at the
|
||||
% window end (equal coverage -> no confound warning), write their own
|
||||
% results file, and embed the full fitlme summary. Unlike mergeA2,
|
||||
% the pooled-naive control keeps the interaction significant in the
|
||||
% fair d0_13 window (~ the paper's F=7.12, p=0.008).
|
||||
here = fileparts(fileparts(mfilename('fullpath'))); % analysis/matlab
|
||||
resDir = fullfile(here, 'results');
|
||||
for w = {'d0_10', 'd0_13'}
|
||||
name = ['paper_mergeNaive_' w{1}];
|
||||
evalc(sprintf('tdcs_glm(''%s'')', name));
|
||||
txt = fileread(fullfile(resDir, [name '.txt']));
|
||||
testCase.verifyTrue(contains(txt, 'Equal day coverage'), ...
|
||||
sprintf('%s: expected equal (fair) day coverage', name));
|
||||
testCase.verifyFalse(contains(txt, '** WARNING'), ...
|
||||
sprintf('%s: fair window should not warn', name));
|
||||
testCase.verifyEqual(count(txt, 'Fixed effects coefficients (95% CIs):'), 1);
|
||||
end
|
||||
% Fair-window d0_13 interaction reproduces the paper (~F=7.1, p~0.009).
|
||||
L = tdcs_paper_lme('mergeNaive', tdcs_config(), 'd0_13');
|
||||
testCase.verifyEqual(L.maxDayStim, L.maxDayCtrl); % equal coverage
|
||||
testCase.verifyLessThan(L.interaction.p, 0.05);
|
||||
testCase.verifyGreaterThan(L.interaction.estimate, 0);
|
||||
end
|
||||
|
||||
function testPaperLmeBadWindowErrors(testCase)
|
||||
testCase.verifyError(@() tdcs_paper_lme('mergeNaive', tdcs_config(), 'bogus'), ...
|
||||
'tdcs_paper_lme:badWindow');
|
||||
end
|
||||
|
||||
function testReportsIncludeFullModelSummary(testCase)
|
||||
% Every scenario prints the full native fitlme summary. The lme_*,
|
||||
% paper_*, and phase_* reports each embed disp(model), whose
|
||||
|
||||
Reference in New Issue
Block a user