Skip to content

Commit

Permalink
Merge branch 'develop' into nan-checking-for-pupil
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikbach authored Aug 11, 2023
2 parents 367995f + 0d635bf commit 7239e5c
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 234 deletions.
18 changes: 9 additions & 9 deletions src/backroom/pspm_find_data_epochs.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@
% of a channel. It then writes it to a file depending on the input and
% returns the location of that file.
%
% FORMAT:
% FORMAT:
% [sts, epochfile] = pspm_find_data_epochs(datafile, chan_id, options)
%
%
% ARGUMENTS:
% datafile: File which contains the corresponding channel to
% look for epochs.
% chan_id: Number or channeltype of the the channel. If
% multiple channels match the specified channeltype
% chan_id: Number or chantype of the the channel. If
% multiple channels match the specified chantype
% only the first found channel will be used.
% options:
% options:
% output_file: Name and path to the output file. Default is the
% same as datafile but prepended with an 'e'.
% overwrite: Overwrite output file if it already exists. Default
% is 0.
%
%
% OUTPUT:
% sts: Return status of the function. If equals 1 no
% error or warnings were produced.
% epochfile: File where the epochs have been saved to.
% epochfile: File where the epochs have been saved to.
%__________________________________________________________________________
% PsPM 3.1
% (C) 2016 Tobias Moser (University of Zurich)
Expand Down Expand Up @@ -90,7 +90,7 @@
if (isempty(stop) && ~isempty(start)) || (start(end) > stop(end))
stop = [stop; numel(logi)];
end;

if (isempty(start) && ~isempty(stop)) || (start(1) > stop(1))
start = [1; start];
end;
Expand All @@ -102,7 +102,7 @@
file_exist = exist(options.output_file, 'file');
write_ok = false;
if file_exist
if options.overwrite
if options.overwrite
write_ok = true;
elseif ~options.dont_ask_overwrite
if feature('ShowFigureWindows')
Expand Down
2 changes: 1 addition & 1 deletion src/pspm_cfg/pspm_cfg_data_convert.m
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
visangle2sps.help = {['Takes paires of channels with gaze data in spherical',...
' coordinates (i.e. visual angle) and computes scanpath speed',...
' (i.e. scalar distance per second). Saves result into a ',...
'new channel with channeltype ''sps'' (scanpath speed)']};
'new channel with chantype ''sps'' (scanpath speed)']};

%% Mode
mode = cfg_choice;
Expand Down
6 changes: 5 additions & 1 deletion src/pspm_cfg/pspm_cfg_run_sf.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@
if ~isempty(job.fresp)
options.fresp = job.fresp;
end

if ~isempty(job.missing)
if ischar(job.missing.missingdata)
options.missing = job.missing;
end
end
options.dispwin = job.dispwin;
options.dispsmallwin = job.dispsmallwin;

Expand Down
37 changes: 31 additions & 6 deletions src/pspm_cfg/pspm_cfg_sf.m
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
direction.labels = {'Unidirectional', 'Bidirectional'};
direction.values = {'uni', 'bi'};
direction.help = {['A unidirectional filter is applied twice in the forward direction. ' ...
'A bidirectional filter is applied once in the forward direction and once in the ' ...
'A "bidirectional" filter is applied once in the forward direction and once in the ' ...
'backward direction to correct the temporal shift due to filtering in forward direction.']};

filter_edit = cfg_branch;
Expand All @@ -165,6 +165,8 @@
filter.values = {filter_def, filter_edit};
filter.help = {'Specify how you want filter the SCR data.'};



%% Epochs
epochfile = cfg_files;
epochfile.name = 'Epoch File';
Expand All @@ -191,11 +193,11 @@
mrk_chan.name = 'Marker Channel';
mrk_chan.tag = 'mrk_chan';
mrk_chan.strtype = 'i';
mrk_chan.val = {0};
mrk_chan.val = {1};
mrk_chan.num = [1 1];
mrk_chan.help = {['Indicate the marker channel. By default the first marker channel is ' ...
'assumed to contain the relevant markers.'], ['Markers are only used if you have ' ...
'specified the time units as markers.']};
'specified the time units as "markers".']};


%% Timeunits
Expand Down Expand Up @@ -228,8 +230,8 @@
timeunits.tag = 'timeunits';
timeunits.values = {seconds, samples, markers, whole};
timeunits.help = {['Indicate the time units on which the specification of the conditions will be based. ' ...
'Time units can be specified in seconds, number of markers, or number of data samples. Time units ' ...
'refer to the beginning of the data file and not to the beginning of the original recordings e. g. if ' ...
'Time units can be specified in "seconds", number of "markers", or number of data "samples". Time units ' ...
'refer to the beginning of the data file and not to the beginning of the original recordings e.g. if ' ...
'data were trimmed.']};

