mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-06-08 22:47:16 +00:00
chore(repo): cosim_dir replay revival + ruff lint cleanup
cosim_dir revival:
- gen_realdata_hex.py: also emit decimated_range_{i,q}.npy (48x512)
and doppler_map_{i,q}.npy (512x48) at production dimensions; the
same Python pipeline that produces the RTL .hex stimuli now writes
the .npy intermediates v7.replay COSIM_DIR loads. Replaces the
workflow lost when golden_reference.py was deleted in e8b495c
- test_v7.py: update test_get_frame_cosim shape from pre-PR-O.6
(64,32) to (NUM_RANGE_BINS, NUM_DOPPLER_BINS)
- check in 4 .npy reference files (~400 KB, deterministic SCENE_SEED=42)
Ruff lint cleanup (was 66 errors; now 0):
- pyproject.toml: ignore T20 in tb/cosim/**.py (CLI tools)
- compare_independent.py: drop redundant int() casts (RUF046),
swap try/except scipy import for importlib.util.find_spec,
remove dead duplicate np import, ASCII-ize comment unicode,
wrap E501 format strings
- fpga_reference.py: drop unused fs arg from nco_reference,
collapse if/else to ternary, mark _out_im unused
- v7/processing.py: ASCII-ize x in docstring, collapse if-branches
- {dashboard,software_fpga,workers,radar_protocol}.py: wrap E501
- test_v7.py: ASCII-ize comment unicode, _alias renames where unused
Result: test_v7 100/100 (0 skips on radar_venv, was 9 graceful
skips); 5 cosim_dir orphan tests now active and passing.
This commit is contained in:
@@ -68,7 +68,7 @@ DATA_PACKET_SIZE = 11 # 1 + 4 + 2 + 2 + 1 + 1
|
||||
STATUS_PACKET_SIZE = 26 # 1 + 24 + 1
|
||||
|
||||
NUM_RANGE_BINS = 512
|
||||
NUM_DOPPLER_BINS = 48 # PR-F/PR-Q: 3 sub-frames * 16 (matches FPGA RP_NUM_DOPPLER_BINS)
|
||||
NUM_DOPPLER_BINS = 48 # PR-F/PR-Q: 3 sub-frames * 16 (= FPGA RP_NUM_DOPPLER_BINS)
|
||||
NUM_CELLS = NUM_RANGE_BINS * NUM_DOPPLER_BINS # 24576
|
||||
|
||||
WATERFALL_DEPTH = 64
|
||||
|
||||
@@ -483,7 +483,7 @@ class TestWaveformConfig(unittest.TestCase):
|
||||
from v7.models import WaveformConfig
|
||||
wc = WaveformConfig()
|
||||
# MEDIUM has the largest per-subframe v_unamb (smallest PRI).
|
||||
# K=6 default → ~266 m/s; well above UAS speeds 50–80 m/s.
|
||||
# K=6 default -> ~266 m/s; well above UAS speeds 50-80 m/s.
|
||||
v6 = wc.extended_max_velocity_mps_crt()
|
||||
self.assertAlmostEqual(v6, wc.max_velocity_medium_mps * 6, places=2)
|
||||
# K=3 should give half of K=6.
|
||||
@@ -669,7 +669,7 @@ class TestSoftwareFPGASignalChain(unittest.TestCase):
|
||||
from v7.software_fpga import SoftwareFPGA
|
||||
from radar_protocol import NUM_RANGE_BINS, NUM_DOPPLER_BINS
|
||||
|
||||
# Production dimensions: 48 chirps × 2048 samples.
|
||||
# Production dimensions: 48 chirps x 2048 samples.
|
||||
iq_i = np.zeros((NUM_DOPPLER_BINS, 2048), dtype=np.int64)
|
||||
iq_q = np.zeros((NUM_DOPPLER_BINS, 2048), dtype=np.int64)
|
||||
# Inject a single strong tone in bin 10 of every chirp.
|
||||
@@ -803,12 +803,12 @@ class TestReplayEngineCosim(unittest.TestCase):
|
||||
if not self._available():
|
||||
self.skipTest("co-sim data not found")
|
||||
from v7.replay import ReplayEngine
|
||||
from radar_protocol import RadarFrame
|
||||
from radar_protocol import RadarFrame, NUM_RANGE_BINS, NUM_DOPPLER_BINS
|
||||
engine = ReplayEngine(self.COSIM_DIR)
|
||||
frame = engine.get_frame(0)
|
||||
self.assertIsInstance(frame, RadarFrame)
|
||||
self.assertEqual(frame.range_doppler_i.shape, (64, 32))
|
||||
self.assertEqual(frame.magnitude.shape, (64, 32))
|
||||
self.assertEqual(frame.range_doppler_i.shape, (NUM_RANGE_BINS, NUM_DOPPLER_BINS))
|
||||
self.assertEqual(frame.magnitude.shape, (NUM_RANGE_BINS, NUM_DOPPLER_BINS))
|
||||
|
||||
def test_get_frame_out_of_range(self):
|
||||
if not self._available():
|
||||
@@ -849,7 +849,7 @@ class TestReplayEngineRawIQ(unittest.TestCase):
|
||||
from v7.software_fpga import SoftwareFPGA
|
||||
from radar_protocol import RadarFrame, NUM_RANGE_BINS, NUM_DOPPLER_BINS
|
||||
|
||||
# Production dimensions: 48 chirps × 2048 samples per frame.
|
||||
# Production dimensions: 48 chirps x 2048 samples per frame.
|
||||
raw = (np.random.randn(2, NUM_DOPPLER_BINS, 2048)
|
||||
+ 1j * np.random.randn(2, NUM_DOPPLER_BINS, 2048))
|
||||
with tempfile.NamedTemporaryFile(suffix=".npy", delete=False) as f:
|
||||
@@ -1082,7 +1082,7 @@ class TestUnfoldVelocityCRT(unittest.TestCase):
|
||||
v_unamb, v_res = self._vu_vr()
|
||||
v_true = -75.0
|
||||
v_meas = [_fold_v(v_true, vu) for vu in v_unamb]
|
||||
v_est, conf, alias = unfold_velocity_crt(v_meas, v_unamb, v_res)
|
||||
v_est, conf, _alias = unfold_velocity_crt(v_meas, v_unamb, v_res)
|
||||
self.assertAlmostEqual(v_est, v_true, places=1)
|
||||
self.assertEqual(conf, "CONFIRMED")
|
||||
|
||||
@@ -1105,7 +1105,7 @@ class TestUnfoldVelocityCRT(unittest.TestCase):
|
||||
v_true = 25.0
|
||||
# SHORT + MEDIUM only (LONG dropped out, e.g. clutter).
|
||||
v_meas = [_fold_v(v_true, v_unamb[0]), _fold_v(v_true, v_unamb[1])]
|
||||
v_est, conf, alias = unfold_velocity_crt(
|
||||
v_est, conf, _alias = unfold_velocity_crt(
|
||||
v_meas, [v_unamb[0], v_unamb[1]], [v_res[0], v_res[1]],
|
||||
)
|
||||
self.assertAlmostEqual(v_est, v_true, places=1)
|
||||
@@ -1117,7 +1117,7 @@ class TestUnfoldVelocityCRT(unittest.TestCase):
|
||||
v_unamb, v_res = self._vu_vr()
|
||||
# Random per-PRI values that do not correspond to any v_true.
|
||||
v_meas = [10.0, -30.0, 35.0]
|
||||
v_est, conf, alias = unfold_velocity_crt(v_meas, v_unamb, v_res)
|
||||
v_est, conf, _alias = unfold_velocity_crt(v_meas, v_unamb, v_res)
|
||||
self.assertEqual(conf, "AMBIGUOUS")
|
||||
self.assertAlmostEqual(v_est, 10.0, places=2) # PRI-0 fallback
|
||||
|
||||
@@ -1130,7 +1130,7 @@ class TestUnfoldVelocityCRT(unittest.TestCase):
|
||||
# Pick v_true near the advertised CRT ceiling.
|
||||
v_true = wc.extended_max_velocity_mps_crt(max_alias_k=6) - 5.0 # ~261 m/s
|
||||
v_meas = [_fold_v(v_true, vu) for vu in v_unamb]
|
||||
v_est, conf, alias = unfold_velocity_crt(v_meas, v_unamb, v_res, max_alias_k=6)
|
||||
v_est, conf, _alias = unfold_velocity_crt(v_meas, v_unamb, v_res, max_alias_k=6)
|
||||
self.assertAlmostEqual(v_est, v_true, places=0) # within 1 m/s
|
||||
# Should still be CONFIRMED for a real velocity at this scale.
|
||||
self.assertIn(conf, ("CONFIRMED", "LIKELY"))
|
||||
|
||||
@@ -94,7 +94,7 @@ def _make_dspin() -> QDoubleSpinBox:
|
||||
# =============================================================================
|
||||
|
||||
class RangeDopplerCanvas(FigureCanvasQTAgg):
|
||||
"""Matplotlib canvas showing the Range-Doppler map (NUM_RANGE_BINS x NUM_DOPPLER_BINS) with dark theme."""
|
||||
"""Matplotlib canvas showing the Range-Doppler map (NUM_RANGE_BINS x NUM_DOPPLER_BINS) with dark theme.""" # noqa: E501
|
||||
|
||||
def __init__(self, _parent=None):
|
||||
fig = Figure(figsize=(10, 6), facecolor=DARK_BG)
|
||||
|
||||
@@ -573,7 +573,7 @@ def unfold_velocity_crt(
|
||||
alias depth k_0 ∈ [-K, K] generates candidates
|
||||
``v_true = v_meas_0 + k_0 · 2 · v_unamb_0``. A candidate is
|
||||
*valid* when it folds back into all other active PRIs to within
|
||||
``tol_factor × max(v_res)``.
|
||||
``tol_factor * max(v_res)``.
|
||||
|
||||
Args:
|
||||
v_meas_per_sf: signed velocity measurement per active sub-frame
|
||||
@@ -652,9 +652,7 @@ def unfold_velocity_crt(
|
||||
confidence = "AMBIGUOUS"
|
||||
elif n_sf == 3 and n_cands == 1:
|
||||
confidence = "CONFIRMED"
|
||||
elif n_sf == 3 and n_cands == 2:
|
||||
confidence = "LIKELY"
|
||||
elif n_sf == 2 and n_cands == 1:
|
||||
elif (n_sf == 3 and n_cands == 2) or (n_sf == 2 and n_cands == 1):
|
||||
confidence = "LIKELY"
|
||||
else: # n_sf == 2 and n_cands == 2
|
||||
confidence = "AMBIGUOUS"
|
||||
|
||||
@@ -192,7 +192,11 @@ class SoftwareFPGA:
|
||||
# to math-generated twiddles otherwise).
|
||||
range_i = np.zeros((n_chirps, n_samples), dtype=np.int64)
|
||||
range_q = np.zeros((n_chirps, n_samples), dtype=np.int64)
|
||||
twiddle_path = TWIDDLE_2048 if (n_samples == 2048 and os.path.exists(TWIDDLE_2048)) else None
|
||||
twiddle_path = (
|
||||
TWIDDLE_2048
|
||||
if (n_samples == 2048 and os.path.exists(TWIDDLE_2048))
|
||||
else None
|
||||
)
|
||||
for c in range(n_chirps):
|
||||
range_i[c], range_q[c] = run_range_fft(
|
||||
iq_i[c].astype(np.int64),
|
||||
|
||||
@@ -196,7 +196,11 @@ class RadarDataWorker(QThread):
|
||||
# for SHORT/MEDIUM sub-frame bins until PR-Q.5 replaces this path
|
||||
# with extract_targets_from_frame_crt.
|
||||
v_res = self._waveform.velocity_resolution_long_mps
|
||||
n_doppler = frame.detections.shape[1] if frame.detections.ndim == 2 else self._waveform.n_doppler_bins
|
||||
n_doppler = (
|
||||
frame.detections.shape[1]
|
||||
if frame.detections.ndim == 2
|
||||
else self._waveform.n_doppler_bins
|
||||
)
|
||||
doppler_center = n_doppler // 2
|
||||
|
||||
for idx in det_indices:
|
||||
|
||||
Reference in New Issue
Block a user