Skip to content

Commit

Permalink
Merge branch 'develop' into manual_updates
Browse files Browse the repository at this point in the history
  • Loading branch information
teddychao authored Jan 29, 2025
2 parents 87bd1b9 + 5bd7ff9 commit 9657758
Show file tree
Hide file tree
Showing 43 changed files with 869 additions and 448 deletions.
20 changes: 11 additions & 9 deletions src/g_SCR.m
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
function [gx,dgdx,dgdPhi] = g_SCR(Xt,Phi,ut,inG)
% ● Description
% TBA.
% ● Description
% This is the SCR observation function required by the VBA toolbox. It
% adds the three generative processes (phasic SCR, SF, SCL) modelled in
% f_SCR.
% ● Arguments
% Xt:
% Phi:
% ut:
% inG:
% Xt: a 7-element vector
% Phi: input required by VBA, ignored
% ut: input required by VBA, ignored
% inG: input required by VBA, ignored
% ● History
% Introduced in PsPM 3.0
% Written in 2008-2015 by Dominik R Bach (Wellcome Trust Centre for Neuroimaging)

global settings;
if isempty(settings), pspm_init; end;
if isempty(settings), pspm_init; end
gx = Xt(1) + Xt(4) + Xt(7);
dgdx = zeros(size(Xt,1),1);
dgdx([1;4;7]) = 1;
dgdPhi = [];
if any(isnan(gx)|isinf(gx)), keyboard; end;
if any(isnan(dgdx)|isinf(dgdx)), keyboard; end;
if any(isnan(gx)|isinf(gx)), keyboard; end
if any(isnan(dgdx)|isinf(dgdx)), keyboard; end
4 changes: 2 additions & 2 deletions src/pspm_cfg/pspm_cfg_pupil_preprocess.m
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@
% Residual filter for lowpass cut-off
ResdFiltLPCF = cfg_entry;
ResdFiltLPCF.name = 'Butterworth cutoff frequency (Hz)';
ResdFiltLPCF.tag = 'residualsFilter_interpFs';
ResdFiltLPCF.tag = 'residualsFilter_lowpassCF';
ResdFiltLPCF.num = [1 1];
ResdFiltLPCF.val = {100};
ResdFiltLPCF.val = {16};%
ResdFiltLPCF.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.residualsFilter_lowpassCF');

% Keep filter data
Expand Down
2 changes: 1 addition & 1 deletion src/pspm_cfg/pspm_cfg_selector_channel.m
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@
function out = pupil_chan(menu_set, menu_default)

labels = {'Combined pupil channel', 'Both pupil channels', 'Left pupil', 'Right pupil', 'Default', 'None'};
values = {'pupil_c', 'both', 'pupil_l', 'pupil_r', 'pupil', ''};
values = {'pupil_c', 'both', 'pupil_l', 'pupil_r', 'pupil', 'none'};

out = cfg_menu;
out.name = 'Channel specification';
Expand Down
72 changes: 39 additions & 33 deletions src/pspm_check_model.m
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
function model = pspm_check_model(model, modeltype)
function [model, options] = pspm_check_model(model, options, modeltype)
% ● Definition
% pspm_check_model automatically determine the fields of the struct model
% for the corresponding function.
% for the corresponding function. It also checks the options structure
% and uses it to determine whether overwriting of the model file is
% allowed
% ● Format
% model = pspm_check_model(model, modeltype)
% ● Arguments
% ┌─────model
% ├─.datafile : Values (any of the following).
% │ A file name (single session);
% │ A cell array of file names (multiple sessions).
% ├.modelfile : A file name for the model output, can be any of the following.
% │ [for GLM, DCM, TAM] A file name.
% │ [for SF] A file name (single data file) or a cell array of file names
% │ (multiple data files).
% │ A cell array of file names (multiple sessions, not allowed for SF).
% ├.modelfile : A file name for the model output.
% ├.timeunits : A string.
% │ [for GLM, TAM] can be either 'seconds', 'samples', 'markers', or
% │ 'markervalues'.
Expand Down Expand Up @@ -56,7 +55,7 @@
% │ or cell array of any of these, for multiple files.
% ├──.missing : [optional] allows to specify missing (e. g. artefact) epochs in the
% │ data file. See pspm_get_timing for epoch definition; specify a cell
% │ array for multiple input files. This must always be specified in SECONDS.
% │ array for multiple input files (not allowed for SF). This must always be specified in SECONDS.
% │ Default: no missing values
% ├──.channel : [optional] channel number (or, for GLM, channel type). If a channel type
% │ is specified the LAST channel matching the given type will be used.
Expand Down Expand Up @@ -118,27 +117,29 @@
% └────method : [optional, SF (modeltype) only] [string/cell_array]
% [string] either 'auc', 'scl', 'dcm' (default), or 'mp'.
% [cell_array] a cell array of methods mentioned above.
% options: see calling functions and pspm_options
% ● History
% Introduced in PsPM 6.1.1
% Written in 2023 by Dominik Bach (UCL and Bonn)

%% 0. Initialise
%% 0. Initialise & check options
global settings
if isempty(settings)
pspm_init;
end

%% 1. General checks ------------------------------------------------------
if ~isstruct(model)
warning('ID:invalid_input', 'Model must be a struct.');
if ~isstruct(model) || isempty(model)
warning('ID:invalid_input', 'Model must be a non-empty struct.');
model = struct('invalid', 1);
return
else
model.invalid = 1;
if isempty(model)
warning('ID:invalid_input', 'Model is empty.');
model.invalid = 1;
end

