Add RFG UDP source to rph_radar
This commit is contained in:
@@ -5,7 +5,7 @@ import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from python_app.hardware_full.rph_radar.protocol import RphRadarStreamParser
|
||||
from python_app.hardware_full.rph_radar.protocol import RfgSweepAssembler, RphRadarStreamParser
|
||||
|
||||
|
||||
def packet(*, source_id=1, cycle_id=1, start=100, end=200, combo=(1, 2), dirty=0, points=None):
|
||||
@@ -65,5 +65,80 @@ class RphRadarStreamParserTest(unittest.TestCase):
|
||||
self.assertTrue(sweep.dirty)
|
||||
|
||||
|
||||
def rfg_datagram(sweep_id, *steps, values=(3, 1, 5, 4, 2, 6), q_shift=27):
|
||||
"""RFG SWEEP_AVG datagram; ``values`` are in units of 2**(q_shift - 7)."""
|
||||
return struct.pack("<HH", 6, q_shift) + b"".join(
|
||||
struct.pack("<I6i", (sweep_id << 24) | step, *[value << (q_shift - 7) for value in values]) for step in steps)
|
||||
|
||||
|
||||
class RfgSweepAssemblerTest(unittest.TestCase):
|
||||
STEP_NS = 50_000
|
||||
PERIOD_NS = 20_000_000
|
||||
|
||||
def feed(self, assembler, sweep_id, steps, start_ns, delay_ns=7_000):
|
||||
sweeps = []
|
||||
for step in steps:
|
||||
sweeps += assembler.feed(rfg_datagram(sweep_id, step), start_ns + (step + 1) * self.STEP_NS + delay_ns)
|
||||
return sweeps
|
||||
|
||||
def test_complete_sweep_maps_sync_detector_and_reference_and_its_true_window(self):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
self.feed(assembler, 9, [0, 1, 2], 1_000_000_000)
|
||||
(sweep,) = assembler.feed(rfg_datagram(10, 0), 1_020_000_000)
|
||||
self.assertFalse(sweep.dirty)
|
||||
self.assertEqual(sweep.steps.tolist(), [0, 1, 2])
|
||||
np.testing.assert_allclose(sweep.main, [(3 - 1 + 1j * (4 - 2)) / 128] * 3) # ch0 - ch1
|
||||
np.testing.assert_allclose(sweep.reference, [(5 + 6j) / 128] * 3) # ch2
|
||||
self.assertEqual(sweep.capture_start_ns, 1_000_007_000)
|
||||
self.assertEqual(sweep.capture_end_ns - sweep.capture_start_ns, 3 * self.STEP_NS)
|
||||
|
||||
def test_window_takes_the_least_delayed_point_when_the_board_batches(self):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
start = 2_000_000_000
|
||||
assembler.feed(rfg_datagram(1, 0, 1), start + 2 * self.STEP_NS + 10_000) # steps 0-1 batched
|
||||
assembler.feed(rfg_datagram(1, 2), start + 3 * self.STEP_NS + 10_000)
|
||||
(sweep,) = assembler.feed(rfg_datagram(2, 0), start + 30_000_000)
|
||||
self.assertEqual(sweep.capture_start_ns, start + 10_000)
|
||||
|
||||
def test_points_of_older_sweeps_are_ignored_until_the_id_space_could_have_wrapped(self):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
sweeps = []
|
||||
for sweep_id, start in ((1, 0), (3, 20_000_000), (2, 40_000_000), (4, 60_000_000), (3, 80_000_000)):
|
||||
sweeps += self.feed(assembler, sweep_id, [0, 1, 2], start)
|
||||
self.assertEqual([sweep.source_id for sweep in sweeps], [1, 2]) # late 2 and replayed 3 are dropped
|
||||
sweeps = self.feed(assembler, 2, [0, 1, 2], 80_000_000 + 128 * self.PERIOD_NS) # 4 closes, 2 is new
|
||||
sweeps += self.feed(assembler, 3, [0], 100_000_000 + 128 * self.PERIOD_NS)
|
||||
self.assertEqual([(sweep.source_id, sweep.dirty) for sweep in sweeps], [(3, False), (4, False)])
|
||||
|
||||
def test_reset_turns_the_rest_of_the_sweep_in_progress_dirty(self):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
self.feed(assembler, 4, [0], 0)
|
||||
assembler.reset()
|
||||
self.feed(assembler, 4, [1, 2], 0)
|
||||
(sweep,) = self.feed(assembler, 5, [0], 20_000_000)
|
||||
self.assertTrue(sweep.dirty)
|
||||
|
||||
def test_partial_gapped_shortened_or_reordered_sweeps_are_dirty(self):
|
||||
for steps in ([1, 2], [0, 2], [0, 1], [0, 2, 1], [0, 1, 1, 2]):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
self.feed(assembler, 255, steps, 0)
|
||||
with self.subTest(steps=steps):
|
||||
(sweep,) = assembler.feed(rfg_datagram(0, 0), 10_000_000) # 255 -> 0 wraps normally
|
||||
self.assertTrue(sweep.dirty)
|
||||
|
||||
def test_a_reused_id_after_an_outage_does_not_splice_two_sweeps(self):
|
||||
assembler = RfgSweepAssembler(steps=3, step_ns=self.STEP_NS, period_ns=self.PERIOD_NS)
|
||||
self.feed(assembler, 5, [0], 0)
|
||||
self.feed(assembler, 5, [1, 2], 4_920_000_000) # 256 sweep periods later
|
||||
(sweep,) = self.feed(assembler, 6, [0], 4_940_000_000)
|
||||
self.assertTrue(sweep.dirty)
|
||||
|
||||
def test_unexpected_layout_fails_fast(self):
|
||||
for datagram in (b"\x06", struct.pack("<HH", 5, 27), struct.pack("<HH", 6, 31) + rfg_datagram(1, 0)[4:],
|
||||
rfg_datagram(1, 0)[:-1]):
|
||||
with self.subTest(datagram=datagram), self.assertRaisesRegex(ValueError, "protocol"):
|
||||
RfgSweepAssembler(steps=3, step_ns=1, period_ns=1).feed(datagram, 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user