Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 38 additions & 61 deletions notebooks/02_benchmark_parsing.ipynb

Large diffs are not rendered by default.

31 changes: 3 additions & 28 deletions src/fasteit/parsers/draeger/bin/bin_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@
from fasteit.parsers.errors import AmbiguousFormatError, UnsupportedFrameSizeError

from .bin_utils import (
_BIT_SENTINELS,
_FLOAT_SENTINELS,
estimate_sampling_frequency_hz,
normalize_frame_slice,
replace_no_data_sentinels,
)

# Default sampling frequency used when fs cannot be estimated from timestamps.
Expand All @@ -43,10 +40,6 @@ class DragerBinParser(BaseParser):
https://github.com/EIT-ALIVE/eitprocessing
"""

def __init__(self) -> None:
self._float_sentinels = _FLOAT_SENTINELS
self._bit_sentinels = _BIT_SENTINELS

def validate(self, path: Path) -> bool:
"""Return True if file exists, is non-empty, and has a known frame size."""
path = Path(path)
Expand Down Expand Up @@ -119,35 +112,17 @@ def parse(
else:
warnings_list = []

# ── 6. Copy memmap to writable array ──────────────────────────────────
frames = mapped_frames.copy()

# ── 7. Sanitize pixels: vectorized over all frames at once ────────────
frames["pixels"] = replace_no_data_sentinels(
mapped_frames["pixels"],
self._float_sentinels,
self._bit_sentinels,
)

# ── 8. Sanitize Medibus data if present (EXT format only) ─────────────
if spec.medibus_fields is not None:
frames["medibus_data"] = replace_no_data_sentinels(
frames["medibus_data"],
self._float_sentinels,
self._bit_sentinels,
)

# ── 9. Build aux_signals dict: {signal_name → array shape (N,)} ──────
# ── 6. Build aux_signals dict: {signal_name → array shape (N,)} ──────
aux_signals = None
if spec.medibus_fields is not None:
aux_signals = {
field_name: frames["medibus_data"][:, field_idx]
field_name: mapped_frames["medibus_data"][:, field_idx]
for field_idx, field_name in enumerate(spec.medibus_fields)
}

# ── 10. Assemble and return result ────────────────────────────────────
result = ReconstructedFrameData(
frames=frames,
frames=mapped_frames,
aux_signals=aux_signals,
fs=fs,
filename=str(path),
Expand Down
11 changes: 7 additions & 4 deletions tests/test_bin_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@ def test_parse_slice_max_frames(tmp_path):
# ── float sentinel replacement ────────────────────────────────────────────────


def test_parse_float_sentinel_replaced_with_nan(tmp_path):
def test_parse_float_sentinel_preserved_in_raw_data(tmp_path):
"""Parser returns raw memmap — sentinel values are NOT replaced.

Sentinel replacement is deferred to the preprocessing layer so that
the memmap is never copied to RAM during parsing (lazy loading).
"""
frames = np.zeros(3, dtype=FRAME_BASE_DTYPE)
dt_day = 1.0 / (50.0 * 86400.0)
frames["ts"] = np.arange(3) * dt_day
Expand All @@ -134,12 +139,10 @@ def test_parse_float_sentinel_replaced_with_nan(tmp_path):
frames.tofile(path)

data = DragerBinParser().parse(path)
assert np.isnan(data.pixels[1, 0, 0])
assert data.pixels[1, 0, 0] == -1000.0


# ── Round-trip value correctness (Tasks 1.5.3 / 1.5.4 / 1.5.5 / 1.5.10) ─────
# Uses the shared bin_3frames fixture from conftest.py.
# Frame i has all pixels = float(i+1), timestamps at 50 Hz fraction-of-day.

_DT_DAY = 1.0 / (50.0 * 86400.0)

Expand Down
Loading