options = pspm_options(options, modeltype);
if options.invalid
return
end
end

%% 2. Reject missing mandatory fields common to all models -----------------
Expand All @@ -154,10 +155,8 @@
% 3. Reject wrong type of mandatory fields --------------------------------
if ~iscell(model.datafile) && ~ischar(model.datafile)
warning('ID:invalid_input', 'Input data must be a cell or string.'); return;
elseif ~ischar(model.modelfile) && ~strcmpi (modeltype, 'sf')
elseif ~ischar(model.modelfile)
warning('ID:invalid_input', 'Output model must be a string.'); return;
elseif ischar(model.modelfile) && strcmpi (modeltype, 'sf')
model.modelfile = {model.modelfile};
end

% NOTE we need to separate the case of DCM timing being
Expand All @@ -168,17 +167,13 @@
%% 3. Fill missing fields common to all models, and accept only allowed values
if ~isfield(model, 'timing')
model.timing = cell(nFile, 1);
else
if ~isempty(model.timing)
if ~iscell(model.timing) || ...
(strcmpi(modeltype, 'dcm') && ~iscell(model.timing{1}) && ~ischar(model.timing{1}))
% for DCM, model.timing is either a file name or a cell array of
% events, or a cell array of file names or cell arrays, so we need to
% take care of cases where model.timing is a cell array but not a cell
% array of cell arrays or a cell array of char
model.timing = {model.timing};
end
end
elseif ~iscell(model.timing) || ...
(strcmpi(modeltype, 'dcm') && ~isempty(model.timing) && ~iscell(model.timing{1}) && ~ischar(model.timing{1}))
% for DCM, model.timing is either a file name or a cell array of
% events, or a cell array of file names or cell arrays, so we need to
% take care of cases where model.timing is a cell array but not a cell
% array of cell arrays or a cell array of char
model.timing = {model.timing};
end
if ~isfield(model, 'missing')
model.missing = cell(nFile, 1);
Expand All @@ -195,8 +190,20 @@
warning('ID:invalid_input', 'Normalisation must be specified as 0 or 1.'); return;
end

% make sure file extension is '.mat'
[pth, fn, ext] = fileparts(model.modelfile);
model.modelfile = fullfile(pth, [fn, '.mat']);

% check that overwriting output is allowed
options.overwrite = pspm_overwrite(model.modelfile, options);
if ~options.overwrite
warning('ID:invalid_input', 'Model file exists, and overwriting not allowed by user.');
return
end

%% 4. Check that session-related field entries have compatible size
if (nFile ~= numel(model.timing)) && ~(numel(model.timing) == 0 && isfield(model, 'nuisance'))
if (nFile ~= numel(model.timing)) && ...
~(numel(model.timing) == 0 && (isfield(model, 'nuisance') || (isfield(model, 'timeunits') && strcmpi(model.timeunits, 'whole'))))
warning('ID:number_of_elements_dont_match',...
'Session numbers of data files and event definitions do not match.');
return
Expand Down Expand Up @@ -335,12 +342,11 @@
warning('ID:invalid_input', 'No timeunits specified.'); return;
elseif ~ischar(model.timeunits) || ~ismember(model.timeunits, {'seconds', 'markers', 'samples','whole'})
warning('ID:invalid_input', 'Timeunits (%s) not recognised; only ''seconds'', ''markers'', ''samples'' and ''whole'' are supported', model.timeunits); return;
elseif nFile > 1
warning('ID:invalid_input', 'Only one data file allowed for SF.'); return;
elseif ~strcmpi(model.timeunits, 'whole') && sum(cellfun(@(f) isempty(f), model.timing)) > 0
warning('ID:number_of_elements_dont_match',...
'Number of data files and epoch definitions does not match.'); return;
elseif numel(model.modelfile) ~= nFile
warning('ID:number_of_elements_dont_match',...
'Number of data files and model files does not match.'); return;
end

% Check optional fields, set default values and reject invalid values
Expand Down
4 changes: 2 additions & 2 deletions src/pspm_convert_pixel2unit_core.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
% ● Description
% pspm_convert_pixel2unit_core converts gaze data from pixel to units.
% ● Format
% [sts, out_data, out_range] = pspm_convert_pixel2unit_core(data, screen_length)
% [out_data, out_range] = pspm_convert_pixel2unit_core(data, data_range, screen_length)
% ● Arguments
% * data: Original data in pixels. No checks are performed.
% * range: Original range in pixels.
% * data_range: Original range in pixels.
% * screen_length: Screen width for gaze_x data, or screen height for gaze_y data, in mm
% ● History
% Introduced in PsPM 4.0
Expand Down
12 changes: 3 additions & 9 deletions src/pspm_dcm.m
Original file line number Diff line number Diff line change
Expand Up @@ -203,18 +203,12 @@
if nargin < 1; errmsg = 'Nothing to do.'; warning('ID:invalid_input', errmsg); return
elseif nargin < 2; options = struct(); end

% 2.2 check model
model = pspm_check_model(model, 'dcm');
if model.invalid
% 2.2 check model and options
[model, options] = pspm_check_model(model, options, 'dcm');
if model.invalid || options.invalid
return
end

% 2.3 check options
options = pspm_options(options, 'dcm');
if options.invalid
return
end

% all the below should be re-factored into pspm_options -------------------
% numeric fields
num_fields = {'depth', 'sfpre', 'sfpost', 'sffreq', 'sclpre', ...
Expand Down
Loading

0 comments on commit 9657758

Please sign in to comment.