Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue 484 --- pspm_sf #483

Merged
merged 32 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
868ee9d
update missthreshold for sf
teddychao May 15, 2023
f3b5fc5
attempting to resolve issue
teddychao May 29, 2023
c0a4a12
update to use non-zero y
Jun 5, 2023
c1ea663
Update pspm_sf_dcm.m
teddychao Jun 5, 2023
f340598
Merge branch 'develop' into sf_dcm_nan_issue
teddychao Jun 5, 2023
0f78326
Update pspm_dcm_inv.m
teddychao Jun 5, 2023
b677236
Update pspm_sf_dcm.m
teddychao Jun 12, 2023
3d7df0b
Merge branch 'develop' into sf_dcm_nan_issue
teddychao Jun 22, 2023
9da282c
Update pspm_sf_dcm.m
teddychao Jun 22, 2023
31e5245
Merge branch '491-generalise-missing-epochs-allocation' into sf_dcm_n…
Jun 25, 2023
4200b2a
Update pspm_sf_dcm.m
Jun 25, 2023
4fde373
update SF
Jun 25, 2023
123f3b4
Merge branch '491-generalise-missing-epochs-allocation' into sf_dcm_n…
Jun 26, 2023
0702106
Update pspm_sf.m
Jun 26, 2023
3b7f8fe
load missing to sf_dcm
teddychao Jun 26, 2023
4260862
Update pspm_sf.m
teddychao Jun 26, 2023
7537b6d
Update pspm_sf.m
teddychao Jun 26, 2023
c0becc0
Merge branch 'develop' into sf_dcm_nan_issue
teddychao Jul 3, 2023
45da6dd
Merge branch 'develop' into sf_dcm_nan_issue
teddychao Jul 3, 2023
52d3f99
update sf series functions
teddychao Jul 17, 2023
6a4983b
Merge branch 'develop' into SF_marker_issue
teddychao Jul 17, 2023
86b0731
Merge branch 'develop' into sf_dcm_nan_issue
teddychao Jul 17, 2023
eb1e6e2
update sf marker definition
teddychao Jul 17, 2023
bbcd442
Merge branch 'SF_marker_issue' of https://github.com/bachlab/PsPM int…
teddychao Jul 17, 2023
e35e467
Update pspm_sf.m
Jul 24, 2023
9b538c0
Update pspm_sf_mp.m
Jul 24, 2023
449c63d
Merge branch 'SF_marker_issue' into sf_dcm_nan_issue
Jul 24, 2023
0ef3fdc
Update pspm_sf.m
Jul 24, 2023
e1782e0
Update pspm_sf.m
Jul 24, 2023
3cfa649
Update pspm_sf.m
teddychao Jul 24, 2023
4938da1
Merge branch 'develop' into sf_dcm_nan_issue
dominikbach Aug 7, 2023
b656762
bugfix
Aug 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/pspm_cfg/pspm_cfg_run_sf.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
options.fresp = job.fresp;
end
if ~isempty(job.missing)
options.missing = job.missing;
if ischar(job.missing.missingdata)
options.missing = job.missing;
end
end
options.dispwin = job.dispwin;
options.dispsmallwin = job.dispsmallwin;
Expand Down
31 changes: 24 additions & 7 deletions src/pspm_cfg/pspm_cfg_sf.m
Original file line number Diff line number Diff line change
Expand Up @@ -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,7 +193,7 @@
mrk_chan.name = 'Marker Channel';
mrk_chan.tag = 'mrk_chan';
mrk_chan.strtype = 'i';
mrk_chan.val = {0};
mrk_chan.val = {1};
dominikbach marked this conversation as resolved.
Show resolved Hide resolved
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 ' ...
Expand Down Expand Up @@ -292,14 +294,29 @@
fresp.help = {'Frequency of responses to model.'};
fresp.hidden = true;

