Skip to content

Commit 6c135b1

Browse files
author
Benjamin Moody
committed
BaseRecord: add time conversion methods.
These methods can be used to convert between three different representations of time: - frame number (i.e., an index into the p_signal or d_signal array) - elapsed time in microseconds, represented by a datetime.timedelta object - absolute date and time, represented by a datetime.datetime object Each of these methods will accept any of these three representations as an argument, and convert into the specified representation. For example, using record 100 (which has a frame frequency of 360 Hz): >>> r = wfdb.rdrecord('sample-data/100') >>> r.get_elapsed_time(180) datetime.timedelta(microseconds=500000) >>> r.get_frame_number(datetime.timedelta(seconds=0.5)) 180.0
1 parent 59b09ba commit 6c135b1

File tree

3 files changed

+107
-4
lines changed

3 files changed

+107
-4
lines changed

docs/io.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ WFDB Records
1212
:members: rdrecord, rdheader, rdsamp, wrsamp
1313

1414
.. autoclass:: wfdb.io.Record
15-
:members: wrsamp, adc, dac
15+
:members: get_frame_number, get_elapsed_time, get_absolute_time,
16+
wrsamp, adc, dac
1617

1718
.. autoclass:: wfdb.io.MultiRecord
18-
:members: multi_to_single
19+
:members: get_frame_number, get_elapsed_time, get_absolute_time,
20+
multi_to_single
1921

2022

2123
WFDB Anotations

docs/wfdb.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ WFDB Records
1212
:members: rdrecord, rdheader, rdsamp, wrsamp
1313

1414
.. autoclass:: wfdb.Record
15-
:members: wrsamp, adc, dac
15+
:members: get_frame_number, get_elapsed_time, get_absolute_time,
16+
wrsamp, adc, dac
1617

1718
.. autoclass:: wfdb.MultiRecord
18-
:members: multi_to_single
19+
:members: get_frame_number, get_elapsed_time, get_absolute_time,
20+
multi_to_single
1921

2022

2123
WFDB Anotations

wfdb/io/record.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,105 @@ def base_datetime(self, value):
249249
else:
250250
raise TypeError(f"invalid base_datetime value: {value!r}")
251251

252+
def get_frame_number(self, time_value):
253+
"""
254+
Convert a time value to a frame number.
255+
256+
A time value may be specified as:
257+
- An integer or floating-point number, representing the number of
258+
WFDB frames elapsed from the start of the record.
259+
- A `datetime.timedelta` object, representing elapsed time from the
260+
start of the record.
261+
- A `datetime.datetime` object, representing an absolute date and
262+
time (if the record starting time is known.)
263+
264+
Note that this function may return a value that is less than zero
265+
or greater than the actual length of the record.
266+
267+
Parameters
268+
----------
269+
time_value : number or timedelta or datetime
270+
A time value.
271+
272+
Returns
273+
-------
274+
frame_number : float
275+
Frame number (possibly a fractional frame number).
276+
277+
"""
278+
if hasattr(time_value, "__float__"):
279+
return float(time_value)
280+
281+
if isinstance(time_value, datetime.datetime):
282+
if not self.base_datetime:
283+
raise ValueError(
284+
"base_datetime is unknown; cannot convert absolute "
285+
"date/time to a frame number"
286+
)
287+
time_value -= self.base_datetime
288+
289+
if isinstance(time_value, datetime.timedelta):
290+
return time_value.total_seconds() * self.fs
291+
292+
raise TypeError(f"invalid time value: {time_value!r}")
293+
294+
def get_elapsed_time(self, time_value):
295+
"""
296+
Convert a time value to an elapsed time in seconds.
297+
298+
A time value may be specified as:
299+
- An integer or floating-point number, representing the number of
300+
WFDB frames elapsed from the start of the record.
301+
- A `datetime.timedelta` object, representing elapsed time from the
302+
start of the record.
303+
- A `datetime.datetime` object, representing an absolute date and
304+
time (if the record starting time is known.)
305+
306+
Parameters
307+
----------
308+
time_value : number or timedelta or datetime
309+
A time value.
310+
311+
Returns
312+
-------
313+
elapsed_time : timedelta
314+
Elapsed time from the start of the record.
315+
316+
"""
317+
time_value = self.get_frame_number(time_value)
318+
return datetime.timedelta(seconds=time_value / self.fs)
319+
320+
def get_absolute_time(self, time_value):
321+
"""
322+
Convert a time value to an absolute date and time.
323+
324+
A time value may be specified as:
325+
- An integer or floating-point number, representing the number of
326+
WFDB frames elapsed from the start of the record.
327+
- A `datetime.timedelta` object, representing elapsed time from the
328+
start of the record.
329+
- A `datetime.datetime` object, representing an absolute date and
330+
time (if the record starting time is known.)
331+
332+
Parameters
333+
----------
334+
time_value : number or timedelta or datetime
335+
A time value.
336+
337+
Returns
338+
-------
339+
absolute_time : datetime
340+
Absolute date and time.
341+
342+
"""
343+
time_value = self.get_elapsed_time(time_value)
344+
if not self.base_datetime:
345+
raise ValueError(
346+
"base_datetime is unknown; cannot convert frame number "
347+
"to an absolute date/time"
348+
)
349+
return time_value + self.base_datetime
350+
252351
def check_field(self, field, required_channels="all"):
253352
"""
254353
Check whether a single field is valid in its basic form. Does

0 commit comments

Comments
 (0)