From c46337d94d1a31a40d44757e615709882602f243 Mon Sep 17 00:00:00 2001 From: Josh Poole Date: Mon, 12 Oct 2026 13:14:25 +0100 Subject: [PATCH] 20261012 - Default the standalone Doppler span to +/-1000 Hz, matching the fleet retina-node now runs every node at +/-1000 Hz (offworldlabs/retina-node#49). config/config.yml is only the standalone and development default, so it moves to match and a local run sees the same geometry as a node. Adds Constructor_Round_Shipped to TestAmbiguity at that geometry: 1001 Doppler bins, nCorr 999, nfft 1997 rounded to 2000 (2^4 * 5^3, so no badly factored FFT length), and the 411-bin delay window inside nCorr. The existing +/-300 cases stay as they are. Corrects the CFAR comment that quoted the +/-300 map as the shipped geometry. Verification: TestAmbiguity built and run on x86 (gcc, FFTW 3), 4 passed and the existing file-replay case skipped for want of its capture file. Changing the expected bin count to 1000 fails the new case. Co-Authored-By: Claude Opus 5.5 (1M context) --- config/config.yml | 4 +-- src/process/detection/CfarDetector1D.cpp | 2 +- test/unit/process/ambiguity/TestAmbiguity.cpp | 28 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/config/config.yml b/config/config.yml index 1f24707e..2df3912a 100644 --- a/config/config.yml +++ b/config/config.yml @@ -27,8 +27,8 @@ process: ambiguity: delayMin: -10 delayMax: 400 - dopplerMin: -300 - dopplerMax: 300 + dopplerMin: -1000 + dopplerMax: 1000 clutter: enable: true delayMin: -10 diff --git a/src/process/detection/CfarDetector1D.cpp b/src/process/detection/CfarDetector1D.cpp index 9d767e6e..7ed4a06b 100644 --- a/src/process/detection/CfarDetector1D.cpp +++ b/src/process/detection/CfarDetector1D.cpp @@ -31,7 +31,7 @@ std::unique_ptr CfarDetector1D::process(Map> *x) // The training window and the false-alarm factor depend on the delay bin // only, not on Doppler, so they are the same for every row. Building them // once per CPI replaces one heap allocation and one pow() per cell, which at - // the shipped geometry is 123,711 of each. + // the shipped geometry (1001 Doppler x 411 delay bins) is 411,411 of each. // // The left window uses k >= 0 like the right one. The original used k > 0, // silently excluding bin 0 from the left window while including it on the diff --git a/test/unit/process/ambiguity/TestAmbiguity.cpp b/test/unit/process/ambiguity/TestAmbiguity.cpp index 8e6af494..0c410dfe 100644 --- a/test/unit/process/ambiguity/TestAmbiguity.cpp +++ b/test/unit/process/ambiguity/TestAmbiguity.cpp @@ -115,6 +115,34 @@ TEST_CASE("Constructor_Round", "[constructor]") CHECK(ambiguity.get_nfft() == 6750); } +/// @brief Test constructor at the shipped geometry, +/-1000 Hz. +/// @details The span every node runs (retina-node's default.yml, mirrored in +/// config/config.yml for standalone use). 2 Hz bins give 1001 Doppler bins and +/// nCorr 999, and the delay window must fit inside nCorr. The FFT length rounds +/// 1997 up to 2000 = 2^4 * 5^3. +TEST_CASE("Constructor_Round_Shipped", "[constructor]") +{ + int32_t delayMin{-10}; + int32_t delayMax{400}; + int32_t dopplerMin{-1000}; + int32_t dopplerMax{1000}; + + uint32_t fs{2'000'000}; + float tCpi{0.5}; + uint32_t nSamples = tCpi * fs; // narrow on purpose + + Ambiguity ambiguity(delayMin, delayMax, dopplerMin, + dopplerMax, fs, nSamples, true); + + CHECK_THAT(ambiguity.get_cpi(), Catch::Matchers::WithinAbs(tCpi, 0.02)); + CHECK(ambiguity.get_doppler_middle() == 0); + CHECK(ambiguity.get_n_corr() == 999); + CHECK(ambiguity.get_n_delay_bins() == 411); + CHECK(ambiguity.get_n_delay_bins() < ambiguity.get_n_corr()); + CHECK(ambiguity.get_n_doppler_bins() == 1001); + CHECK(ambiguity.get_nfft() == 2000); +} + /// @brief Test simple ambiguity processing. TEST_CASE("Process_Simple", "[process]") {