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

758 pspm_expand_epochs #786

Merged
merged 9 commits into from
Nov 19, 2024
Merged
147 changes: 147 additions & 0 deletions src/pspm_expand_epochs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
function [sts, ep_exp] = pspm_expand_epochs(epoches, expansion, options)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest using the varargin syntax.


% fn passt nicht zu missing epochs
% [sts, channel_index] = pspm_expand_epochs( {data_fn, channel}, expansion , options)
% [sts, output_file] = pspm_expand_epochs( missing_epochs_fn, expansion , options)
% [sts, expanded_epochs] = pspm_expand_epochs( missing_epochs, expansion , options) %
% options.mode = 'datafile'
% 'missing_ep_file'
% 'missing_ep'

global settings
if isempty(settings)
pspm_init;
end

sts = -1;

if nargin < 3
warning('ID:invalid_input', 'Not enough input arguments');
return;
end

switch options.mode
% missing epochs
case 'missing_ep'
% Directly expand the given epochs
[sts, ep_exp] = expand(epoches, expansion);
return;

% missing epoches file
case 'missing_ep_file'
% Load missing epochs from file
data = load(epoches); % Load the file without specifying a variable
dominikbach marked this conversation as resolved.
Show resolved Hide resolved

% Assuming the file contains a variable called 'epochs', access it
% Right name?
if isfield(data, 'epochs')
missing_epochs = data.epochs;
else
error('File does not contain variable ''epochs''.');
return;
end

if isempty(missing_epochs)
error('Failed to load missing epochs from file.');
return;
end

% Expand the loaded epochs
[sts, ep_exp] = expand(missing_epochs, expansion);
if sts == -1
error('Failed to expand epochs.');
end

% Save expanded missing epoch to a new file with 'e' prefix
[pathstr, name, ext] = fileparts(epoches);
output_file = fullfile(pathstr, ['e' name ext]);
save(output_file, 'ep_exp'); % should i save it as epoch???
disp(['Expanded epochs saved to: ', output_file]);

sts = 0;
return;


case 'datafile' % rename!!

% Load channel data
datafile = epoches{1};
channel = epoches{2};
[lsts, ~, data] = pspm_load_data(datafile, channel);
if lsts == -1
error('Failed to load data from file.');
end

channel_data = data{1};
sr = channel_data.header.sr;

% Find NaN indices
nan_indices = isnan(channel_data.data);

% Convert NaN indices to epochs
nan_epochs = pspm_logical2epochs(nan_indices, sr);

% Expand the epochs
[sts, ep_exp] = expand(nan_epochs, expansion);
if sts == -1
error('Failed to expand epochs.');
end

% Convert expanded epochs back to logical indices
expanded_indices = pspm_epochs2logical(ep_exp, numel(channel_data.data), sr);

% Set data to NaN at expanded indices
channel_data.data(expanded_indices) = NaN;

% Save the data back to the file
[sts, out] = pspm_write_channel(datafile, {channel_data}, 'replace'); % add to options 'newfile'?
varargout{2} = 23 % channel_data.data;
return;


otherwise
error('Unknown mode in options.');
return;
end

end


function [sts, ep_exp] = expand(ep, expansion)
% Helper function to expand epochs by the specified pre and post times
% and merge overlapping epochs.
% Also ensures that no epoch starts before time 0.

% Initialize status
sts = -1;

% Check if epochs matrix and expansion vector are valid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is needed for all modes of the function, I would check it in the beginning of the main function, before anything is loaded from file (faster and easier to read).

if isempty(ep) || numel(expansion) ~= 2
error('Invalid input to expand function.');
return;
end

% Expand epochs
pre = expansion(1);
post = expansion(2);
expanded_epochs_temp = [ep(:,1) - pre, ep(:,2) + post];

%
% Ensure that the start of any epoch is not negative
4gwe marked this conversation as resolved.
Show resolved Hide resolved
expanded_epochs_temp(expanded_epochs_temp(:,1) < 0, 1) = 0; % or <1???
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we should put this code into pspm_get_epochs (if the functionality does not exist there already), because it is needed in several functions.

then just call [sts, epochs] = pspm_get_timing('epochs', epochs)


% Merge overlapping epochs
ep_exp = expanded_epochs_temp(1, :); % Start with the first epoch
for i = 2:size(expanded_epochs_temp, 1)
% If the current epoch overlaps with the previous, merge them
if ep_exp(end, 2) >= expanded_epochs_temp(i, 1)
ep_exp(end, 2) = max(ep_exp(end, 2), expanded_epochs_temp(i, 2));
else
% Otherwise, add the current epoch as a new row
ep_exp = [ep_exp; expanded_epochs_temp(i, :)];
end
end

% Success
sts = 0;
end
27 changes: 25 additions & 2 deletions src/pspm_remove_epochs.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
% be in seconds. This parameter is passed to pspm_get_timing().
% * timeunits: timeunits of the epochfile.
% ┌───options
% └─.channel_action:
% └─.channel_action: [pre, post]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the channel action changed?

% ['add'/'replace'] Defines whether new channels should be added or
% corresponding channels should be replaced. The default value is 'add'.
% .expand_epochs:
% Expand epochs by 0.5 seconds before and after
% ● Output
% * channel_index: index of channel containing the processed data
% ● History
% Introduced in PsPM 4.0
% Written in 2016 by Tobias Moser (University of Zurich)
% Maintained in 2024 by Bernhard Agoué von Raußendorf

global settings
if isempty(settings)
Expand All @@ -36,7 +39,7 @@
elseif nargin < 4
options = struct();
end
options = pspm_options(options, 'remove_epochs');
options = pspm_options(options, 'remove_epochs'); % change!!! [0,0]
if options.invalid
return
end
Expand All @@ -51,6 +54,26 @@
return;
end



expansion = options.expand_epochs;

if numel(expansion) ~= 2
error('Expansion must be a 2-element vector [pre, post].');
end
% Expand the epochs

[sts, ep_exp] = pspm_expand_epochs(ep, expansion, 'missing_ep');
if psts == -1
return;
end







n_ep = size(ep, 1);
n_data = numel(data);
for i_data = 1:n_data
Expand Down
Loading