%% Channel nr
Expand Down Expand Up @@ -292,6 +294,29 @@
fresp.help = {'Frequency of responses to model.'};
fresp.hidden = true;



missingepoch_none = cfg_const;
missingepoch_none.name = 'Not added';
missingepoch_none.tag = 'missingdata';
missingepoch_none.val = {0};
missingepoch_none.help = {'Do not add missing epochs.'};

missingepoch_file = cfg_files;
missingepoch_file.name = 'Missing epoch file';
missingepoch_file.tag = 'missingdata';
missingepoch_file.num = [1 1];
missingepoch_file.filter = '.*\.(mat|MAT)$';
missingepoch_file.help = {['Missing (e.g. artefact) epochs in the data file, where ',...
'data must always be specified in seconds.']};

missing = cfg_choice;
missing.name = 'Missing Epoch Settings';
missing.tag = 'missing';
missing.val = {missingepoch_none};
missing.values = {missingepoch_none, missingepoch_file};
missing.help = {'Specify whether you would like to include missing epochs.'};

% Show figures
dispwin = cfg_menu;
dispwin.name = 'Display Progress Window';
Expand All @@ -314,7 +339,7 @@
sf = cfg_exbranch;
sf.name = 'SF';
sf.tag = 'sf';
sf.val = {datafile, modelfile, outdir, method, timeunits, filter, chan, overwrite, threshold, theta, fresp, dispwin, dispsmallwin};
sf.val = {datafile, modelfile, outdir, method, timeunits, filter, chan, overwrite, threshold, missing, theta, fresp, dispwin, dispsmallwin};
sf.prog = @pspm_cfg_run_sf;
sf.vout = @pspm_cfg_vout_sf;
sf.help = {['This suite of models is designed for analysing spontaneous fluctuations (SF) in skin conductance ' ...
Expand Down
2 changes: 1 addition & 1 deletion src/pspm_dcm.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
% │ trial. If this is not the case, include `dummy` events with
% │ negative onsets.
% │ ▶︎ Optional
% ├───.missing: Allows to specify missing (e. g. artefact) epochs in the
% ├───.missing: 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.
Expand Down
17 changes: 10 additions & 7 deletions src/pspm_dcm_inv.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
% │ transformed back into raw data units.
% ├───.flexevents: flexible events to adjust amplitude priors
% ├────.fixevents: fixed events to adjust amplitude priors
% ├─.missing_data: missing epoch data, originally loaded as model.missing
% │ from pspm_dcm, but calculated into .missing_data (created
% │ in pspm_dcm and then transferred to pspm_dcm_inv.
% └──.constrained: [optional]
% constrained model for flexible responses which have
% have fixed dispersion (0.3 s SD) but flexible latency
Expand Down Expand Up @@ -64,7 +67,6 @@
% │ [numeric, default: 0.1, unit: second]
% │ minimum dispersion (standard deviation) for flexible
% │ responses.
% ├──────.missing: data points to be disregarded by inversion.
% │ ▶︎ display
% ├──────.dispwin: [bool, default as 1]
% │ display progress window.
Expand Down Expand Up @@ -126,9 +128,9 @@
try model.meanSCR; catch, model.meanSCR = 0; end
% These parameters were set with default fallback values but will be
% determined later by processing (same to pspm_dcm)
%try model.fixevents; catch, warning('model.fixevents not defined.'); end
%try model.flexevents; catch, warning('model.flexevents not defined.'); end
%try model.missing_data; catch, warning('model.missing_data not defined.'); end
% try model.fixevents; catch, warning('model.fixevents not defined.'); end
% try model.flexevents; catch, warning('model.flexevents not defined.'); end
% try model.missing_data; catch, warning('model.missing_data not defined.'); end
% These parameters do not need to have a default value and will be
% determined later (same to pspm_dcm)

Expand Down Expand Up @@ -551,9 +553,10 @@
priors.SigmaX0 = zeros(7);
priors.muX0 = zeros(7, 1);
if trl == 1
priors.muX0(1) = mean(y(1:3));%) - min(y);
priors.muX0(2) = mean(diff(y(1:3)));
priors.muX0(3) = diff(diff(y(1:3)));
y_non_nan = y(~isnan(y));
priors.muX0(1) = mean(y_non_nan(1:3));%) - min(y);
priors.muX0(2) = mean(diff(y_non_nan(1:3)));
priors.muX0(3) = diff(diff(y_non_nan(1:3)));
priors.muX0(7) = 0;%min(y);
for n = [1:3 7]
priors.SigmaX0(n, n) = 1e-2;
Expand Down
6 changes: 3 additions & 3 deletions src/pspm_guide.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function varargout = pspm_guide(varargin)
% â—? Description
% Description
% pspm_guide handles the main GUI for PsPM
% â—? Developer's Guide
% Developer's Guide
% * Template
% function varargout = FunctionName(hObject, eventdata, handles, varargin)
% varargout cell array for returning output args (see VARARGOUT);
Expand All @@ -15,7 +15,7 @@
% contents{get(hObject,'Value')} returns selected item from the list
% * Hint
% popupmenu controls usually have a white background on Windows.
% â—? Copyright
% Copyright
% Introduced in PsPM 1.0 and terminated in PsPM 6.1.
% Written by Dominik R Bach (Wellcome Centre for Human Neuroimaging) in 2008-2021
% Lastly updated in PsPM 6.1 by Teddy Chao (UCL) in 2022
Expand Down
111 changes: 111 additions & 0 deletions src/pspm_interp1.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
function Y = pspm_interp1(varargin)
% ● Description
% pspm_interp1 is a shared PsPM function for interpolating data with NaNs
% based on the reference of missing epochs and first order interpolation.
% ● Format
% Y = pspm_interp1(varargin)
% ● Arguments
% X: data that contains NaNs to be interpolated
% index_missing: index of missing epochs with the same size of X in binary
% values. 1 if NaNs, 0 if non-NaNs.
% Y: processed data
% ● History
% Introduced in PsPM 6.1
% Written in 2023 by Teddy Chao (UCL)

%% 1 Load inputs
switch nargin
case 1
X = varargin{1};
index_missing = zeros(size(X));
case 2
X = varargin{1};
index_missing = varargin{2};
otherwise
warning('ID:invalid_input','pspm_interp1 accepts up to two arguments');
end
%% 2 Check inputs
switch sum(~isnan(X))
case 0
% if there are no non-nans, do not process any interpolation, give a
% warning and return
warning('ID:invalid_input',...
'Input data contains only NaNs thus cannot be interpolated.')
Y = X;
return
case 1
% if there are only 1 non-nan, do not process any interpolation,
% give a warning and explain the reason
warning('ID:invalid_input',...
'Input data contains only 1 non-NaN thus cannot be interpolated.')
Y = X;
return
otherwise
% if there are less than 10^ non-nan, still perform interpolation,
% however give a warning and explain the reason
non_nan_percentage = sum(~isnan(X))/length(X);
if non_nan_percentage<0.1
warning('ID:invalid_input',...
'Input data contains less than 10% non-NaN. Interpolation can ',...
'still be performed but results could be inaccurate.')
end
end
%% 3 find nan head and tail
X_nan_head = 0;
X_nan_tail = 0;
X_nan_head_range = [];
X_nan_tail_range = [];
X_nan_head_interp = [];
X_nan_tail_interp = [];
index_non_nan_full = 1:length(X);
index_non_nan_full = index_non_nan_full(~isnan(X));
if index_non_nan_full(1) > 1
X_nan_head = 1;
X_nan_head_range = 1:(index_non_nan_full(1)-1);
end
if index_non_nan_full(end) < length(X)
X_nan_tail = 1;
X_nan_tail_range = (index_non_nan_full(end)+1):length(X);
end
X_body = X(index_non_nan_full(1):index_non_nan_full(end));
% processing body
index = 1:length(X_body);
index_nan = index(isnan(X_body) | index_missing(index_non_nan_full(1):index_non_nan_full(end))) ;
index_non_nan = 1 - index_nan;
if ~isempty(index_nan)
X_body_interp = interp1(index_non_nan,X_body(index_non_nan),index_nan);
else
X_body_interp = X_body;
end
% interpolate head
if X_nan_head
X_nan_head_interp = interp1(...
(1:length(X_body_interp))+length(X_nan_head_range),...
X_body_interp,...
X_nan_head_range,'linear','extrap');
end
% interpolate tail
if X_nan_tail
X_nan_tail_interp = interp1(...
(1:length(X_body_interp))+length(X_nan_head_range),...
X_body_interp,...
X_nan_tail_range,'linear','extrap');
end
if iscolumn(X_body_interp)
if ~iscolumn(X_nan_head_interp)
X_nan_head_interp = transpose(X_nan_head_interp);
end
if ~iscolumn(X_nan_tail_interp)
X_nan_tail_interp = transpose(X_nan_tail_interp);
end
Y = [X_nan_head_interp; X_body_interp; X_nan_tail_interp];
else
if iscolumn(X_nan_head_interp)
X_nan_head_interp = transpose(X_nan_head_interp);
end
if iscolumn(X_nan_tail_interp)
X_nan_tail_interp = transpose(X_nan_tail_interp);
end
Y = [X_nan_head_interp, X_body_interp, X_nan_tail_interp];
end
return
Loading

0 comments on commit 7239e5c

Please sign in to comment.