From defba27faaa0008ce5f863ba7ddd3cb6b788b85e Mon Sep 17 00:00:00 2001 From: Dominik Bach Date: Thu, 29 Aug 2024 09:51:14 +0200 Subject: [PATCH 1/4] fix errors in pspm_extract_segments when timeunits is marker and n_sn>2 --- src/pspm_extract_segments.m | 14 ++++++++------ src/pspm_glm.m | 7 ++++++- src/pspm_multi2index.m | 8 ++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/pspm_extract_segments.m b/src/pspm_extract_segments.m index dfe5ff06c..f41e15f85 100644 --- a/src/pspm_extract_segments.m +++ b/src/pspm_extract_segments.m @@ -133,6 +133,7 @@ switch method case 'data' data_raw = data; + if isnumeric(data), data_raw = {data}; end case 'file' for i_sn = 1:numel(datafile) [lsts, alldata{i_sn}] = pspm_load_channel(datafile{i_sn}, channel); @@ -152,6 +153,9 @@ case 'model' if strcmpi(data.modeltype, 'glm') data_raw = data.input.data; + timing = data.input.timing; + options.timeunits = data.input.timeunits; + events = data.input.events; elseif strcmpi(data.modeltype, 'dcm') data_raw = data.input.scr; else @@ -181,19 +185,15 @@ session_duration(i_sn, 1) = numel(data_raw{i_sn}); end -if strcmpi(method, 'model') && strcmpi(data.modeltype, 'glm') - timing = data.input.timing; -end - - if strcmpi(method, 'model') && strcmpi(data.modeltype, 'dcm') % DCM has no condition information - onsets{1} = cellfun(@(x, y) pspm_time2index(x, sr , y), ... + onsets = cellfun(@(x, y) pspm_time2index(x, sr , y), ... data.input.trlstart(:), ... num2cell(session_duration), ... 'UniformOutput', false); names{1} = 'all'; n_cond = 1; + options.timeunits = 'seconds'; else [lsts, multi] = pspm_get_timing('onsets', timing, options.timeunits); [msts, onsets] = pspm_multi2index(options.timeunits, multi, sr, session_duration, events); @@ -204,6 +204,8 @@ end end +% onsets has the structure: onsets{i_cond}{i_sn} + %% prepare missing if isfield(options, 'missing') missing = options.missing; diff --git a/src/pspm_glm.m b/src/pspm_glm.m index 263ff2127..414cbd9cd 100644 --- a/src/pspm_glm.m +++ b/src/pspm_glm.m @@ -241,7 +241,10 @@ warning('ID:invalid_input', 'Could not load the specified markerchannel'); return end - events{iFile} = data.data(:) * data.header.sr; + % here, data.header.sr correponds to the time resolution of the + % time stamps which should always be 1, but this will convert any + % potentially deviating time stamp resolution to seconds + events{iFile} = data.data(:) / data.header.sr; if strcmp(model.timeunits,'markervalues') model.timing{iFile}.markerinfo = data.markerinfo; end @@ -491,6 +494,7 @@ %% 12 collect data & regressors for output model glm.input.data = y; glm.input.sr = sr; +glm.input.events = events; glm.Y = Y; glm.M = M; % set to 1 if data is missing, otherwise set to 0 glm.infos.sr = newsr; @@ -758,6 +762,7 @@ %% 17 save data % 17.1 overwrite is determined in load1 -- +glm.datetime = datetime; savedata = struct('glm', glm); [sts, data_load1, mdltype_load1] = pspm_load1(model.modelfile, 'save', savedata, options); diff --git a/src/pspm_multi2index.m b/src/pspm_multi2index.m index 0d8ee95bf..e69d816bf 100644 --- a/src/pspm_multi2index.m +++ b/src/pspm_multi2index.m @@ -8,7 +8,7 @@ % [onsets, durations] = pspm_multi2index('markers', multi, sr, session_duration, events) % ● Arguments % * multi : multi structure from pspm_get_timing -% sr : sampling rate, or vector of sampling rates with the same number of +% sr : sampling rate, or vector of sampling rates with the same number of % elements as multi % * sr_ratio : If data was downsampled wrt onset definition, ratio of new_sr/old_sr; or % vector of sampling rate ratios. Otherwise, should be 1. @@ -23,7 +23,7 @@ sr = repmat(sr, numel(multi), 1); end if numel(sr) ~= numel(multi) || numel(session_duration) ~= numel(multi) - warning('ID:invalid_input', 'No event definition provided.'); return; + warning('ID:invalid_input', 'Number of sessions do not match.'); return; end if ~isempty(multi) for iSn = 1:numel(multi) @@ -40,8 +40,8 @@ events = varargin{1}; end % markers are timestamps in seconds - onsets{n}{iSn} = pspm_time2index(multi(iSn).onsets{n}, sr(iSn), session_duration, 0, events{iSn}); - durations{n}{iSn} = pspm_time2index(multi(iSn).durations{n}, sr(iSn), session_duration, 1); + onsets{n}{iSn} = pspm_time2index(multi(iSn).onsets{n}, sr(iSn), session_duration(iSn), 0, events{iSn}); + durations{n}{iSn} = pspm_time2index(multi(iSn).durations{n}, sr(iSn), session_duration(iSn), 1); end end end From 7da117710d63dd13a8679dd7aa35a51e87e109aa Mon Sep 17 00:00:00 2001 From: Dominik Bach Date: Thu, 29 Aug 2024 12:00:22 +0200 Subject: [PATCH 2/4] improve test syntax --- test/pspm_extract_segments_test.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/pspm_extract_segments_test.m b/test/pspm_extract_segments_test.m index 55683a038..bd7cfe8fa 100644 --- a/test/pspm_extract_segments_test.m +++ b/test/pspm_extract_segments_test.m @@ -186,8 +186,9 @@ function test_auto_mode_glm_with_markers(this) import matlab.unittest.constraints.IsEqualTo import matlab.unittest.constraints.RelativeTolerance rehash - load(['ImportTestData' filesep 'fitted_models' filesep 'glm_scr_cond_marker.mat'], 'glm'); - load(['ImportTestData' filesep 'fitted_models' filesep 'glm_orig_data.mat'], 'data'); + pspm_path = fileparts(which('pspm')); + load(fullfile('ImportTestData', 'fitted_models', 'glm_scr_cond_marker.mat'), 'glm'); + load(fullfile('ImportTestData', 'fitted_models', 'glm_orig_data.mat'), 'data'); if ~isfield(glm.input, 'channel') && isfield(glm.input, 'chan') glm.input.channel = glm.input.chan; glm.input = rmfield(glm.input,'chan'); % rename the field channel to chan From 460c7679084f4957099acd28d32edcd7491f7aef Mon Sep 17 00:00:00 2001 From: Dominik Bach Date: Thu, 29 Aug 2024 12:43:52 +0200 Subject: [PATCH 3/4] fix test and fix typo in pspm_extract_segments --- src/pspm_extract_segments.m | 2 +- test/pspm_extract_segments_test.m | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pspm_extract_segments.m b/src/pspm_extract_segments.m index f41e15f85..bd8ae4bc9 100644 --- a/src/pspm_extract_segments.m +++ b/src/pspm_extract_segments.m @@ -187,7 +187,7 @@ if strcmpi(method, 'model') && strcmpi(data.modeltype, 'dcm') % DCM has no condition information - onsets = cellfun(@(x, y) pspm_time2index(x, sr , y), ... + onsets{1} = cellfun(@(x, y) pspm_time2index(x, sr , y), ... data.input.trlstart(:), ... num2cell(session_duration), ... 'UniformOutput', false); diff --git a/test/pspm_extract_segments_test.m b/test/pspm_extract_segments_test.m index bd7cfe8fa..2a4d7356b 100644 --- a/test/pspm_extract_segments_test.m +++ b/test/pspm_extract_segments_test.m @@ -185,8 +185,6 @@ function test_manual_length(this,nr_trial,nan_ratio) function test_auto_mode_glm_with_markers(this) import matlab.unittest.constraints.IsEqualTo import matlab.unittest.constraints.RelativeTolerance - rehash - pspm_path = fileparts(which('pspm')); load(fullfile('ImportTestData', 'fitted_models', 'glm_scr_cond_marker.mat'), 'glm'); load(fullfile('ImportTestData', 'fitted_models', 'glm_orig_data.mat'), 'data'); if ~isfield(glm.input, 'channel') && isfield(glm.input, 'chan') @@ -222,13 +220,13 @@ function test_auto_mode_glm_with_markers(this) this.verifyThat(nanmean(seg{3}.data, 1), IsEqualTo(seg{3}.mean, 'Within', RelativeTolerance(1e-10))); this.verifyThat(nanstd(seg{3}.data, 0, 1), IsEqualTo(seg{3}.std, 'Within', RelativeTolerance(1e-10))); % compute statistics from scratch - for i = 1:numel(glm.timing.multi.durations) + for i = 1:numel(glm.timing.multi.onsets) all_vecs = []; seg_len = this.options.length * sr; - onset_i = glm.timing.multi.onsets{i}; + onsets_i = pspm_time2index(marker(glm.timing.multi.onsets{i}), sr); for j = 1:numel(onset_i) - onset = round(onset_i(j) * sr) + 1; - all_vecs = [all_vecs, input_data(onset : onset + seg_len - 1)]; + onset = onsets_i(j); + all_vecs = [all_vecs, input_data(onset : onset + seg_len - 1)]; end all_vecs = all_vecs'; expected_mean = nanmean(all_vecs, 1); From 45ab6e71a128eea99277d5eb856a77da420fa7ef Mon Sep 17 00:00:00 2001 From: Dominik Bach Date: Thu, 29 Aug 2024 13:16:48 +0200 Subject: [PATCH 4/4] fix typo --- test/pspm_extract_segments_test.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pspm_extract_segments_test.m b/test/pspm_extract_segments_test.m index 2a4d7356b..233c5c19c 100644 --- a/test/pspm_extract_segments_test.m +++ b/test/pspm_extract_segments_test.m @@ -224,7 +224,7 @@ function test_auto_mode_glm_with_markers(this) all_vecs = []; seg_len = this.options.length * sr; onsets_i = pspm_time2index(marker(glm.timing.multi.onsets{i}), sr); - for j = 1:numel(onset_i) + for j = 1:numel(onsets_i) onset = onsets_i(j); all_vecs = [all_vecs, input_data(onset : onset + seg_len - 1)]; end