rdrecord的使用:
import matplotlib.pyplot as plt
import wfdb
record = wfdb.rdrecord('sample-data/a103l')
plt.plot(record.p_signal[0: 500, 0])
plt.plot(record.p_signal[500: 1000, 1])
plt.plot(record.p_signal[49500: 50000, 2])
plt.show()
rdsamp的使用:
from IPython.display import display
import matplotlib.pyplot as plt
import numpy as np
import os
import shutil
import wfdb
# Demo 2 - Read certain channels and sections of the WFDB record using the simplified 'rdsamp' function
# which returns a numpy array and a dictionary. Show the data.
signals, fields = wfdb.rdsamp('sample-data/s0010_re', channels=[14, 0, 5, 10], sampfrom=100, sampto=15000)
display(signals)
display(fields)
运行结果如下:
[[ 0.0335 -0.167 -0.237 0.1165]
[ 0.0355 -0.1615 -0.2395 0.119 ]
[ 0.0385 -0.168 -0.2465 0.116 ]
...
[-0.0445 0.008 0.033 0.045 ]
[-0.044 0.0175 0.042 0.052 ]
[-0.044 0.0245 0.0365 0.05 ]]
{'comments': ['age: 81', 'sex: female', 'ECG date: 01/10/1990', 'Diagnose:', 'Reason for admission: Myocardial infarction', 'Acute infarction (localization): infero-latera', 'Former infarction (localization): no', 'Additional diagnoses: Diabetes mellitus', 'Smoker: no', 'Number of coronary vessels involved: 1', 'Infarction date (acute): 29-Sep-90', 'Previous infarction (1) date: n/a', 'Previous infarction (2) date: n/a', 'Hemodynamics:', 'Catheterization date: 16-Oct-90', 'Ventriculography: Akinesia inferior wall', 'Chest X-ray: Heart size upper limit of norm', 'Peripheral blood Pressure (syst/diast): 140/80 mmHg', 'Pulmonary artery pressure (at rest) (syst/diast): n/a', 'Pulmonary artery pressure (at rest) (mean): n/a', 'Pulmonary capillary wedge pressure (at rest): n/a', 'Cardiac output (at rest): n/a', 'Cardiac index (at rest): n/a', 'Stroke volume index (at rest): n/a', 'Pulmonary artery pressure (laod) (syst/diast): n/a', 'Pulmonary artery pressure (laod) (mean): n/a', 'Pulmonary capillary wedge pressure (load): n/a', 'Cardiac output (load): n/a', 'Cardiac index (load): n/a', 'Stroke volume index (load): n/a', 'Aorta (at rest) (syst/diast): 160/64 cmH2O', 'Aorta (at rest) mean: 106 cmH2O', 'Left ventricular enddiastolic pressure: 11 cmH2O', 'Left coronary artery stenoses (RIVA): RIVA 70% proximal to ramus diagonalis_2', 'Left coronary artery stenoses (RCX): No stenoses', 'Right coronary artery stenoses (RCA): No stenoses', 'Echocardiography: n/a', 'Therapy:', 'Infarction date: 29-Sep-90', 'Catheterization date: 16-Oct-90', 'Admission date: 29-Sep-90', 'Medication pre admission: Isosorbit-Dinitrate Digoxin Glibenclamide', 'Start lysis therapy (hh.mm): 19:45', 'Lytic agent: Gamma-TPA', 'Dosage (lytic agent): 30 mg', 'Additional medication: Heparin Isosorbit-Mononitrate ASA Diazepam', 'In hospital medication: ASA Isosorbit-Mononitrate Ca-antagonist Amiloride+Chlorothiazide Glibenclamide Insulin', 'Medication after discharge: ASA Isosorbit-Mononitrate Amiloride+Chlorothiazide Glibenclamide'], 'sig_len': 14900, 'sig_name': ['vz', 'i', 'avf', 'v5'], 'units': ['mV', 'mV', 'mV', 'mV'], 'n_sig': 4, 'base_time': None, 'fs': 1000, 'base_date': None}
Process finished with exit code 0
读header文件:
# Demo 3 - Read a WFDB header file only (without the signals)
record = wfdb.rdheader('sample-data/drive02')
display(record.__dict__)
# Can also read the same file hosted on Physiobank
record2 = wfdb.rdheader('drive02', pb_dir='drivedb')
rdann读取注释文件:
# Demo 4 - Read part of a WFDB annotation file into a wfdb.Annotation object, and plot the samples
annotation = wfdb.rdann('sample-data/100', 'atr', sampfrom=100000, sampto=110000)
显示label信息:
import wfdb
# View the standard WFDB annotation labels
wfdb.show_ann_labels()
运行结果如下:
label_store symbol description
0 0 Not an actual annotation
1 1 N Normal beat
2 2 L Left bundle branch block beat
3 3 R Right bundle branch block beat
4 4 a Aberrated atrial premature beat
5 5 V Premature ventricular contraction
6 6 F Fusion of ventricular and normal beat
7 7 J Nodal (junctional) premature beat
8 8 A Atrial premature contraction
9 9 S Premature or ectopic supraventricular beat
10 10 E Ventricular escape beat
11 11 j Nodal (junctional) escape beat
12 12 / Paced beat
13 13 Q Unclassifiable beat
14 14 ~ Signal quality change
16 16 | Isolated QRS-like artifact
18 18 s ST change
19 19 T T-wave change
20 20 * Systole
21 21 D Diastole
22 22 " Comment annotation
23 23 = Measurement annotation
24 24 p P-wave peak
25 25 B Left or right bundle branch block
26 26 ^ Non-conducted pacer spike
27 27 t T-wave peak
28 28 + Rhythm change
29 29 u U-wave peak
30 30 ? Learning
31 31 ! Ventricular flutter wave
32 32 [ Start of ventricular flutter/fibrillation
33 33 ] End of ventricular flutter/fibrillation
34 34 e Atrial escape beat
35 35 n Supraventricular escape beat
36 36 @ Link to external data (aux_note contains URL)
37 37 x Non-conducted P-wave (blocked APB)
38 38 f Fusion of paced and normal beat
39 39 ( Waveform onset
40 40 ) Waveform end
41 41 r R-on-T premature ventricular contraction
Process finished with exit code 0
ECG Processing:
import matplotlib.pyplot as plt
import numpy as np
import wfdb
from wfdb import processing
# Use the gqrs detection algorithm and correct the peaks
def peaks_hr(sig, peak_inds, fs, title, figsize=(20, 10), saveto=None):
"Plot a signal with its peaks and heart rate"
# Calculate heart rate
hrs = processing.compute_hr(sig_len=sig.shape[0], qrs_inds=peak_inds, fs=fs)
N = sig.shape[0]
fig, ax_left = plt.subplots(figsize=figsize)
ax_right = ax_left.twinx()
ax_left.plot(sig, color='#3979f0', label='Signal')
ax_left.plot(peak_inds, sig[peak_inds], 'rx', marker='x', color='#8b0000', label='Peak', markersize=12)
ax_right.plot(np.arange(N), hrs, label='Heart rate', color='m', linewidth=2)
ax_left.set_title(title)
ax_left.set_xlabel('Time (ms)')
ax_left.set_ylabel('ECG (mV)', color='#3979f0')
ax_right.set_ylabel('Heart rate (bpm)', color='m')
# Make the y-axis label, ticks and tick labels match the line color.
ax_left.tick_params('y', colors='#3979f0')
ax_right.tick_params('y', colors='m')
if saveto is not None:
plt.savefig(saveto, dpi=600)
plt.show()
# Load the wfdb record and the physical samples
record = wfdb.rdrecord('sample-data/100', sampfrom=0, sampto=10000, channels=[0])
# Use the gqrs algorithm to detect qrs locations in the first channel
qrs_inds = processing.gqrs_detect(sig=record.p_signal[:, 0], fs=record.fs)
# Plot results
peaks_hr(sig=record.p_signal, peak_inds=qrs_inds, fs=record.fs,
title="GQRS peak detection on record 100")
# Correct the peaks shifting them to local maxima
min_bpm = 20
max_bpm = 230
# min_gap = record.fs * 60 / min_bpm
# Use the maximum possible bpm as the search radius
search_radius = int(record.fs * 60 / max_bpm)
corrected_peak_inds = processing.correct_peaks(record.p_signal[:, 0], peak_inds=qrs_inds,
search_radius=search_radius, smooth_window_size=150)
# Display results
print('Corrected gqrs detected peak indices:', sorted(corrected_peak_inds))
peaks_hr(sig=record.p_signal, peak_inds=sorted(corrected_peak_inds), fs=record.fs,
title="Corrected GQRS peak detection on sampledata/100")
Use the xqrs detection algorithm and compare results to reference annotations
import matplotlib.pyplot as plt
import numpy as np
import wfdb
from wfdb import processing
sig, fields = wfdb.rdsamp('sample-data/100', channels=[0], sampto=15000)
ann_ref = wfdb.rdann('sample-data/100','atr', sampto=15000)
# Run qrs detection on signal
xqrs = processing.XQRS(sig=sig[:,0], fs=fields['fs'])
xqrs.detect()
# Alternatively, use the gateway function to get the qrs indices directly
# qrs_inds = processing.xqrs_detect(sig=sig[:,0], fs=fields['fs'])
# Compare detected qrs complexes to reference annotation.
# Note, first sample in 100.atr is not a qrs.
comparitor = processing.compare_annotations(ref_sample=ann_ref.sample[1:],
test_sample=xqrs.qrs_inds,
window_width=int(0.1 * fields['fs']),
signal=sig[:,0])
# Print and plot the results
comparitor.print_summary()
comparitor.plot(title='xqrs detected qrs vs reference annotations')
运行结果如下: