From e4df355f2e5004d44010ae100e140a4d84233d77 Mon Sep 17 00:00:00 2001 From: Jan-Mathijs Schoffelen <1517611+schoffelen@users.noreply.github.com> Date: Fri, 3 May 2024 15:51:26 +0200 Subject: [PATCH 1/5] ENH - also attempt to extract events from biosig hdr --- fileio/ft_read_event.m | 32 ++++++++--- fileio/private/biosig2fieldtripevent.m | 78 ++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 fileio/private/biosig2fieldtripevent.m diff --git a/fileio/ft_read_event.m b/fileio/ft_read_event.m index ececfc92ba..81f101f7fb 100644 --- a/fileio/ft_read_event.m +++ b/fileio/ft_read_event.m @@ -492,15 +492,33 @@ hdr = ft_read_header(filename); end % the following applies to Biosemi data that is stored in the gdf format - statusindx = find(strcmp(hdr.label, 'STATUS')); - if length(statusindx)==1 + chanindx = find(strcmp(hdr.label, 'STATUS')); + event = []; + if length(chanindx)==1 % represent the rising flanks in the STATUS channel as events - event = read_trigger(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', flt_minsample, 'endsample', flt_maxsample, 'chanindx', statusindx, 'detectflank', 'up', 'trigshift', trigshift, 'trigpadding', trigpadding, 'fixbiosemi', true); + event = read_trigger(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', flt_minsample, 'endsample', flt_maxsample, 'chanindx', chanindx, 'detectflank', detectflank, 'trigshift', trigshift, 'trigpadding', trigpadding, 'fixbiosemi', true); else - ft_warning('BIOSIG does not have a consistent event representation, skipping events') - event = []; - end - + ft_warning('data does not have a STATUS channel'); + end + + % make an attempt to get the events from the BIOSIG hdr + if isfield(hdr.orig, 'EVENT') + % this is code that has been inspired by eeglab's biosig2eeglabevent + event_hdr = biosig2fieldtripevent(hdr.orig.EVENT); + else + event_hdr = []; + end + + if ~isempty(event) && ~isempty(event_hdr) + % merge the two structs + event = appendstruct(event(:), event_hdr(:)); + smp = [event.sample]; + [srt, indx] = sort(smp); + event = event(indx); + elseif isempty(event) && ~isempty(event_hdr) + event = event_hdr(:); + end + case 'AnyWave' event = read_ah5_markers(hdr, filename); diff --git a/fileio/private/biosig2fieldtripevent.m b/fileio/private/biosig2fieldtripevent.m new file mode 100644 index 0000000000..944dfeda1c --- /dev/null +++ b/fileio/private/biosig2fieldtripevent.m @@ -0,0 +1,78 @@ +function eventout = biosig2fieldtripevent(eventin) + +% BIOSIG2FIELDTRIPEVENT converts event information from a biosig hdr into +% fieldtrip events + +ft_hastoolbox('BIOSIG', 1); +f = which('sopen.m'); +[p,f,e] = fileparts(f); + +if contains(p, 'external') + % assume the biosig to be shipped with the fieldtrip distro, in which + % case we need to look into fullfile(p,'doc') +else + % assume the biosig to be from the official distro, in which case we need + % to look into ../doc, relative to p + tok = tokenize(p, filesep); + p = fullfile(tok{1:end-1}); +end + +try + EVT = sopen(fullfile(p, 'doc', 'eventcodes.txt'));sclose(EVT); +catch + warning('failed to load eventcodes'); + eventout = []; + return; +end + +if isfield(eventin, 'TYP') + for index = 1:length( eventin.TYP ) + eType = eventin.TYP(index); + + % use file in + % https://sccn.ucsd.edu/bugzilla/show_bug.cgi?id=1387 to test + % for boundary events + if eType < 256 && isfield(eventin,'CodeDesc') && eType < length(eventin.CodeDesc) + eventout(index).type = eventin.CodeDesc{eType}; + eventout(index).value = eType; + elseif isfield(EVT, 'EVENT') && isfield(EVT.EVENT,'CodeIndex') && isfield(EVT.EVENT,'CodeDesc') + if any(EVT.EVENT.CodeIndex==eType) + eventout(index).type = EVT.EVENT.CodeDesc{EVT.EVENT.CodeIndex==eType}; + else + eventout(index).type = 'event'; + end + eventout(index).value = eType; + + % FIXME I leave the below in for reference, I don't know what it + % means, but we might need it in the future +% if eType == 32766 || eType == 32767 +% eventout(index).edfplustype = eventout(index).type; +% eventout(index).type = eeg_boundarytype(event); +% end + else + eventout(index).type = 'event'; + eventout(index).value = eType; + end + end +end +if isfield(eventin, 'POS') + for index = 1:length( eventin.POS ) + eventout(index).sample = eventin.POS(index); + end +end +if isfield(eventin, 'DUR') + if any( [ eventin.DUR ] ) + for index = 1:length( eventin.DUR ) + eventout(index).duration = eventin.DUR(index); + end + end +end +if isfield(eventin, 'CHN') + if any( [ eventin.CHN ] ) + for index = 1:length( eventin.CHN ) + eventout(index).chanindex = eventin.CHN(index); + end + end +end + +eventout = eventout(:); From 463b0a86051a935711d51971a0e08da60509dffe Mon Sep 17 00:00:00 2001 From: Jan-Mathijs Schoffelen <1517611+schoffelen@users.noreply.github.com> Date: Tue, 14 May 2024 09:39:47 +0200 Subject: [PATCH 2/5] ENH - only check for STATUS channel when chanindx not empty --- fileio/ft_read_event.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fileio/ft_read_event.m b/fileio/ft_read_event.m index 81f101f7fb..f996af3b90 100644 --- a/fileio/ft_read_event.m +++ b/fileio/ft_read_event.m @@ -492,10 +492,12 @@ hdr = ft_read_header(filename); end % the following applies to Biosemi data that is stored in the gdf format - chanindx = find(strcmp(hdr.label, 'STATUS')); + if ~isempty(chanindx) + chanindx = find(strcmp(hdr.label, 'STATUS')); + end event = []; if length(chanindx)==1 - % represent the rising flanks in the STATUS channel as events + % represent the rising flanks in the STATUS (or user specified) channel as events event = read_trigger(filename, 'header', hdr, 'dataformat', dataformat, 'begsample', flt_minsample, 'endsample', flt_maxsample, 'chanindx', chanindx, 'detectflank', detectflank, 'trigshift', trigshift, 'trigpadding', trigpadding, 'fixbiosemi', true); else ft_warning('data does not have a STATUS channel'); From 12e9d794d412dece8d42b6138277434be4c35ae5 Mon Sep 17 00:00:00 2001 From: Jan-Mathijs Schoffelen <1517611+schoffelen@users.noreply.github.com> Date: Tue, 14 May 2024 10:12:28 +0200 Subject: [PATCH 3/5] ENH - improved robustness --- fileio/private/biosig2fieldtripevent.m | 1 + 1 file changed, 1 insertion(+) diff --git a/fileio/private/biosig2fieldtripevent.m b/fileio/private/biosig2fieldtripevent.m index 944dfeda1c..d5c5565fd1 100644 --- a/fileio/private/biosig2fieldtripevent.m +++ b/fileio/private/biosig2fieldtripevent.m @@ -25,6 +25,7 @@ return; end +eventout = struct([]); if isfield(eventin, 'TYP') for index = 1:length( eventin.TYP ) eType = eventin.TYP(index); From 7bdb9667828dbf42a47fa98eab48ee47bfee60ef Mon Sep 17 00:00:00 2001 From: Jan-Mathijs Schoffelen <1517611+schoffelen@users.noreply.github.com> Date: Tue, 14 May 2024 10:17:11 +0200 Subject: [PATCH 4/5] ENH - added placeholder file --- test/test_pull2413.m | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/test_pull2413.m diff --git a/test/test_pull2413.m b/test/test_pull2413.m new file mode 100644 index 0000000000..a601daa05e --- /dev/null +++ b/test/test_pull2413.m @@ -0,0 +1,28 @@ +function test_pull2413 + +% MEM 1gb +% WALLTIME 00:10:00 +% DEPENDENCY ft_read_event +% DATA private + +%% + +mshdir = dccnpath('/home/common/matlab/fieldtrip/data/test/pull2183/'); + +d = dir(fullfile(mshdir, '*.msh')); +for k = 1:numel(d) + hs = ft_read_headshape(fullfile(d(k).folder, d(k).name)); +end + +%% + +filename = dccnpath('/home/common/matlab/fieldtrip/data/test/original/simnibs/v4/ernie.msh'); +hm = ft_read_headmodel(filename, 'fileformat', 'simnibs'); +hm = ft_read_headmodel(filename, 'fileformat', 'simnibs', 'meshtype', 'surface'); + +%% + +filename = dccnpath('/home/common/matlab/fieldtrip/data/test/original/simnibs/v3/ernie_v3.msh'); +hm = ft_read_headmodel(filename, 'fileformat', 'simnibs'); +hm = ft_read_headmodel(filename, 'fileformat', 'simnibs', 'meshtype', 'surface'); + From 4274be6a49972abee10bbb9b2a7cc9895ca5aeff Mon Sep 17 00:00:00 2001 From: Jan Mathijs Schoffelen Date: Tue, 14 May 2024 10:23:08 +0200 Subject: [PATCH 5/5] ENH - added test function + test data (from mne-testing-data) --- test/test_pull2413.m | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/test/test_pull2413.m b/test/test_pull2413.m index a601daa05e..de67482fd3 100644 --- a/test/test_pull2413.m +++ b/test/test_pull2413.m @@ -7,22 +7,10 @@ %% -mshdir = dccnpath('/home/common/matlab/fieldtrip/data/test/pull2183/'); +datadir = dccnpath('/home/common/matlab/fieldtrip/data/test/original/eeg/gdf/'); -d = dir(fullfile(mshdir, '*.msh')); +d = dir(fullfile(datadir, '*.gdf')); for k = 1:numel(d) - hs = ft_read_headshape(fullfile(d(k).folder, d(k).name)); + event = ft_read_event(fullfile(d(k).folder, d(k).name)); end -%% - -filename = dccnpath('/home/common/matlab/fieldtrip/data/test/original/simnibs/v4/ernie.msh'); -hm = ft_read_headmodel(filename, 'fileformat', 'simnibs'); -hm = ft_read_headmodel(filename, 'fileformat', 'simnibs', 'meshtype', 'surface'); - -%% - -filename = dccnpath('/home/common/matlab/fieldtrip/data/test/original/simnibs/v3/ernie_v3.msh'); -hm = ft_read_headmodel(filename, 'fileformat', 'simnibs'); -hm = ft_read_headmodel(filename, 'fileformat', 'simnibs', 'meshtype', 'surface'); -