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
185 changes: 185 additions & 0 deletions src/pspm_expand_epochs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
function [sts, ep_exp] = pspm_expand_epochs(varargin)

% fn passt nicht zu missing epochs
% [sts, output_file] = pspm_expand_epochs( missing_epochs_fn, expansion , options)
% [sts, expanded_epochs] = pspm_expand_epochs( missing_epochs, expansion , options)
% [sts, channel_index] = pspm_expand_epochs( filename, channel, 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




if nargin == 3

expansion = varargin{2};
options = varargin{3};

switch options.mode
% missing epochs
case 'missing_ep'
% Directly expand the given epochs
epochs = varargin{1};
[ests, ep_exp] = expand(epochs, expansion);

if ests == -1
error("Failed to expand epochs.");
return;
end

sts = 1;
return;

% missing epoches file
case 'missing_ep_file'
% Load missing epochs from file
filename = varargin{1};

[lsts, epochs] = pspm_get_timing('file', filename);


if lsts == -1
error("Epoch could not be loaded");
return;
end

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

% Save expanded missing epoch to a new file with 'e' prefix
[pathstr, name, ext] = fileparts(filename);
output_file = fullfile(pathstr, ['e' name ext]);
save(output_file, 'ep_exp'); % should i save it as epoch???
4gwe marked this conversation as resolved.
Show resolved Hide resolved
disp(['Expanded epochs saved to: ', output_file]);

sts = 1;
return;
end
end

if nargin == 4 %&& options.mode == 'datafile' % rename!!

% Load channel data
filename = varargin{1};
channel = varargin{2};
expansion = varargin{3};
[lsts, ~, data] = pspm_load_data(filename, channel);
if lsts == -1
error('Failed to load data from file.');
return;
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
[ests, ep_exp] = expand(nan_epochs, expansion);
if ests == -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(logical(expanded_indices)) = NaN;

% Save the data back to the file
opt = struct();
[wsts, ~] = pspm_write_channel(filename, {channel_data}, 'replace',opt); % add to options 'newfile'?
% channel_data.data;

if wsts == -1
error('Failed to write the new channel.');
return
end

sts = 1;
return;


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


end



function [ests, 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 of expand
ests = -1;
ep_exp = [];

% 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

[ksts, expanded_epochs_temp] = pspm_get_timing('epochs',expanded_epochs_temp , 'seconds') ;
if ksts == -1
error('Offsets must be larger than onsets')
return
end

% If there is only one epoch, no need for merging
if size(expanded_epochs_temp, 1) == 1
ep_exp = expanded_epochs_temp;
ests = 1;
return;
end



% 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

ests = 1;
end
30 changes: 26 additions & 4 deletions src/pspm_remove_epochs.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
% be in seconds. This parameter is passed to pspm_get_timing().
% * timeunits: timeunits of the epochfile.
% ┌───options
% └─.channel_action:
% ['add'/'replace'] Defines whether new channels should be added or
% corresponding channels should be replaced. The default value is 'add'.
% └─.channel_action: ['add'/'replace'] Defines whether new channels should be added or
% corresponding channels should be replaced. The default value is 'add'.
% └─.expand_epochs: [pre, post]
%
% ● 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 +38,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 +53,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