Repository navigation
Commit dda360e
authored
Support multi-segment records in .wfdb archive files (#583)
Follow-up to #541, which added `.wfdb` archive files for single-segment
records. This adds support for multi-segment records.
## 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. Finding the main header takes linear
time in the number of segments, whatever order the headers were added
in.
- 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.
- `set_defaults()` no longer fails for null signals: they get the WFDB
library's default resolution (12 bits), so a variable layout record
created from scratch can be written too. A record that mixes null
signals with signals that have samples is rejected with a clear error.
## Example
```python
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 new tests that write a variable layout record to
files and read it back (one read from `sample-data`, one created from
scratch), and that check the error for a record that mixes null signals
with other signals.
- An archive whose main header was added last is read correctly.
`p000878` isn't used in the archive tests, because one of its segments
is not included in `sample-data`.8 files changed
Lines changed: 622 additions & 133 deletions
File tree
- docs
- src/wfdb/io
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
79 | 82 | | |
80 | 83 | | |
81 | 84 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
77 | 79 | | |
78 | 80 | | |
79 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
251 | 251 | | |
252 | 252 | | |
253 | 253 | | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
254 | 281 | | |
255 | 282 | | |
256 | 283 | | |
| |||
580 | 607 | | |
581 | 608 | | |
582 | 609 | | |
583 | | - | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
| 610 | + | |
588 | 611 | | |
589 | 612 | | |
590 | 613 | | |
| |||
620 | 643 | | |
621 | 644 | | |
622 | 645 | | |
623 | | - | |
| 646 | + | |
624 | 647 | | |
625 | 648 | | |
626 | 649 | | |
| |||
633 | 656 | | |
634 | 657 | | |
635 | 658 | | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
636 | 662 | | |
637 | 663 | | |
638 | 664 | | |
| |||
655 | 681 | | |
656 | 682 | | |
657 | 683 | | |
658 | | - | |
| 684 | + | |
659 | 685 | | |
660 | 686 | | |
661 | 687 | | |
| |||
730 | 756 | | |
731 | 757 | | |
732 | 758 | | |
733 | | - | |
| 759 | + | |
734 | 760 | | |
735 | 761 | | |
736 | 762 | | |
| |||
740 | 766 | | |
741 | 767 | | |
742 | 768 | | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
743 | 772 | | |
744 | 773 | | |
745 | 774 | | |
| |||
774 | 803 | | |
775 | 804 | | |
776 | 805 | | |
777 | | - | |
| 806 | + | |
778 | 807 | | |
779 | 808 | | |
780 | 809 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
47 | 50 | | |
48 | 51 | | |
49 | 52 | | |
| |||
0 commit comments