missing = cfg_files;
missing.name = 'Missing epoch file';
missing.tag = 'missingfile';
missing.num = [1 1];
missing.filter = '.*\.(mat|MAT)$';
missing.help = {['Missing (e.g. artefact) epochs in the data file, where ',...


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 Down
7 changes: 4 additions & 3 deletions src/pspm_dcm_inv.m
Original file line number Diff line number Diff line change
Expand Up @@ -553,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
3 changes: 2 additions & 1 deletion src/pspm_options.m
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@
options = autofill(options,'dispwin', 1, 0 );
options = autofill(options,'fresp', 0.5, '>=', 0 );
options = autofill(options,'marker_chan_num', 1, '*Int*Char' );
options = autofill(options,'missingthresh', 2, '>', 0 );
options = autofill(options,'overwrite', 1, 0 );
options = autofill(options,'threshold', 0.1, '>', 0 );
options = autofill(options,'missingthresh', 2, '>', 0 );
Expand Down Expand Up @@ -579,7 +580,7 @@
if contains(optional_value, '*Int')
flag_is_allowed_value = flag_is_allowed_value || ...
all([isnumeric(options.(field_name)), ...
options.(field_name)>0, ...
options.(field_name)>=0, ...
mod(options.(field_name), 1)==0]);
end
if contains(optional_value, '*Struct')
Expand Down
2 changes: 2 additions & 0 deletions src/pspm_overwrite.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,7 @@
case 2
varargout{1} = sts;
varargout{2} = overwrite_final;
otherwise
varargout{1} = overwrite_final;
end
return
87 changes: 40 additions & 47 deletions src/pspm_sf.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
% ┌─────────options
% ├──────.overwrite: [logical] [default: determined by pspm_overwrite]
% │ Define whether to overwrite existing output files or not.
% ├.marker_chan_num: [integer]
% ├.marker_chan_num: [integer]
% │ marker channel number
% │ if undefined or 0, first marker channel is used.
% │ * Additional options for individual methods:
Expand Down Expand Up @@ -77,7 +77,7 @@
outfile = [];
sts = -1;
%% 2 Check input
% 2.1 Check missing input
% 2.1 Check missing input --
if nargin<1
warning('ID:invalid_input', 'Nothing to do.'); return;
elseif nargin<2
Expand All @@ -92,7 +92,7 @@
elseif ~isfield(model, 'timing') && ~strcmpi(model.timeunits, 'file')
warning('ID:invalid_input', 'No epochs specified.'); return;
end
% 2.2 Check faulty input
% 2.2 Check faulty input --
if ~ischar(model.datafile) && ~iscell(model.datafile)
warning('ID:invalid_input', 'Input data must be a cell or string.'); return;
elseif ~ischar(model.modelfile) && ~iscell(model.modelfile)
Expand All @@ -115,15 +115,15 @@
if ischar(model.modelfile)
model.modelfile = {model.modelfile};
end
% 2.4 Check number of files
% 2.4 Check number of files --
if ~strcmpi(model.timeunits, 'whole') && numel(model.datafile) ~= numel(model.timing)
warning('ID:number_of_elements_dont_match',...
'Number of data files and epoch definitions does not match.'); return;
elseif numel(model.datafile) ~= numel(model.modelfile)
warning('ID:number_of_elements_dont_match',...
'Number of data files and model files does not match.'); return;
end
% 2.5 check methods
% 2.5 check methods --
if ~isfield(model, 'method')
model.method = {'dcm'};
elseif ischar(model.method)
Expand Down Expand Up @@ -162,31 +162,31 @@
end
end
end
% 2.6 Check timing
% 2.6 Check timing --
if strcmpi(model.timeunits, 'whole')
epochs = repmat({[1 1]}, numel(model.datafile), 1);
else
for iSn = 1:numel(model.datafile)
[sts_get_timing, epochs{iSn}] = pspm_get_timing('epochs', model.timing{iSn}, model.timeunits);
for iFile = 1:numel(model.datafile)
[sts_get_timing, epochs{iFile}] = pspm_get_timing('epochs', model.timing{iFile}, model.timeunits);
if sts_get_timing == -1
warning('ID:invalid_input', 'Call of pspm_get_timing failed.');
return;
end
end
end
% 2.7 Check filter
% 2.7 Check filter --
if ~isfield(model, 'filter')
model.filter = settings.dcm{2}.filter;
elseif ~isfield(model.filter, 'down') || ~isnumeric(model.filter.down)
warning('ID:invalid_input', 'Filter structure needs a numeric ''down'' field.'); return;
end
% 2.8 Set options
% 2.8 Set options --
try model.channel; catch, model.channel = 'scr'; end
options = pspm_options(options, 'sf');
if options.invalid
return
end
% 2.9 Set missing epochs
% 2.9 Set missing epochs --
if ~isfield(model, 'missing')
model.missing = cell(numel(model.datafile), 1);
elseif ischar(model.missing) || isnumeric(model.missing)
Expand All @@ -197,14 +197,15 @@
return
end
%% 3 Get data
missing = cell(size(model.missing));
for iFile = 1:numel(model.datafile)
% 3.1 User output
% 3.1 User output --
fprintf('SF analysis: %s ...', model.datafile{iFile});
% 3.2 Check whether model file exists
% 3.2 Check whether model file exists --
if ~pspm_overwrite(model.modelfile, options)
return
end
% 3.3 get and filter data
% 3.3 get and filter data --
[sts_load_data, ~, data] = pspm_load_data(model.datafile{iFile}, model.channel);
if sts_load_data < 0, return; end
Y{1} = data{1}.data; sr(1) = data{1}.header.sr;
Expand All @@ -214,23 +215,23 @@
warning('ID:invalid_input', 'Call of pspm_prepdata failed.');
return;
end
% 3.4 Check data units
% 3.4 Check data units --
if ~strcmpi(data{1}.header.units, 'uS') && any(strcmpi('dcm', method))
fprintf(['\nYour data units are stored as %s, ',...
'and the method will apply an amplitude threshold in uS. ',...
'Please check your results.\n'], ...
data{1}.header.units);
end
% 3.5 Get missing epochs
% 3.5 Get missing epochs --
% 3.5.1 Load missing epochs --
if ~isempty(model.missing{iFile})
[~, missing{iFile}] = pspm_get_timing('epochs', ...
model.missing{iFile}, 'seconds');
% sort missing epochs
[~, missing{iFile}] = pspm_get_timing('epochs', model.missing{iFile}, 'seconds');
% 3.5.2 sort missing epochs --
if size(missing{iFile}, 1) > 0
[~, sortindx] = sort(missing{iFile}(:, 1));
missing{iFile} = missing{iFile}(sortindx,:);
% check for overlap and merge
for k = 2:size(missing{iSn}, 1)
for k = 2:size(missing{iFile}, 1)
if missing{iFile}(k, 1) <= missing{iFile}(k - 1, 2)
missing{iFile}(k, 1) = missing{iFile}(k - 1, 1);
missing{iFile}(k - 1, :) = [];
Expand All @@ -240,33 +241,16 @@
else
missing{iFile} = [];
end
% 3.6 Get marker data
% 3.6 Get marker data --
if any(strcmp(model.timeunits, {'marker', 'markers'}))
if options.marker_chan_num
[nsts, ~, ndata] = pspm_load_data(model.datafile, options.marker_chan_num);
if nsts == -1
warning('ID:invalid_input', 'Could not load data');
return;
end
if ~strcmp(ndata{1}.header.chantype, 'marker')
warning('ID:invalid_option', ...
['Channel %i is no marker channel. ',...
'The first marker channel in the file is used instead'],...
options.marker_chan_num);
[nsts, ~, ~] = pspm_load_data(model.datafile, 'marker');
if nsts == -1
warning('ID:invalid_input', 'Could not load data');
return;
end
end
[nsts, ~, ndata] = pspm_load_data(model.datafile{iFile}, options.marker_chan_num);
if nsts == -1; warning('ID:invalid_input', 'Could not load data'); return; end
else
[nsts, ~, ~] = pspm_load_data(model.datafile, 'marker');
if nsts == -1
warning('ID:invalid_input', 'Could not load data');
return;
end
[nsts, ~, ndata] = pspm_load_data(model.datafile{iFile}, 'marker');
if nsts == -1; warning('ID:invalid_input', 'Could not load data'); return; end
end
events = data{1}.data;
events = ndata{1}.data;
end
for iEpoch = 1:size(epochs{iFile}, 1)
if iEpoch > 1, fprintf('\n\t\t\t'); end
Expand All @@ -279,7 +263,7 @@
case 'samples'
win = round(epochs{iFile}(iEpoch, :) * sr(datatype(k)) / sr(1));
case 'markers'
win = round(events(epochs{1}(iEpoch, :)) * sr(datatype(k)));
win = round(events(epochs{iFile}(iEpoch, :)) * sr(datatype(k)));
case 'whole'
win = [1 numel(Y{datatype(k)})];
end
Expand All @@ -290,7 +274,7 @@
win(1) = max(win(1), 1);
win(2) = min(win(2), numel(Y{datatype(k)}));
end
% 3.6.1 collect information
% 3.6.1 collect information --
sf.model{k}(iEpoch).modeltype = method{k};
sf.model{k}(iEpoch).boundaries = squeeze(epochs{iFile}(iEpoch, :));
sf.model{k}(iEpoch).timeunits = model.timeunits;
Expand All @@ -299,8 +283,17 @@
%
escr = Y{datatype(k)}(win(1):win(end));
sf.model{k}(iEpoch).data = escr;
% 3.6.2 do the analysis and collect results
model_analysis = struct('scr', escr, 'sr', sr(datatype(k)));
if any(missing{iFile})
model.missing_data = zeros(size(escr));
teddychao marked this conversation as resolved.
Show resolved Hide resolved
missing_index = pspm_time2index(missing, sr(datatype(k)));
model.missing_data((missing_index{iFile}(:,1)+1):(missing_index{iFile}(:,2)+1)) = 1;
end
% 3.6.2 do the analysis and collect results --
if any(missing{iFile})
model_analysis = struct('scr', escr, 'sr', sr(datatype(k)), 'missing_data', model.missing_data);
else
model_analysis = struct('scr', escr, 'sr', sr(datatype(k)));
end
invrs = fhandle{k}(model_analysis, options);
if any(strcmpi(method{k}, {'dcm', 'mp'}))
sf.model{k}(iEpoch).inv = invrs;
Expand Down
6 changes: 5 additions & 1 deletion src/pspm_sf_auc.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function varargout = pspm_sf_auc(scr, sr, options)
function varargout = pspm_sf_auc(model, options)
% ● Description
% pspm_sf_auc returns the integral/area under the curve of an SCR time series
% ● Format
Expand Down Expand Up @@ -28,6 +28,10 @@
if nargin < 1
warning('No data specified'); return;
end;
try model.scr; catch, warning('Input data is not defined.'); return; end
try model.sr; catch, warning('Sample rate is not defined.'); return; end
scr = model.scr;
sr = model.sr;
scr = scr - min(scr);
auc = mean(scr);
sts = 1;
Expand Down
Loading