Rework radar system
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"""JSON export keeps real stage data and never guesses across repeated sweep IDs."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from python_app.models.dataset_model import ComboKey, ResultCollection, SweepCollection, TraceData
|
||||
from python_app.storage.npz.vna_history_json import build_vna_history_payload
|
||||
|
||||
|
||||
def sweep(cid: int, ns: int, value: float, window: tuple[int, int] = (0, 0)) -> SweepCollection:
|
||||
trace = TraceData(
|
||||
ComboKey(0, 0), np.array([1e8, 2e8]), np.full(2, value, complex),
|
||||
capture_start_ns=window[0], capture_end_ns=window[1],
|
||||
)
|
||||
return SweepCollection(cid, ns, [trace], capture_start_ns=window[0], capture_end_ns=window[1])
|
||||
|
||||
|
||||
def payload(raw: list[SweepCollection], pre: list[SweepCollection], **kwargs):
|
||||
return build_vna_history_payload(raw, pre, [], input_index=0, output_index=0, **kwargs)
|
||||
|
||||
|
||||
class VnaHistoryJsonTest(unittest.TestCase):
|
||||
def test_missing_stage_is_empty_instead_of_fabricated(self) -> None:
|
||||
for stage in ("raw", "preprocessed"):
|
||||
with self.subTest(stage=stage):
|
||||
raw, pre = ([sweep(1, 100, 7)], []) if stage == "raw" else ([], [sweep(1, 110, 9)])
|
||||
history = payload(raw, pre)["sweep_history"]
|
||||
self.assertEqual(len(history), 1)
|
||||
self.assertEqual(history[0]["sweep_points"], [[7., 0.], [7., 0.]] if raw else [])
|
||||
self.assertEqual(history[0]["calibrated_points"], [[9., 0.], [9., 0.]] if pre else [])
|
||||
|
||||
def test_dropped_stages_and_reused_ids_preserve_every_trace_once(self) -> None:
|
||||
raw = [sweep(1, 100, 1, (80, 90)), sweep(1, 200, 2, (180, 190)), sweep(2, 300, 3, (280, 290))]
|
||||
pre = [sweep(1, 210, 20, (180, 190)), sweep(3, 410, 40, (380, 390))]
|
||||
for stage in ("raw", "preprocessed"):
|
||||
with self.subTest(primary=stage):
|
||||
history = payload(raw, pre, primary_stage=stage)["sweep_history"]
|
||||
self.assertEqual(len(history), 4)
|
||||
self.assertEqual([row["sweep_points"][0][0] if row["sweep_points"] else None for row in history], [1, 2, 3, None])
|
||||
self.assertEqual([row["calibrated_points"][0][0] if row["calibrated_points"] else None for row in history], [None, 20, None, 40])
|
||||
|
||||
def test_conflicting_windows_are_never_paired(self) -> None:
|
||||
history = payload([sweep(1, 100, 1, (80, 90))], [sweep(1, 110, 10, (81, 91))])["sweep_history"]
|
||||
self.assertEqual(len(history), 2)
|
||||
self.assertEqual(history[0]["calibrated_points"], [])
|
||||
self.assertEqual(history[1]["sweep_points"], [])
|
||||
|
||||
def test_export_timestamp_uses_selected_trace_in_a_switched_collection(self) -> None:
|
||||
pre = sweep(1, 200, 10, (100, 150))
|
||||
pre.capture_start_ns, pre.capture_end_ns = 1, 190
|
||||
history = payload([], [pre])["sweep_history"]
|
||||
self.assertEqual(history[0]["timestamp"], 150 / 1e9)
|
||||
|
||||
def test_join_uses_collection_window_and_capture_order_not_trace_or_stage_time(self) -> None:
|
||||
raw = sweep(1, 900, 1, (10, 20))
|
||||
pre = sweep(1, 1000, 10, (10, 20))
|
||||
pre.traces[0].capture_start_ns = 11
|
||||
pre.traces[0].capture_end_ns = 19
|
||||
fresh = sweep(1, 100, 2, (30, 40))
|
||||
history = payload([fresh, raw], [pre])["sweep_history"]
|
||||
self.assertEqual(len(history), 2)
|
||||
self.assertEqual(history[0]["sweep_points"], [[1., 0.], [1., 0.]])
|
||||
self.assertEqual(history[0]["calibrated_points"], [[10., 0.], [10., 0.]])
|
||||
self.assertEqual(history[0]["timestamp"], 19 / 1e9)
|
||||
self.assertEqual(history[1]["calibrated_points"], [])
|
||||
|
||||
def test_reordered_results_do_not_produce_an_alignment_warning(self) -> None:
|
||||
pre = [sweep(1, 110, 1, (10, 20)), sweep(2, 210, 2, (30, 40))]
|
||||
result = [ResultCollection(2, 999, capture_start_ns=30, capture_end_ns=40),
|
||||
ResultCollection(1, 888, capture_start_ns=10, capture_end_ns=20)]
|
||||
exported = build_vna_history_payload([], pre, result, input_index=0, output_index=0)
|
||||
self.assertNotIn("alignment_warning", exported)
|
||||
|
||||
def test_selected_combo_with_many_distinct_ids_has_no_lost_or_duplicated_records(self) -> None:
|
||||
raw = [sweep(cid, cid * 100, cid, (cid * 100 - 20, cid * 100 - 10)) for cid in range(1, 2001)]
|
||||
pre = [sweep(cid, cid * 100 + 10, cid * 2, (cid * 100 - 20, cid * 100 - 10)) for cid in range(1, 2001)]
|
||||
history = payload(raw, pre)["sweep_history"]
|
||||
self.assertEqual(len(history), 2000)
|
||||
self.assertEqual(history[-1]["sweep_points"][0][0], 2000)
|
||||
self.assertEqual(history[-1]["calibrated_points"][0][0], 4000)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user