Skip to content

WIP: Support multi-segment records in .wfdb archive files - #583

Draft
tompollard wants to merge 2 commits into
tp/wfdb_filefrom
tp/wfdb_file_multiseg
Draft

tompollard wants to merge 2 commits into
tp/wfdb_filefrom
tp/wfdb_file_multiseg

Conversation

@tompollard

Copy link
Copy Markdown
Member

Follow-up to #541, which adds .wfdb archive files for single-segment records. This adds support for multi-segment records. It targets the tp/wfdb_file branch and should be rebased onto main once #541 is merged.

Changes

  1. Multi-segment records in archives. The archive of a multi-segment record holds the main header together with the header and signal files of each segment.
    • rdrecord, rdsamp and rdheader (with rd_segments=True) read the segments from the same open archive. This covers fixed and variable layouts, empty segments (~), sample ranges, channels, channel_names and m2s=False.
    • MultiRecord.wrsamp takes a wfdb_archive argument and writes the whole record into one archive.
    • An archive still holds a single record. It can contain several headers only if one is a multi-segment header that lists all the others as its segments (including the layout header). This is now checked when the archive is closed, so files can be added in any order, and an archive that breaks the rule is not saved.
    • Segments can share a signal file (as in sample-data/multi-segment/fixed1), so writing a file that is already in the archive is allowed if the content is the same.
    • Small fix: reading a fixed-layout record with channel_names now takes the signal names from the first non-empty segment, as the code intended, instead of the first segment, which can be empty.
  2. Writing variable layout records. This fixes an existing bug that also affects writing to normal files. MultiRecord.wrsamp failed for variable layout records, such as those read with rdrecord(..., m2s=False). The layout header lists its signals as null signals (format 0, file name ~), which the header validation rejected, and Record.wrsamp tried to compute checksums and write .dat files for signals without samples. Null signals are now accepted, and only the header is written for a record whose signals have no files.

Example

import wfdb
from wfdb.io.archive import create_archive

# Write a multi-segment record into an archive
record = wfdb.rdrecord(
    "sample-data/multi-segment/s25047/s25047-2704-05-04-10-44",
    m2s=False,
    physical=False,
)
record.wrsamp(wfdb_archive="s25047.wfdb")

# Read it back, as a single record or as segments
signal = wfdb.rdrecord("s25047.wfdb", channel_names=["ABP", "II"])
segments = wfdb.rdrecord("s25047.wfdb", m2s=False)
header = wfdb.rdheader("s25047.wfdb", rd_segments=True)

Tests

  • Records read from archives are compared with the same records read from files, for the fixed and variable layout samples in sample-data/multi-segment. This includes sample ranges, channel selection and m2s=False.
  • Multi-segment records written into archives read back the same as the original files, and contain exactly the record's files.
  • Error cases: a missing segment, and an archive with a header that isn't one of the record's segments.
  • test_record.py has a new test that writes a variable layout record to files and reads it back.

p000878 isn't used in the archive tests, because one of its segments is not included in sample-data.

The archive of a multi-segment record holds the main header together
with the header and signal files of each segment. rdrecord, rdsamp and
rdheader (with rd_segments) read the segments from the same open
archive, and MultiRecord.wrsamp takes a wfdb_archive argument to write
the whole record into one archive.

An archive still holds a single record: it can contain several headers
only if one is a multi-segment header listing all the others as its
segments. This is now checked when the archive is closed, so files can
be added in any order. Writing a file that is already in the archive
is allowed if the content is the same, since segments can share a
signal file.

Reading a fixed-layout record with channel_names now uses the first
non-empty segment for the signal names, as intended, instead of the
first segment, which can be empty.
The layout header of a variable layout multi-segment record lists its
signals as null signals (format 0, file name '~'), with no samples.
Writing such a record failed: the header validation rejected format 0
and the file name '~', and Record.wrsamp tried to compute checksums and
write dat files for signals with no data.

Null signals are now accepted (file name '~' together with format 0),
and only the header is written for a record whose signals have no
files. This applies to records written to files as well as to .wfdb
archives.
@tompollard
tompollard force-pushed the tp/wfdb_file_multiseg branch from 75c188c to 680c727 Compare October 29, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant