|
12 | 12 | {
|
13 | 13 | "cell_type": "code",
|
14 | 14 | "execution_count": null,
|
15 |
| - "metadata": {}, |
| 15 | + "metadata": { |
| 16 | + "collapsed": true |
| 17 | + }, |
16 | 18 | "outputs": [],
|
17 | 19 | "source": [
|
18 | 20 | "import wfdb\n",
|
19 | 21 | "import numpy as np\n",
|
20 | 22 | "import os\n",
|
| 23 | + "import matplotlib.pyplot as plt\n", |
21 | 24 | "from IPython.display import display"
|
22 | 25 | ]
|
23 | 26 | },
|
|
46 | 49 | {
|
47 | 50 | "cell_type": "code",
|
48 | 51 | "execution_count": null,
|
49 |
| - "metadata": {}, |
| 52 | + "metadata": { |
| 53 | + "collapsed": true |
| 54 | + }, |
50 | 55 | "outputs": [],
|
51 | 56 | "source": [
|
52 | 57 | "# Demo 1 - Read a wfdb record using the 'rdsamp' function into a wfdb.Record object.\n",
|
|
64 | 69 | {
|
65 | 70 | "cell_type": "code",
|
66 | 71 | "execution_count": null,
|
67 |
| - "metadata": {}, |
| 72 | + "metadata": { |
| 73 | + "collapsed": true |
| 74 | + }, |
68 | 75 | "outputs": [],
|
69 | 76 | "source": [
|
70 | 77 | "# Demo 2 - Read certain channels and sections of the WFDB record using the simplified 'srdsamp' function\n",
|
|
80 | 87 | {
|
81 | 88 | "cell_type": "code",
|
82 | 89 | "execution_count": null,
|
83 |
| - "metadata": {}, |
| 90 | + "metadata": { |
| 91 | + "collapsed": true |
| 92 | + }, |
84 | 93 | "outputs": [],
|
85 | 94 | "source": [
|
86 | 95 | "# Demo 3 - Read a WFDB header file only (without the signals)\n",
|
|
94 | 103 | {
|
95 | 104 | "cell_type": "code",
|
96 | 105 | "execution_count": null,
|
97 |
| - "metadata": {}, |
| 106 | + "metadata": { |
| 107 | + "collapsed": true |
| 108 | + }, |
98 | 109 | "outputs": [],
|
99 | 110 | "source": [
|
100 | 111 | "# Demo 4 - Read part of a WFDB annotation file into a wfdb.Annotation object, and plot the samples\n",
|
|
109 | 120 | {
|
110 | 121 | "cell_type": "code",
|
111 | 122 | "execution_count": null,
|
112 |
| - "metadata": {}, |
| 123 | + "metadata": { |
| 124 | + "collapsed": true |
| 125 | + }, |
113 | 126 | "outputs": [],
|
114 | 127 | "source": [
|
115 | 128 | "# Demo 5 - Read a WFDB record and annotation. Plot all channels, and the annotation on top of channel 0.\n",
|
|
134 | 147 | {
|
135 | 148 | "cell_type": "code",
|
136 | 149 | "execution_count": null,
|
137 |
| - "metadata": {}, |
| 150 | + "metadata": { |
| 151 | + "collapsed": true |
| 152 | + }, |
138 | 153 | "outputs": [],
|
139 | 154 | "source": [
|
140 | 155 | "# Demo 6 - Read the multi-segment record and plot waveforms from the MIMIC matched waveform database. \n",
|
|
151 | 166 | {
|
152 | 167 | "cell_type": "code",
|
153 | 168 | "execution_count": null,
|
154 |
| - "metadata": {}, |
| 169 | + "metadata": { |
| 170 | + "collapsed": true |
| 171 | + }, |
155 | 172 | "outputs": [],
|
156 | 173 | "source": [
|
157 | 174 | "# Demo 7 - Read the multi-segment record and plot waveforms from the MIMIC matched waveform database.\n",
|
|
186 | 203 | {
|
187 | 204 | "cell_type": "code",
|
188 | 205 | "execution_count": null,
|
189 |
| - "metadata": {}, |
| 206 | + "metadata": { |
| 207 | + "collapsed": true |
| 208 | + }, |
190 | 209 | "outputs": [],
|
191 | 210 | "source": [
|
192 | 211 | "# Demo 8 - Read a wfdb record in which one channel has multiple samples/frame. Return a smoothed uniform array.\n",
|
|
197 | 216 | {
|
198 | 217 | "cell_type": "code",
|
199 | 218 | "execution_count": null,
|
200 |
| - "metadata": {}, |
| 219 | + "metadata": { |
| 220 | + "collapsed": true |
| 221 | + }, |
201 | 222 | "outputs": [],
|
202 | 223 | "source": [
|
203 | 224 | "# Demo 9 - Read a wfdb record in which one channel has multiple samples/frame. Return a list of all the expanded samples.\n",
|
|
220 | 241 | {
|
221 | 242 | "cell_type": "code",
|
222 | 243 | "execution_count": null,
|
223 |
| - "metadata": {}, |
| 244 | + "metadata": { |
| 245 | + "collapsed": true |
| 246 | + }, |
224 | 247 | "outputs": [],
|
225 | 248 | "source": [
|
226 | 249 | "# Demo 10 - Read a WFDB record's digital samples and create a copy via the wrsamp() instance method \n",
|
|
261 | 284 | {
|
262 | 285 | "cell_type": "code",
|
263 | 286 | "execution_count": null,
|
264 |
| - "metadata": {}, |
| 287 | + "metadata": { |
| 288 | + "collapsed": true |
| 289 | + }, |
265 | 290 | "outputs": [],
|
266 | 291 | "source": [
|
267 | 292 | "# Demo 12 - Write a WFDB record with multiple samples/frame in a channel\n",
|
|
280 | 305 | {
|
281 | 306 | "cell_type": "code",
|
282 | 307 | "execution_count": null,
|
283 |
| - "metadata": {}, |
| 308 | + "metadata": { |
| 309 | + "collapsed": true |
| 310 | + }, |
284 | 311 | "outputs": [],
|
285 | 312 | "source": [
|
286 | 313 | "# Demo 13 - Read a WFDB annotation file and create a copy via the wrann() instance method\n",
|
|
320 | 347 | {
|
321 | 348 | "cell_type": "code",
|
322 | 349 | "execution_count": null,
|
323 |
| - "metadata": {}, |
| 350 | + "metadata": { |
| 351 | + "collapsed": true |
| 352 | + }, |
324 | 353 | "outputs": [],
|
325 | 354 | "source": [
|
326 | 355 | "# Demo 15 - View what the 'anntype' symbols mean in the standard WFDB library\n",
|
|
341 | 370 | {
|
342 | 371 | "cell_type": "code",
|
343 | 372 | "execution_count": null,
|
344 |
| - "metadata": {}, |
| 373 | + "metadata": { |
| 374 | + "collapsed": true |
| 375 | + }, |
345 | 376 | "outputs": [],
|
346 | 377 | "source": [
|
347 | 378 | "# Demo 16 - List the Physiobank Databases\n",
|
|
353 | 384 | {
|
354 | 385 | "cell_type": "code",
|
355 | 386 | "execution_count": null,
|
356 |
| - "metadata": {}, |
| 387 | + "metadata": { |
| 388 | + "collapsed": true |
| 389 | + }, |
357 | 390 | "outputs": [],
|
358 | 391 | "source": [
|
359 | 392 | "# Demo 17 - Download all the WFDB records and annotations from a small Physiobank Database\n",
|
|
375 | 408 | {
|
376 | 409 | "cell_type": "code",
|
377 | 410 | "execution_count": null,
|
378 |
| - "metadata": {}, |
| 411 | + "metadata": { |
| 412 | + "collapsed": true |
| 413 | + }, |
379 | 414 | "outputs": [],
|
380 | 415 | "source": [
|
381 | 416 | "# Demo 18 - Download specified files from a Physiobank database\n",
|
|
398 | 433 | "display(os.listdir(os.path.join(dldir, 'data')))"
|
399 | 434 | ]
|
400 | 435 | },
|
| 436 | + { |
| 437 | + "cell_type": "markdown", |
| 438 | + "metadata": { |
| 439 | + "collapsed": true |
| 440 | + }, |
| 441 | + "source": [ |
| 442 | + "## ECG Peak Detection" |
| 443 | + ] |
| 444 | + }, |
| 445 | + { |
| 446 | + "cell_type": "code", |
| 447 | + "execution_count": null, |
| 448 | + "metadata": {}, |
| 449 | + "outputs": [], |
| 450 | + "source": [ |
| 451 | + "def peaks_hr(x, peak_indices, fs, title, figsize=(20, 10), saveto=None):\n", |
| 452 | + " \n", |
| 453 | + " # Calculate heart rate\n", |
| 454 | + " hrs = wfdb.processing.compute_hr(siglen=x.shape[0], peak_indices=peak_indices, fs=fs)\n", |
| 455 | + " \n", |
| 456 | + " N = x.shape[0]\n", |
| 457 | + " \n", |
| 458 | + " fig, ax_left = plt.subplots(figsize=figsize)\n", |
| 459 | + " ax_right = ax_left.twinx()\n", |
| 460 | + " \n", |
| 461 | + " ax_left.plot(x, color='#3979f0', label='Signal')\n", |
| 462 | + " ax_left.plot(peak_indices, x[peak_indices], 'rx', marker='x', color='#8b0000', label='Peak', markersize=12)\n", |
| 463 | + " ax_right.plot(np.arange(N), hrs, label='Heart rate', color='m', linewidth=2)\n", |
| 464 | + "\n", |
| 465 | + " ax_left.set_title(title)\n", |
| 466 | + "\n", |
| 467 | + " ax_left.set_xlabel('Time (ms)')\n", |
| 468 | + " ax_left.set_ylabel('ECG (mV)', color='#3979f0')\n", |
| 469 | + " ax_right.set_ylabel('Heart rate (bpm)', color='m')\n", |
| 470 | + " # Make the y-axis label, ticks and tick labels match the line color.\n", |
| 471 | + " ax_left.tick_params('y', colors='#3979f0')\n", |
| 472 | + " ax_right.tick_params('y', colors='m')\n", |
| 473 | + " if saveto is not None:\n", |
| 474 | + " plt.savefig(saveto, dpi=600)\n", |
| 475 | + " plt.show()\n", |
| 476 | + "\n", |
| 477 | + "\n", |
| 478 | + "recordname = 'sampledata/100'\n", |
| 479 | + "\n", |
| 480 | + "def gqrs_plot(recordname, t0=0, tf=10000):\n", |
| 481 | + " # Load the wfdb record and the physical samples\n", |
| 482 | + " record = wfdb.rdsamp(recordname, sampfrom=t0, sampto=tf, channels=[0])\n", |
| 483 | + " \n", |
| 484 | + " # Use the gqrs algorithm to find peaks in the first channel\n", |
| 485 | + " # The gqrs_detect argument expects a digital signal for the first argument.\n", |
| 486 | + " d_signal = record.adc()[:,0]\n", |
| 487 | + " peak_indices = wfdb.processing.gqrs_detect(d_signal, fs=record.fs, adcgain=record.adcgain[0], adczero=record.adczero[0], threshold=1.0)\n", |
| 488 | + " print('gqrs detected peak indices:', peak_indices)\n", |
| 489 | + " peaks_hr(x=record.p_signals, peak_indices=peak_indices, fs=record.fs, title=\"GQRS peak detection on sampledata/100\")\n", |
| 490 | + " \n", |
| 491 | + " # Do peak detection with constraints\n", |
| 492 | + " min_bpm = 20\n", |
| 493 | + " max_bpm = 230\n", |
| 494 | + " min_gap = record.fs*60/min_bpm\n", |
| 495 | + " max_gap = record.fs*60/max_bpm\n", |
| 496 | + " peak_indices = wfdb.processing.correct_peaks(d_signal, peak_indices=peak_indices, min_gap=min_gap, max_gap=max_gap, smooth_window=150)\n", |
| 497 | + " print('corrected gqrs detected peak indices:', sorted(peak_indices))\n", |
| 498 | + " peaks_hr(x=record.p_signals, peak_indices=sorted(peak_indices), fs=record.fs, title=\"Corrected GQRS peak detection on sampledata/100\")\n", |
| 499 | + "\n", |
| 500 | + "gqrs_plot(recordname)" |
| 501 | + ] |
| 502 | + }, |
401 | 503 | {
|
402 | 504 | "cell_type": "code",
|
403 | 505 | "execution_count": null,
|
|
0 commit comments