Refactor radar system
This commit is contained in:
@@ -20,6 +20,7 @@ never see time jump backwards. ``collection_id`` increases forever.
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from contextlib import ExitStack
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
@@ -39,7 +40,7 @@ from python_app.storage.npz.serialize import RAW_MAGIC, serialize_trace_collecti
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_SNAPSHOT_NAME = re.compile(r"^\d+_id\d+_ns(\d+)$")
|
||||
_SNAPSHOT_NAME = re.compile(r"^(\d+)_id\d+_ns(\d+)$")
|
||||
|
||||
|
||||
class ReplayDataset:
|
||||
@@ -62,11 +63,11 @@ def _load_dataset(dataset_dir: Path, combos: list[ComboKey], expected_points: in
|
||||
if not dataset_dir.is_dir():
|
||||
raise RuntimeError(f"radar.replay.dataset_dir is not a directory: {dataset_dir}")
|
||||
|
||||
named: list[tuple[str, int]] = []
|
||||
for entry in sorted(dataset_dir.iterdir()):
|
||||
named: list[tuple[int, str, int]] = []
|
||||
for entry in dataset_dir.iterdir():
|
||||
match = _SNAPSHOT_NAME.match(entry.name)
|
||||
if entry.is_dir() and match:
|
||||
named.append((entry.name, int(match.group(1))))
|
||||
named.append((int(match.group(1)), entry.name, int(match.group(2))))
|
||||
if not named:
|
||||
raise RuntimeError(
|
||||
f"No snapshot folders (NNNN_idK_ns<ts>) found in {dataset_dir}"
|
||||
@@ -74,7 +75,7 @@ def _load_dataset(dataset_dir: Path, combos: list[ComboKey], expected_points: in
|
||||
|
||||
snapshots: list[list[TraceData]] = []
|
||||
timestamps_ns: list[int] = []
|
||||
for name, timestamp_ns in named:
|
||||
for _, name, timestamp_ns in sorted(named):
|
||||
folder = dataset_dir / name
|
||||
# Recorded per-trace capture windows from the snapshot's meta.json: the
|
||||
# sar3d segmented timing model reconstructs the acquisition segments
|
||||
@@ -102,10 +103,12 @@ def _load_dataset(dataset_dir: Path, combos: list[ComboKey], expected_points: in
|
||||
f"input={combo.input} output={combo.output}: expected "
|
||||
f"{s21_path.name} and {freq_path.name}. Check run.combos vs the dataset."
|
||||
)
|
||||
s21 = np.load(s21_path).astype(np.complex64, copy=False)
|
||||
freq = np.load(freq_path).astype(np.float32, copy=False)
|
||||
if s21.size != freq.size:
|
||||
raise RuntimeError(f"{s21_path}: s21 size {s21.size} != freq size {freq.size}")
|
||||
s21 = np.load(s21_path, allow_pickle=False).astype(np.complex64, copy=False)
|
||||
freq = np.load(freq_path, allow_pickle=False).astype(np.float32, copy=False)
|
||||
s11_path = folder / f"i{combo.input}_o{combo.output}_s11.npy"
|
||||
s11 = np.load(s11_path, allow_pickle=False).astype(np.complex64, copy=False) if s11_path.is_file() else np.zeros_like(s21)
|
||||
if freq.ndim != 1 or s21.shape != freq.shape or s11.shape != freq.shape:
|
||||
raise RuntimeError(f"Snapshot {name}: frequency, S11 and S21 must be equally sized 1D arrays")
|
||||
if expected_points and s21.size != expected_points:
|
||||
raise RuntimeError(
|
||||
f"{s21_path}: {s21.size} points, but radar.sweep.points = "
|
||||
@@ -116,7 +119,7 @@ def _load_dataset(dataset_dir: Path, combos: list[ComboKey], expected_points: in
|
||||
TraceData(
|
||||
combo=combo,
|
||||
frequency_hz=freq,
|
||||
s11=np.zeros_like(s21),
|
||||
s11=s11,
|
||||
s21=s21,
|
||||
capture_start_ns=window[0],
|
||||
capture_end_ns=window[1],
|
||||
@@ -206,25 +209,34 @@ def main() -> int:
|
||||
dataset.median_gap_ns / 1e9, replay.loop, rate_scale,
|
||||
)
|
||||
|
||||
raw_writer = ShmRingWriter(
|
||||
config.rings.raw.name,
|
||||
config.rings.raw.capacity,
|
||||
config.rings.raw.slot_size_bytes,
|
||||
)
|
||||
raw_tap_writer = ShmRingWriter(
|
||||
config.rings.raw_tap.name,
|
||||
config.rings.raw_tap.capacity,
|
||||
config.rings.raw_tap.slot_size_bytes,
|
||||
)
|
||||
|
||||
cleanup = ExitStack()
|
||||
try:
|
||||
raw_writer = ShmRingWriter(
|
||||
config.rings.raw.name,
|
||||
config.rings.raw.capacity,
|
||||
config.rings.raw.slot_size_bytes,
|
||||
)
|
||||
cleanup.callback(raw_writer.close)
|
||||
raw_tap_writer = ShmRingWriter(
|
||||
config.rings.raw_tap.name,
|
||||
config.rings.raw_tap.capacity,
|
||||
config.rings.raw_tap.slot_size_bytes,
|
||||
)
|
||||
cleanup.callback(raw_tap_writer.close)
|
||||
|
||||
payload_size = len(serialize_trace_collection(
|
||||
_build_collection(dataset, 0, 1, time.monotonic_ns()), RAW_MAGIC
|
||||
))
|
||||
for ring in (config.rings.raw, config.rings.raw_tap):
|
||||
if ring.slot_size_bytes < payload_size:
|
||||
raise ValueError(f"Replay requires {payload_size} bytes per slot; ring {ring.name} has {ring.slot_size_bytes}")
|
||||
|
||||
base_ns = time.monotonic_ns()
|
||||
wall_start_s = time.monotonic()
|
||||
first_ts = dataset.timestamps_ns[0]
|
||||
cycle_span_ns = dataset.timestamps_ns[-1] - first_ts + dataset.median_gap_ns
|
||||
|
||||
collection_id = 1
|
||||
publish_failures = 0
|
||||
cycle = 0
|
||||
while not stop_requested.is_set():
|
||||
for index in range(len(dataset)):
|
||||
@@ -246,15 +258,9 @@ def main() -> int:
|
||||
|
||||
collection = _build_collection(dataset, index, collection_id, frame_ns)
|
||||
payload = serialize_trace_collection(collection, RAW_MAGIC)
|
||||
if raw_writer.push(payload):
|
||||
raw_tap_writer.push(payload) # best-effort GUI tap; never fatal
|
||||
else:
|
||||
publish_failures += 1
|
||||
if publish_failures == 1 or publish_failures % 100 == 0:
|
||||
logger.error(
|
||||
"Replay payload %d B exceeds ring slot %d B; dropping collection %d (drops=%d)",
|
||||
len(payload), raw_writer.slot_size_bytes, collection_id, publish_failures,
|
||||
)
|
||||
if not raw_writer.push(payload):
|
||||
raise RuntimeError(f"Replay raw ring rejected collection {collection_id}")
|
||||
raw_tap_writer.push(payload)
|
||||
if collection_id == 1 or collection_id % 50 == 0:
|
||||
logger.info(
|
||||
"replay collection %d published (snapshot %d/%d, cycle %d)",
|
||||
@@ -268,8 +274,7 @@ def main() -> int:
|
||||
break
|
||||
cycle += 1
|
||||
finally:
|
||||
raw_tap_writer.close()
|
||||
raw_writer.close()
|
||||
cleanup.close()
|
||||
|
||||
logger.info("replay raw producer stopped")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user