Eventfilters with durations return wrong (amount of) rows?

조회 수: 4 (최근 30일)
Soc
Soc 2024년 9월 19일
댓글: Soc 2024년 9월 25일
Hi all, I have a question that's either a case of "am I not understanding this right?" or a bug in eventfilters.
I've noticed 2 things: 1) event filters with durations seem to return the rows after the start of events, and 2) scaling the duration of events does not result in the expected scaling of the number of rows filtered.
For background, in reality I'm using this to mark the edges of TTL-pulses in datasets, but I made an example below that I think illustrates my point.
Running the following code:
% Create a 5s timetable with mock data.
test_table = timetable(seconds(linspace(1/1000, 5, 5000)).', linspace(0, 1, 5000).');
% Create an eventtable with 3 events at random time points and a duration
% equal to the table timestep.
test_times = seconds([1.101, 2.2, 3]);
labels = ["rising", "rising", "falling"];
delta_t = test_table.Properties.TimeStep;
lengths = repmat(1*delta_t, 1, 3);
test_events = eventtable(test_times, EventLabels = labels, EventLengths = lengths);
% Associate events with timetable.
test_table.Properties.Events = test_events;
% Create a filter to determine the time of the rising edges.
test_filter = eventfilter("rising");
test_rows = test_table(test_filter, :);
% Display number of rows returned by the filter.
disp(height(test_rows));
% Display the times of the filtered rows.
disp(test_rows.Time);
So here I'm making a mock timetable of 5 seconds at 1000 Hz, with mock data in it, and 3 time events: two rising edges, and one falling edge. Each event is given a length of 1/1000s or 1 ms, which is equal to the timestep of the table. Then, I create an eventfilter to extract the rows of the time table at these edges.
Issue 1
The filter returns 2 rows as expected. However, the row times are 1.102 and 2.201, which are the row times after the rows in which the events begin according to the event table. This seems at odds with the description in the documentation for eventtable, which says that "Interval events happen during intervals that start at event times and include all times up to, but not including, the times at the end of the events." (emphasis mine). So shouldn't these timed events return the row times 1.101 and 2.200 seconds?
As an aside, removing the EventLengths from the eventtable constructor returns the correct row times.
Issue 2
Second, for events with lengths larger than a single TimeStep, increasing the duration by a given factor does not always increase the number of returned rows by the same amount.
In this case, if I replace
lengths = repmat(1*delta_t, 1, 3);
with
lengths = repmat(50*delta_t, 1, 3);
and run the code again:
test_events = eventtable(test_times, EventLabels = labels, EventLengths = lengths);
test_table.Properties.Events = test_events;
test_filter = eventfilter("rising");
test_rows = test_table(test_filter, :);
disp(height(test_rows));
the number of filtered rows increases from 2 to 100, as expected.
However, increasing the duration of the events to 100 TimeSteps, changes the number of filtered rows to 199 instead of 200, which is what I was expecting.
lengths = repmat(100*delta_t, 1, 3);
test_events = eventtable(test_times, EventLabels = labels, EventLengths = lengths);
test_table.Properties.Events = test_events;
test_filter = eventfilter("rising");
test_rows = test_table(test_filter, :);
disp(height(test_rows));
This seems odd, given that both 50 and 100 TimeSteps should easily fit within the time vector of the table, are exact multiples of each other, do not overlap with other events and the length was based on the TimeStep property of the table.
I've locally tested the script in 2024a, but the code examples above ran in 2024b.
  댓글 수: 1
Soc
Soc 2024년 9월 19일
Apologies, the post used to have the 'live-script'-style code returns underneath the code blocks, but after trying to edit a typo, the text is somehow in two invisible colums with the code returns in the second column which doesn't show up when the webpage is rendered.

댓글을 달려면 로그인하십시오.

채택된 답변

Peter Perkins
Peter Perkins 2024년 9월 25일
Soc, I think you need
test_table = timetable(milliseconds(1:5000).', linspace(0, 1, 5000).');
test_times = milliseconds([1101 2200 3000]);
By the time you do this
sprintf("%.20f",1/1000)
ans = "0.00100000000000000002"
you are done for.
  댓글 수: 2
Corey Silva
Corey Silva 2024년 9월 25일
Peter is correct,
One solution for this would be to use a withtol around the eventfilter to give it a tolerance.
>> test_filter = withtol(eventfilter("rising"),milliseconds(.01));
>> test_rows = test_table(test_filter, :)
test_rows = 4×1 timetable with 3 events
Time Var1
_________ _______
1.101 sec 0.22004
rising 1.102 sec 0.22024
2.2 sec 0.43989
rising 2.201 sec 0.44009
Soc
Soc 2024년 9월 25일
Thank you Peter and Corey for the answer and suggestion of withtol(). I didn't expect the floating-point precision of seconds() versus milliseconds() to make a difference here, but that makes sense.

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Timetables에 대해 자세히 알아보기

제품


릴리스

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by