Skip to content

Commit 15b7e50

Browse files
committed
Fix TAM z-score normalization
1 parent b1e525c commit 15b7e50

2 files changed

Lines changed: 106 additions & 11 deletions

File tree

‎src/pspm_tam.m‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
% Filling up the data and the sampling rates
156156
y{iFile} = data.data(:);
157157
sr(iFile) = data.header.sr;
158-
158+
159159
fprintf('.');
160160
end
161161

@@ -174,15 +174,15 @@
174174
fprintf('\n');
175175
end
176176

177-
%% Zscoring the data -> can be done by pspm_extract_segments ! what is with nans?
178-
if model.norm
179-
fprintf('Zscoring ...\n')
180-
n_file = numel(model.datafile);
181-
for iFile = 1:n_file
182-
% NANZSCORE found in src/ext/VBA/stats&plots
183-
[y{iFile},~,~] = nannorm(y{iFile}); %nannorm??? -> nanzscore??
184-
end
185-
end
177+
%% Zscoring the data -> will be done by pspm_extract_segments
178+
% if model.norm
179+
% fprintf('Zscoring ...\n')
180+
% n_file = numel(model.datafile);
181+
% for iFile = 1:n_file
182+
% % NANZSCORE found in src/ext/VBA/stats&plots
183+
% [y{iFile},~,~] = nanzscore(y{iFile}); %nannorm??? -> nanzscore??
184+
% end
185+
% end
186186

187187
%% Extracting segments
188188
fprintf('Extracting segments ...\n')
@@ -191,6 +191,7 @@
191191
extrsgopt.timeunits = model.timeunits;
192192
extrsgopt.length = model.window; % segments of 'model.window' time unit long
193193
extrsgopt.plot = 0; % do not plot mean value and std
194+
extrsgopt.norm = model.norm;
194195

195196
for k=1:n_file
196197
if strcmpi(model.timeunits, 'markers')
@@ -207,7 +208,6 @@
207208

208209
% In file mode the raw pupil data are loaded again,
209210
% so normalization must happen inside extract_segments.
210-
fileopt.norm = model.norm;
211211
[lsts, s] = pspm_extract_segments( 'file', model.datafile{k}, model.channel, model.timing{k}, fileopt);
212212
else
213213
[lsts, s] = pspm_extract_segments('data', y{k}, sr(k), model.timing{k}, extrsgopt); % wird es richtig gen znormed?

‎test/pspm_tam_test.m‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,102 @@ function testMarkerTimeunits(testCase, nFiles)
675675

676676
end
677677

678+
function testZscoreNormalization(testCase)
678679

680+
sr = 10;
681+
duration = 50;
682+
window = 5;
683+
684+
t = (0:1/sr:window-1/sr)';
685+
response = exp(-((t - 2).^2) / (2 * 0.5^2));
686+
687+
onsets = [10 20 30];
688+
689+
y = zeros(duration * sr, 1);
690+
691+
for iTrial = 1:numel(onsets)
692+
startSample = round(onsets(iTrial) * sr) + 1;
693+
stopSample = startSample + numel(response) - 1;
694+
695+
y(startSample:stopSample) = ...
696+
y(startSample:stopSample) + response;
697+
end
698+
699+
timing.names = {'condition_1'};
700+
timing.onsets = {onsets};
701+
timing.durations = {zeros(size(onsets))};
702+
703+
data = cell(1,1);
704+
705+
data{1}.header = struct( ...
706+
'chantype', 'pupil', ...
707+
'sr', sr, ...
708+
'units', 'a.u.');
709+
710+
data{1}.data = y(:);
711+
712+
infos.duration = duration;
713+
infos.durationinfo = 'Duration in seconds';
714+
infos.source = struct();
715+
716+
datafile = [tempname '.mat'];
717+
save(datafile, 'data', 'infos');
718+
testCase.addTeardown(@() deleteIfExists(datafile));
719+
720+
% ----
721+
modelfile = [tempname '.mat'];
722+
testCase.addTeardown(@() deleteIfExists(modelfile));
723+
724+
model = struct();
725+
726+
model.modelfile = modelfile;
727+
model.datafile = {datafile};
728+
model.timing = {timing};
729+
730+
model.timeunits = 'seconds';
731+
model.window = window;
732+
733+
model.modelspec = 'dilation';
734+
model.modality = 'pupil';
735+
model.channel = 'pupil';
736+
737+
% This is what we are testing
738+
model.norm = 1;
739+
740+
model.baseline = 0;
741+
model.norm_max = 0;
742+
743+
model.filter = struct( ...
744+
'lpfreq', 'none', ...
745+
'lporder', 1, ...
746+
'hpfreq', 'none', ...
747+
'hporder', 1, ...
748+
'down', 'none', ...
749+
'direction', 'bi');
750+
751+
options.overwrite = 1;
752+
753+
[sts, tam] = pspm_tam(model, options);
754+
755+
testCase.verifyEqual(sts, 1);
756+
757+
% Expected z-scoring of the COMPLETE continuous time series
758+
mu = mean(y, 'omitnan');
759+
sigma = std(y, 0, 'omitnan');
760+
761+
expected = (response - mu) / sigma;
762+
763+
% TAM subsequently baselines against the first point
764+
expected = expected - expected(1);
765+
766+
testCase.verifyEqual( ...
767+
tam.data.Y{1}, ...
768+
expected(:), ...
769+
'AbsTol', 1e-10);
770+
771+
testCase.verifyEqual(tam.data.norm, 1);
772+
773+
end
679774

680775

681776

0 commit comments

Comments
 (0)