From 9636489fce9ec2349a8799e2f4d04a0a71b06307 Mon Sep 17 00:00:00 2001 From: AxisRay Date: Tue, 16 Jun 2026 09:14:21 +0800 Subject: [PATCH 1/2] Added check to ignore specific indices in signal processing.(#134) --- sources/radio/blocks/transmission.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sources/radio/blocks/transmission.cpp b/sources/radio/blocks/transmission.cpp index 975e9db..9688417 100644 --- a/sources/radio/blocks/transmission.cpp +++ b/sources/radio/blocks/transmission.cpp @@ -84,6 +84,9 @@ void Transmission::addSignals(const float* avgPower, const float* rawPower, cons for (const auto& index : indexes) { if (!containsWithMargin(m_signals, index, m_groupSize)) { const auto bestIndex = getBestIndex(index); + if (isIndexIgnored(bestIndex)) { + continue; + } const auto bestTunedFrequency = getTunedFrequency(m_indexToFrequency(bestIndex), m_config.recordingTuningStep()); Logger::info( LABEL, From 78b1e3a134e52e91d70a1038268503bc306d7259 Mon Sep 17 00:00:00 2001 From: AxisRay Date: Tue, 18 Aug 2026 21:13:12 +0800 Subject: [PATCH 2/2] Optimize ignored-frequency matching at scanner load. Filter ignores to scanned ranges, pre-merge overlapping intervals in memory, and look them up with binary search so the config list itself stays unmerged. --- sources/config.cpp | 28 ++++++++++++-- sources/config.h | 8 +++- sources/radio/blocks/transmission.cpp | 10 +---- sources/scanner.cpp | 2 +- sources/utils/radio_utils.cpp | 56 ++++++++++++++++++++++++++- sources/utils/radio_utils.h | 8 +++- tests/test_radio_utils.cpp | 29 ++++++++++++++ 7 files changed, 124 insertions(+), 17 deletions(-) diff --git a/sources/config.cpp b/sources/config.cpp index 72c8174..e0bfc93 100644 --- a/sources/config.cpp +++ b/sources/config.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,11 @@ spdlog::level::level_enum parseLogLevel(const std::string& level) { return spdlog::level::level_enum::off; } -Config::Config(const ArgConfig& argConfig, const FileConfig& fileConfig) : m_id(!argConfig.id.empty() ? argConfig.id : randomHex(8)), m_argConfig(argConfig), m_fileConfig(fileConfig) {} +Config::Config(const ArgConfig& argConfig, const FileConfig& fileConfig) + : m_id(!argConfig.id.empty() ? argConfig.id : randomHex(8)), + m_argConfig(argConfig), + m_fileConfig(fileConfig), + m_ignoredRanges(buildIgnoredRanges(fileConfig)) {} std::string Config::mqtt() const { return fmt::format("{}@{}", m_argConfig.mqttUser, m_argConfig.mqttUrl); }; std::string Config::getId() const { return m_id; } @@ -34,13 +39,28 @@ bool Config::isColorLogEnabled() const { return m_fileConfig.output.color_log_en spdlog::level::level_enum Config::consoleLogLevel() const { return parseLogLevel(m_fileConfig.output.console_log_level); } spdlog::level::level_enum Config::fileLogLevel() const { return parseLogLevel(m_fileConfig.output.file_log_level); } -std::vector Config::ignoredRanges() const { +std::vector Config::buildIgnoredRanges(const FileConfig& fileConfig) { + std::vector scanRanges; + for (const auto& device : fileConfig.devices) { + if (!device.enabled) { + continue; + } + scanRanges.insert(scanRanges.end(), device.ranges.begin(), device.ranges.end()); + } + std::vector ranges; - for (const auto& range : m_fileConfig.ignored_frequencies) { + ranges.reserve(fileConfig.ignored_frequencies.size()); + for (const auto& range : fileConfig.ignored_frequencies) { ranges.emplace_back(range.frequency - range.bandwidth / 2, range.frequency + range.bandwidth / 2); } - return ranges; + return mergeOverlappingRanges(filterRangesOverlapping(ranges, scanRanges)); } + +std::size_t Config::ignoredFrequencyCount() const { return m_fileConfig.ignored_frequencies.size(); } + +const std::vector& Config::ignoredRanges() const { return m_ignoredRanges; } + +bool Config::isFrequencyIgnored(Frequency frequency) const { return isFrequencyInRanges(m_ignoredRanges, frequency); } int Config::recordersCount() const { const auto max_workers = static_cast(std::thread::hardware_concurrency()); const auto auto_workers = max_workers / 2; diff --git a/sources/config.h b/sources/config.h index d5615b0..0b0e20d 100644 --- a/sources/config.h +++ b/sources/config.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -53,7 +54,9 @@ class Config { spdlog::level::level_enum consoleLogLevel() const; spdlog::level::level_enum fileLogLevel() const; - std::vector ignoredRanges() const; + std::size_t ignoredFrequencyCount() const; + const std::vector& ignoredRanges() const; + bool isFrequencyIgnored(Frequency frequency) const; int recordersCount() const; Frequency recordingBandwidth() const; std::chrono::milliseconds recordingMinTime() const; @@ -73,7 +76,10 @@ class Config { bool dumpRecording() const; private: + static std::vector buildIgnoredRanges(const FileConfig& fileConfig); + const std::string m_id; const ArgConfig& m_argConfig; const FileConfig& m_fileConfig; + const std::vector m_ignoredRanges; }; diff --git a/sources/radio/blocks/transmission.cpp b/sources/radio/blocks/transmission.cpp index 9688417..7e88b2a 100644 --- a/sources/radio/blocks/transmission.cpp +++ b/sources/radio/blocks/transmission.cpp @@ -143,15 +143,7 @@ Transmission::Index Transmission::getBestIndex(Index index) const { return mostFrequentIndex; } -bool Transmission::isIndexIgnored(const Index& index) const { - const auto frequency = m_indexToFrequency(index); - for (const auto& range : m_config.ignoredRanges()) { - if (range.contains(frequency)) { - return true; - } - } - return false; -} +bool Transmission::isIndexIgnored(const Index& index) const { return m_config.isFrequencyIgnored(m_indexToFrequency(index)); } std::vector Transmission::getSortedTransmissions(const std::chrono::milliseconds now) const { std::vector indexes; diff --git a/sources/scanner.cpp b/sources/scanner.cpp index 6fa2b64..c37b4b6 100644 --- a/sources/scanner.cpp +++ b/sources/scanner.cpp @@ -13,7 +13,7 @@ Scanner::Scanner(const Config& config, const Device& device, RemoteController& r m_isRunning(true), m_thread([this]() { worker(); }) { Logger::info(LABEL, "starting"); - Logger::info(LABEL, "ignored ranges: {}", colored(GREEN, "{}", config.ignoredRanges().size())); + Logger::info(LABEL, "ignored frequencies: {}, active ranges: {}", colored(GREEN, "{}", config.ignoredFrequencyCount()), colored(GREEN, "{}", config.ignoredRanges().size())); for (const auto& range : config.ignoredRanges()) { Logger::info(LABEL, "ignored range: {}", formatFrequencyRange(range)); } diff --git a/sources/utils/radio_utils.cpp b/sources/utils/radio_utils.cpp index 799de0f..d6df4e8 100644 --- a/sources/utils/radio_utils.cpp +++ b/sources/utils/radio_utils.cpp @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include namespace { @@ -208,4 +210,56 @@ std::vector splitRanges(const std::vector& range } } return results; -} \ No newline at end of file +} + +std::vector filterRangesOverlapping(const std::vector& ranges, const std::vector& bounds) { + if (bounds.empty()) { + return ranges; + } + std::vector results; + results.reserve(ranges.size()); + for (const auto& range : ranges) { + for (const auto& bound : bounds) { + if (range.start <= bound.stop && bound.start <= range.stop) { + results.push_back(range); + break; + } + } + } + return results; +} + +std::vector mergeOverlappingRanges(std::vector ranges) { + if (ranges.size() <= 1) { + return ranges; + } + std::sort(ranges.begin(), ranges.end(), [](const FrequencyRange& a, const FrequencyRange& b) { + if (a.start != b.start) { + return a.start < b.start; + } + return a.stop < b.stop; + }); + std::vector merged; + merged.reserve(ranges.size()); + merged.push_back(ranges.front()); + for (size_t i = 1; i < ranges.size(); ++i) { + auto& last = merged.back(); + if (ranges[i].start <= last.stop) { + last.stop = std::max(last.stop, ranges[i].stop); + } else { + merged.push_back(ranges[i]); + } + } + return merged; +} + +bool isFrequencyInRanges(const std::vector& ranges, Frequency frequency) { + if (ranges.empty()) { + return false; + } + const auto it = std::upper_bound(ranges.begin(), ranges.end(), frequency, [](Frequency value, const FrequencyRange& range) { return value < range.start; }); + if (it == ranges.begin()) { + return false; + } + return std::prev(it)->contains(frequency); +} diff --git a/sources/utils/radio_utils.h b/sources/utils/radio_utils.h index cbfa3f7..e47572b 100644 --- a/sources/utils/radio_utils.h +++ b/sources/utils/radio_utils.h @@ -26,4 +26,10 @@ Frequency getRangeSplitSampleRate(Frequency sampleRate); std::vector splitRange(const FrequencyRange& range, Frequency sampleRate); -std::vector splitRanges(const std::vector& ranges, Frequency sampleRate); \ No newline at end of file +std::vector splitRanges(const std::vector& ranges, Frequency sampleRate); + +std::vector filterRangesOverlapping(const std::vector& ranges, const std::vector& bounds); + +std::vector mergeOverlappingRanges(std::vector ranges); + +bool isFrequencyInRanges(const std::vector& ranges, Frequency frequency); diff --git a/tests/test_radio_utils.cpp b/tests/test_radio_utils.cpp index adced49..e2c8c41 100644 --- a/tests/test_radio_utils.cpp +++ b/tests/test_radio_utils.cpp @@ -130,3 +130,32 @@ TEST(RadioUtils, SplitRanges) { EXPECT_EQ(splitRange({140000000, 145000000}, 2000000), Ranges({{140000000, 142000000}, {142000000, 144000000}, {144000000, 146000000}})); EXPECT_EQ(splitRange({140000000, 150000000}, 2000000), Ranges({{140000000, 142000000}, {142000000, 144000000}, {144000000, 146000000}, {146000000, 148000000}, {148000000, 150000000}})); } + +TEST(RadioUtils, FilterRangesOverlapping) { + using Ranges = std::vector; + const Ranges scan({{432000000, 440000000}}); + EXPECT_EQ(filterRangesOverlapping(Ranges({{100000000, 100025000}, {432350000, 432375000}, {450000000, 450025000}}), scan), Ranges({{432350000, 432375000}})); + EXPECT_EQ(filterRangesOverlapping(Ranges({{431990000, 432010000}}), scan), Ranges({{431990000, 432010000}})); + EXPECT_EQ(filterRangesOverlapping(Ranges({{432350000, 432375000}}), Ranges{}), Ranges({{432350000, 432375000}})); +} + +TEST(RadioUtils, MergeOverlappingRanges) { + using Ranges = std::vector; + EXPECT_EQ(mergeOverlappingRanges(Ranges({{100, 200}, {200, 300}, {400, 500}})), Ranges({{100, 300}, {400, 500}})); + EXPECT_EQ(mergeOverlappingRanges(Ranges({{150, 180}, {100, 160}, {170, 190}})), Ranges({{100, 190}})); + EXPECT_EQ(mergeOverlappingRanges(Ranges({{100, 120}, {130, 140}})), Ranges({{100, 120}, {130, 140}})); +} + +TEST(RadioUtils, IsFrequencyInRanges) { + using Ranges = std::vector; + const Ranges ranges({{100, 200}, {400, 500}}); + EXPECT_FALSE(isFrequencyInRanges(ranges, 99)); + EXPECT_TRUE(isFrequencyInRanges(ranges, 100)); + EXPECT_TRUE(isFrequencyInRanges(ranges, 200)); + EXPECT_FALSE(isFrequencyInRanges(ranges, 201)); + EXPECT_FALSE(isFrequencyInRanges(ranges, 399)); + EXPECT_TRUE(isFrequencyInRanges(ranges, 400)); + EXPECT_TRUE(isFrequencyInRanges(ranges, 500)); + EXPECT_FALSE(isFrequencyInRanges(ranges, 501)); + EXPECT_FALSE(isFrequencyInRanges(Ranges{}, 100)); +}