Attaching event labels from excel to EDF file - how to interpolate and merge data?

7 views (last 30 days)
Hello!
I have recorded ECG data with Acqknowledge (BioPac) and want to analyse the data in Matlab. Having used different experimental conditions, I have a number of event labels indicating the onset of a particular stimulus which are visible in Acqknowledge but have to be exported separatly to Matlab.
The ECG data can be exported from Acq to EDF which is a file the toolbox I am using can read. The event labels are stored in a .xls file as a table format.
Now I face the challenge of attaching my event labels to my ECG data which I then want to save as a new EDF file for analysing the data depending on the respective experimental conditions (indicated by the labels).
My ecgData comes as a timetalbe format (apparently) with the recorded time in seconds as a first column, followed by four columns representing my channels (ECG, rate, digital input etc.)
My eventlabel data is in numeric values (codes for e.g., '255', '254'...) and is connected to a column indicating the even onset in seconds.
I am rather unexperienced in Matlab, so I tried a few things which did not work out yet.
data = edfread('T1_subject2_HRV.edf'); %read my data
ecgData = data(:, 3); % extract the exgData which is in column 3, resulting in a time object (?) with both recording time and ECG data in two columns
timeData = ecgData.Properties.RowTimes % I try to access time stmaps which results in a new time object with only the seconds of recording
% then I read the event labels in my xls file and extract the tie and event column separatly
table = readtable('subj2_T1_events.xlsx'); % Assuming event labels are in column A
timeColumn = table.Time
eventColumn = table.Label
% Convert time values to same format
timeInSecondsEvents = str2double(strrep(table.Time, ' sec', ''));
timeInSecondsECG = seconds(timeDataECG);
% Remove NaN I had left in my event label data because of some weird reason
validIndices = isfinite(eventColumn) & isfinite(timeInSecondsEvents);
eventColumnValid = eventColumn(validIndices);
timeInSecondsValidEvents = timeInSecondsEvents(validIndices);
Now I would like to merye my eventColumnValid back with my timeinSecondsValidEvents and attach these to my timeinSecondsECG and to my ecgData.
One idea was to use an if loop and let every column compare the time stamps of ECG recording with the event label time and insert the label when the time would match but I guess my computer would give up on me going through 3000 columns per participant.
% I stumbled across the inperpolate function trying to find the nearest neighbour between them.
matchedEventLabelsInSeconds = interp1(eventColumnValid, timeInSecondsValidEvents, timeInSecondsECG', 'extrap');
However, this produces the following error:
Error using interp1>parseinputs
An interpolation method must be specified with 'extrap'.
Error in interp1 (line 112)
parseinputs(X,V,penultimate,last,nargin,ndataarg,pp);
and I also need to attach my ecgData back to it which still lingers around in a timetable.
I am very happy for any suggestion on trying out something different or resolving this error in the first place.
Thank you and best regards
Linn

Answers (2)

Sanjana
Sanjana on 30 Aug 2023
Hi Linn,
I understand that you are trying to merge the ECG data read from “. edf” file and the data read from the “.xls” file containing event labels along with the onset durations, based on the common “recorded time column” in both the tables.
To achieve the above you can use, “join” function specifying the “keys” argument to be the name of the column that is common to both the tables, that is the “recorded time” column.
Please refer to the following documentation, for further information,
Hope this helps!
Regards,
Sanjana

Seth Furman
Seth Furman on 14 Sep 2023
Read event data and convert to an event table
Starting in R2023a, you can represent event data as an event table (eventtable).
% Ordinarily you'd use readtimetable here instead of readtable, but
% readtimetable does not currently support row-times of the format
% "<number> sec". You can avoid this by using row-times of the format
% "hh:mm:ss".
%
% See https://www.mathworks.com/help/matlab/ref/duration.html#mw_7dddd595-1be8-452b-8270-5589013aa7d4
%
% For example,
%
% Labels = [255;254];
% tt = timetable(seconds([1;2]),Labels);
% tt.Time.Format = "hh:mm:ss";
% writetimetable(tt,"data.xlsx");
%
% opts = detectImportOptions("data.xlsx");
% opts = setvaropts(opts,"Time",Type="duration",DurationFormat="hh:mm:ss");
% tt2 = readtimetable("data.xlsx",opts);
evnts = readtable("events.xlsx",TextType="string")
evnts = 5×2 table
Time Labels ________ ______ "10 sec" 255 "30 sec" 254 "45 sec" 253 "sec" 252 "50 sec" NaN
% At the moment, you can't directly convert strings with the format
% "<number> sec" into durations. datetime, however, allows you to specify
% many different formats, so you can use the datetime constructor to
% convert the strings into datetimes and then pull out the time of day to
% get the duration.
evnts.Time = timeofday(datetime(evnts.Time,InputFormat="ss 'sec'"));
% Now that we've converted evnts.Time into a duration array, we can convert
% the table into a timetable.
evnts = table2timetable(evnts)
evnts = 5×1 timetable
Time Labels ________ ______ 00:00:10 255 00:00:30 254 00:00:45 253 NaN 252 00:00:50 NaN
evnts = rmmissing(evnts) % Remove rows with missing data.
evnts = 3×1 timetable
Time Labels ________ ______ 00:00:10 255 00:00:30 254 00:00:45 253
% Convert the timetable into an eventtable.
evnts = eventtable(evnts,EventLabelsVariable="Labels")
evnts = 3×1 eventtable
Event Labels Variable: Labels Event Lengths Variable: <instantaneous> Time Labels ________ ______ 00:00:10 255 00:00:30 254 00:00:45 253
Read in the EDF data as a timetable and attach the event table
Event tables can be attached to a timetable using the new Events timetable property.
tt = edfread("example.edf")
tt = 6×2 timetable
Record Time ECG ECG2 ___________ _______________ _______________ 0 sec {1280×1 double} {1280×1 double} 10 sec {1280×1 double} {1280×1 double} 20 sec {1280×1 double} {1280×1 double} 30 sec {1280×1 double} {1280×1 double} 40 sec {1280×1 double} {1280×1 double} 50 sec {1280×1 double} {1280×1 double}
tt.Properties.Events = evnts
tt = 6×2 timetable
Record Time ECG ECG2 ___________ _______________ _______________ 0 sec {1280×1 double} {1280×1 double} 255 10 sec {1280×1 double} {1280×1 double} 20 sec {1280×1 double} {1280×1 double} 254 30 sec {1280×1 double} {1280×1 double} 40 sec {1280×1 double} {1280×1 double} 50 sec {1280×1 double} {1280×1 double}
Use the eventfilter subscripter to select rows corresponding to given events
% Get the rows of the timetable corresponding to the event whose label is 255.
eventLabelOfInterest = 255;
tt(eventfilter(eventLabelOfInterest),:)
ans = 1×2 timetable
Record Time ECG ECG2 ___________ _______________ _______________ 255 10 sec {1280×1 double} {1280×1 double}
% Get all rows of the timetable corresponding to any event.
tt(eventfilter(),:)
ans = 2×2 timetable
Record Time ECG ECG2 ___________ _______________ _______________ 255 10 sec {1280×1 double} {1280×1 double} 254 30 sec {1280×1 double} {1280×1 double}
Add and synchronize variables from the attached event table to the timetable
Data from an event table attached to a timetable can be added and synchronized to the timetable using syncevents.
tt = syncevents(tt)
tt = 6×3 timetable
Record Time ECG ECG2 Labels ___________ _______________ _______________ ______ 0 sec {1280×1 double} {1280×1 double} NaN 255 10 sec {1280×1 double} {1280×1 double} 255 20 sec {1280×1 double} {1280×1 double} NaN 254 30 sec {1280×1 double} {1280×1 double} 254 40 sec {1280×1 double} {1280×1 double} NaN 50 sec {1280×1 double} {1280×1 double} NaN
Aside
(1) You say that your event label data are numeric codes. If you have a fixed number of them, you can consider representing them as categoricals instead of numbers. For example,
evnts.Labels = categorical(evnts.Labels)
evnts = 3×1 eventtable
Event Labels Variable: Labels Event Lengths Variable: <instantaneous> Time Labels ________ ______ 00:00:10 255 00:00:30 254 00:00:45 253
(2) Your example has the following line.
table = readtable("...");
table is a bad variable name in MATLAB since it is the name of a class. Prefer something else, like tbl.

Products


Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!