Refactor radar system

This commit is contained in:
Ayzen
2026-10-05 16:46:28 +03:00
parent 515049d2ed
commit 8f097dfa2e
179 changed files with 8212 additions and 6676 deletions
@@ -1,4 +1,4 @@
"""Tests for Kamil ADC neutral preprocessing-set generation."""
"""Neutral preprocessing grids must preserve the actual radar data unchanged."""
from __future__ import annotations
@@ -6,8 +6,9 @@ import unittest
import numpy as np
from python_app.hardware_full.point_target_mock_service import PointTargetMockService
from python_app.models.run_config_model import RunConfigModel
from python_app.workflows.kamil_adc_neutral_preprocess import build_kamil_adc_neutral_s21_sets
from python_app.workflows.kamil_adc_neutral_preprocess import build_neutral_s21_sets, supports_neutral_preprocess_sets
def _kamil_config(*, points: int = 5) -> RunConfigModel:
@@ -27,7 +28,7 @@ def _kamil_config(*, points: int = 5) -> RunConfigModel:
class KamilAdcNeutralPreprocessTest(unittest.TestCase):
def test_builds_passthrough_s21_sets_on_band_grid(self) -> None:
calibration, reference = build_kamil_adc_neutral_s21_sets(_kamil_config(points=5))
calibration, reference = build_neutral_s21_sets(_kamil_config(points=5))
expected_frequency = np.linspace(2_100_000_000.0, 5_500_000_000.0, 5).astype(np.float32)
self.assertEqual(len(calibration.traces), 2)
@@ -53,20 +54,15 @@ class KamilAdcNeutralPreprocessTest(unittest.TestCase):
config = _kamil_config(points=17)
processor = KamilAdcSweepProcessor(KamilAdcProcessingParams.from_kamil_model(config.radar.kamil_adc))
calibration, _reference = build_kamil_adc_neutral_s21_sets(config)
calibration, _reference = build_neutral_s21_sets(config)
np.testing.assert_array_equal(calibration.traces[0].frequency_hz, processor.grid_hz)
def test_rejects_non_kamil_config(self) -> None:
config = RunConfigModel.from_dict({"radar": {"model": "librevna"}})
with self.assertRaisesRegex(ValueError, "kamil_adc"):
build_kamil_adc_neutral_s21_sets(config)
def test_rejects_degenerate_band(self) -> None:
with self.assertRaisesRegex(ValueError, "points must be >= 2"):
build_kamil_adc_neutral_s21_sets(_kamil_config(points=1))
build_neutral_s21_sets(_kamil_config(points=1))
def test_dtypes_are_float32_and_complex64(self) -> None:
calibration, _reference = build_kamil_adc_neutral_s21_sets(_kamil_config())
calibration, _reference = build_neutral_s21_sets(_kamil_config())
trace = calibration.traces[0]
self.assertEqual(trace.frequency_hz.dtype, np.float32)
self.assertEqual(trace.s21.dtype, np.complex64)
@@ -75,10 +71,29 @@ class KamilAdcNeutralPreprocessTest(unittest.TestCase):
def test_calibration_s21_is_a_nonzero_divisor(self) -> None:
# The C++ through-calibrator divides measured/calibration, so calibration S21
# must never be zero — that is the whole point of the '1+0j neutral' contract.
calibration, _reference = build_kamil_adc_neutral_s21_sets(_kamil_config())
calibration, _reference = build_neutral_s21_sets(_kamil_config())
for trace in calibration.traces:
self.assertTrue(bool(np.all(trace.s21 != 0)))
def test_single_mock_grid_is_exact_and_neutral_s21_is_passthrough(self) -> None:
config = RunConfigModel.from_dict({"radar": {
"model": "librevna", "driver_mode": "mock",
"sweep": {"start_hz": 1e6, "stop_hz": 6e9, "points": 201},
}})
self.assertTrue(supports_neutral_preprocess_sets(config))
radar = PointTargetMockService(config)
radar.configure(config.radar.sweep)
measured = radar.acquire_collection()
calibration, reference = build_neutral_s21_sets(config)
for trace, cal, ref in zip(measured.traces, calibration.traces, reference.traces):
np.testing.assert_array_equal(trace.frequency_hz, cal.frequency_hz)
np.testing.assert_array_equal(trace.frequency_hz, ref.frequency_hz)
np.testing.assert_array_equal(trace.s21 / cal.s21 - ref.s21, trace.s21)
def test_native_single_axis_remains_outside_verified_shortcut(self) -> None:
config = RunConfigModel.from_dict({"radar": {"model": "librevna", "driver_mode": "native"}})
self.assertFalse(supports_neutral_preprocess_sets(config))
if __name__ == "__main__":
unittest.main()