wfdb-python icon indicating copy to clipboard operation
wfdb-python copied to clipboard

WIP: Add support for reading and writing .wfdb archive files

Open tompollard opened this issue 7 months ago • 0 comments

As discussed in https://github.com/wfdb/wfdb-spec/issues/21 and https://github.com/MIT-LCP/wfdb-python/issues/540 we would like to allow WFDB Records to be saved to a single file .wfdb.

This pull request introduces support for reading and writing .wfdb archive files, a ZIP-based format that stores .hea, .dat, and related files in a single container.

Implementation

  • Adds WFDBArchive class to handle reading/writing of .wfdb archives
  • Archives are implemented as uncompressed ZIP files for maximum simplicity
  • Two ways to create archives:
    1. Inline creation via wrsamp(..., wfdb_archive=...) which writes files directly to the archive
    2. Two-step creation via wrsamp(...) followed by WFDBArchive.create_archive(...) which writes files to disk first
  • Adds support for reading records directly from .wfdb archives via rdrecord()
  • Adds tests covering:
    • Round-trip read/write of archives
    • Reading subset of channels
    • Reading partial samples
    • Error handling for missing files
    • Both inline and two-step archive creation methods

Example usage

import wfdb
from wfdb.io.archive import WFDBArchive
import numpy as np

# 1. Read an existing WFDB record
record = wfdb.rdrecord('sample-data/test01_00s')

# 2. Convert physical signals to digital signals
#     Side note, but this shouldn't be necessary.
#     ...or at least the write error should be clearer.
record.d_signal = record.adc()

# 3. Write the record to the archive
record.wrsamp(wfdb_archive="new_archive.wfdb")

# 4. Read back from the archive
archive_record = wfdb.rdrecord('new_archive.wfdb')

# 5. Verify the data matches
assert record.fs == archive_record.fs
assert record.n_sig == archive_record.n_sig
assert record.sig_name == archive_record.sig_name
assert record.units == archive_record.units
assert record.p_signal.shape == archive_record.p_signal.shape

tompollard avatar May 03 '25 19:05 tompollard