Skip to content

Commit fafa01a

Browse files
authored
Merge pull request MIT-LCP#287 from MIT-LCP/wfdbdesc
Adds wfdbdesc function
2 parents 2673243 + 4369b7a commit fafa01a

File tree

3 files changed

+119
-2
lines changed

3 files changed

+119
-2
lines changed

wfdb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from wfdb.io.record import (Record, MultiRecord, rdheader, rdrecord, rdsamp,
22
wrsamp, dl_database, edf2mit, mit2edf, wav2mit, mit2wav,
3-
wfdb2mat, csv2mit, sampfreq, signame)
3+
wfdb2mat, csv2mit, sampfreq, signame, wfdbdesc)
44
from wfdb.io.annotation import (Annotation, rdann, wrann, show_ann_labels,
55
show_ann_classes, ann2rr, rr2ann)
66
from wfdb.io.download import get_dbs, get_record_list, dl_files, set_db_index_url

wfdb/io/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from wfdb.io.record import (Record, MultiRecord, rdheader, rdrecord, rdsamp, wrsamp,
22
dl_database, edf2mit, mit2edf, wav2mit, mit2wav, wfdb2mat,
3-
csv2mit, sampfreq, signame, SIGNAL_CLASSES)
3+
csv2mit, sampfreq, signame, wfdbdesc, SIGNAL_CLASSES)
44
from wfdb.io._signal import est_res, wr_dat_file
55
from wfdb.io.annotation import (Annotation, rdann, wrann, show_ann_labels,
66
show_ann_classes, ann2rr, rr2ann)

wfdb/io/record.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,6 +3805,123 @@ def signame(record_name, pn_dir=None, sig_nums=[]):
38053805
print(*record.sig_name, sep='\n')
38063806

38073807

3808+
def wfdbdesc(record_name, pn_dir=None):
3809+
"""
3810+
Reads specifications for the signals described in the header file for
3811+
a record.
3812+
3813+
Parameters
3814+
----------
3815+
record_name : str
3816+
The name of the WFDB record to be read, without any file
3817+
extensions. If the argument contains any path delimiter
3818+
characters, the argument will be interpreted as PATH/BASE_RECORD.
3819+
Both relative and absolute paths are accepted. If the `pn_dir`
3820+
parameter is set, this parameter should contain just the base
3821+
record name, and the files fill be searched for remotely.
3822+
Otherwise, the data files will be searched for in the local path.
3823+
pn_dir : str, optional
3824+
Option used to stream data from Physionet. The Physionet
3825+
database directory from which to find the required record files.
3826+
eg. For record '100' in 'http://physionet.org/content/mitdb'
3827+
pn_dir='mitdb'.
3828+
3829+
Returns
3830+
-------
3831+
N/A
3832+
3833+
Examples
3834+
--------
3835+
>>> wfdb.wfdbdesc('100', pn_dir='mitdb')
3836+
Record 100
3837+
Notes
3838+
=====
3839+
69 M 1085 1629 x1
3840+
Aldomet, Inderal
3841+
=====
3842+
3843+
Starting time: not specified
3844+
Length: 0:30:05.555556 (650000 sample intervals)
3845+
Sampling frequency: 360 Hz
3846+
2 signals
3847+
Group 0, Signal 0:
3848+
File: 100.dat
3849+
Description: MLII
3850+
Gain: 200.0 mV
3851+
Initial value: 995
3852+
Storage format: 212 (1 sample per frame)
3853+
I/O: can be unbuffered
3854+
ADC resolution: 11 bits
3855+
ADC zero: 1024
3856+
Baseline: 1024
3857+
Checksum: -22131
3858+
Group 0, Signal 1:
3859+
File: 100.dat
3860+
Description: V5
3861+
Gain: 200.0 mV
3862+
Initial value: 1011
3863+
Storage format: 212 (1 sample per frame)
3864+
I/O: can be unbuffered
3865+
ADC resolution: 11 bits
3866+
ADC zero: 1024
3867+
Baseline: 1024
3868+
Checksum: 20052
3869+
3870+
"""
3871+
if (pn_dir is not None) and ('.' not in pn_dir):
3872+
dir_list = pn_dir.split('/')
3873+
pn_dir = posixpath.join(dir_list[0], get_version(dir_list[0]),
3874+
*dir_list[1:])
3875+
3876+
record = rdheader(record_name, pn_dir=pn_dir)
3877+
if type(record) is MultiRecord:
3878+
sub_string = 'fixed' if record.segments else 'variable'
3879+
seg_string = f' (a {sub_string}-layout multi-segment record)'
3880+
else:
3881+
seg_string = ''
3882+
3883+
print(f'Record {record_name}{seg_string}')
3884+
3885+
if record.comments:
3886+
print('Notes')
3887+
print('=====')
3888+
for comment in record.comments:
3889+
print(f' {comment}')
3890+
print('=====')
3891+
print()
3892+
3893+
try:
3894+
start_time = f'[{datetime.datetime.combine(record.base_date, record.base_time)}]'
3895+
except TypeError:
3896+
start_time = 'not specified'
3897+
print(f'Starting time: {start_time}')
3898+
3899+
record_length = str(datetime.timedelta(seconds=record.sig_len/record.fs))
3900+
print(f'Length: {record_length} ({record.sig_len} sample intervals)')
3901+
3902+
print(f'Sampling frequency: {record.fs} Hz')
3903+
print(f'{record.n_sig} signal{"" if record.n_sig==1 else "s"}')
3904+
3905+
if type(record) is not MultiRecord:
3906+
for i in range(record.n_sig):
3907+
print(f'Group 0, Signal {i}:')
3908+
print(f' File: {record.file_name[i]}')
3909+
print(f' Description: {record.sig_name[i]}')
3910+
print(f' Gain: {record.adc_gain[i]} {record.units[i]}')
3911+
print(f' Initial value: {record.init_value[i]}')
3912+
sample_string = '' if record.samps_per_frame[i]==1 else 's'
3913+
print(f' Storage format: {record.fmt[i]} ({record.samps_per_frame[i]} sample{sample_string} per frame)')
3914+
if record.byte_offset[i]:
3915+
byte_string = f'{record.byte_offset[i]}-byte blocks'
3916+
else:
3917+
byte_string = 'can be unbuffered'
3918+
print(f' I/O: {byte_string}')
3919+
print(f' ADC resolution: {record.adc_res[i]} bits')
3920+
print(f' ADC zero: {record.adc_zero[i]}')
3921+
print(f' Baseline: {record.baseline[i]}')
3922+
print(f' Checksum: {record.checksum[i]}')
3923+
3924+
38083925
def _get_wanted_channels(wanted_sig_names, record_sig_names, pad=False):
38093926
"""
38103927
Given some wanted signal names, and the signal names contained in a

0 commit comments

Comments
 (0)