From e5a3e8326f6884719896beca92bf6613b89aa847 Mon Sep 17 00:00:00 2001 From: Belousov Oleg Date: Mon, 27 Jul 2026 21:45:10 +0300 Subject: [PATCH] Isolate filtered spectrum collection from WFM --- firmware/baseband/CMakeLists.txt | 1 + .../baseband/filtered_spectrum_collector.cpp | 84 +++++++++++++++++++ .../baseband/filtered_spectrum_collector.hpp | 43 ++++++++++ firmware/baseband/proc_am_audio.cpp | 4 +- firmware/baseband/proc_am_audio.hpp | 4 +- firmware/baseband/proc_nfm_audio.cpp | 4 +- firmware/baseband/proc_nfm_audio.hpp | 4 +- firmware/baseband/spectrum_collector.cpp | 62 ++------------ firmware/baseband/spectrum_collector.hpp | 17 +--- 9 files changed, 144 insertions(+), 79 deletions(-) create mode 100644 firmware/baseband/filtered_spectrum_collector.cpp create mode 100644 firmware/baseband/filtered_spectrum_collector.hpp diff --git a/firmware/baseband/CMakeLists.txt b/firmware/baseband/CMakeLists.txt index 6ea2595dd..abc2ac5fa 100644 --- a/firmware/baseband/CMakeLists.txt +++ b/firmware/baseband/CMakeLists.txt @@ -124,6 +124,7 @@ set(CPPSRC dsp_goertzel.cpp matched_filter.cpp spectrum_collector.cpp + filtered_spectrum_collector.cpp tv_collector.cpp stream_input.cpp stream_output.cpp diff --git a/firmware/baseband/filtered_spectrum_collector.cpp b/firmware/baseband/filtered_spectrum_collector.cpp new file mode 100644 index 000000000..a8837a550 --- /dev/null +++ b/firmware/baseband/filtered_spectrum_collector.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +#include "filtered_spectrum_collector.hpp" + +#include "dsp_fir_taps.hpp" +#include "event_m4.hpp" + +#include + +void FilteredSpectrumCollector::on_message(const Message* const message) { + if (message->id == Message::ID::UpdateSpectrum) { + update(); + } + SpectrumCollector::on_message(message); +} + +void FilteredSpectrumCollector::start_capture( + const size_t decimation_factor) { + capture_decimation_ = decimation_factor; + capture_count_ = 0; + capture_ready_ = false; +} + +bool FilteredSpectrumCollector::feed( + const buffer_c16_t& channel, + const int32_t filter_low_frequency, + const int32_t filter_high_frequency, + const int32_t filter_transition) { + set_filter( + filter_low_frequency, + filter_high_frequency, + filter_transition); + + const size_t required_samples = 256 * capture_decimation_; + const size_t copy_count = std::min( + channel.count, required_samples - capture_count_); + std::copy_n( + channel.p, + copy_count, + capture_.begin() + capture_count_); + capture_count_ += copy_count; + + if (capture_count_ == required_samples) { + sampling_rate_ = channel.sampling_rate / capture_decimation_; + capture_ready_ = true; + EventDispatcher::events_flag(EVT_MASK_SPECTRUM); + return true; + } + return false; +} + +void FilteredSpectrumCollector::update() { + if (!capture_ready_) { + return; + } + + decim_0_.configure(taps_audio_spectrum_halfband.taps); + const buffer_c16_t capture{ + capture_.data(), + 256 * capture_decimation_, + sampling_rate_ * capture_decimation_}; + const buffer_c16_t stage_0{ + stage_0_.data(), + stage_0_.size()}; + const auto filtered = decim_0_.execute(capture, stage_0); + + if (capture_decimation_ == 4) { + decim_1_.configure(taps_audio_spectrum_halfband.taps); + const buffer_c16_t stage_1{ + stage_1_.data(), + stage_1_.size()}; + post_message(decim_1_.execute(filtered, stage_1)); + } else { + post_message(filtered); + } + capture_ready_ = false; +} diff --git a/firmware/baseband/filtered_spectrum_collector.hpp b/firmware/baseband/filtered_spectrum_collector.hpp new file mode 100644 index 000000000..4d8e2edfd --- /dev/null +++ b/firmware/baseband/filtered_spectrum_collector.hpp @@ -0,0 +1,43 @@ +/* + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + */ + +#ifndef __FILTERED_SPECTRUM_COLLECTOR_H__ +#define __FILTERED_SPECTRUM_COLLECTOR_H__ + +#include "dsp_decimate.hpp" +#include "spectrum_collector.hpp" + +#include + +class FilteredSpectrumCollector : public SpectrumCollector { + public: + void on_message(const Message* const message); + + void start_capture(const size_t decimation_factor); + bool feed( + const buffer_c16_t& channel, + const int32_t filter_low_frequency, + const int32_t filter_high_frequency, + const int32_t filter_transition); + + private: + std::array capture_{}; + std::array stage_0_{}; + std::array stage_1_{}; + dsp::decimate::FIRC16xR16x63HalfbandDecim2 decim_0_{}; + dsp::decimate::FIRC16xR16x63HalfbandDecim2 decim_1_{}; + size_t capture_count_{0}; + size_t capture_decimation_{1}; + uint32_t sampling_rate_{0}; + bool capture_ready_{false}; + + void update(); +}; + +#endif /*__FILTERED_SPECTRUM_COLLECTOR_H__*/ diff --git a/firmware/baseband/proc_am_audio.cpp b/firmware/baseband/proc_am_audio.cpp index a53d6b24e..32b497cc0 100644 --- a/firmware/baseband/proc_am_audio.cpp +++ b/firmware/baseband/proc_am_audio.cpp @@ -51,12 +51,12 @@ void NarrowbandAMAudio::execute(const buffer_c8_t& buffer) { if (!spectrum_capture_active && spectrum_samples >= spectrum_interval_samples) { spectrum_samples -= spectrum_interval_samples; - channel_spectrum.start_filtered_capture(spectrum_zoom_x2 ? 4 : 2); + channel_spectrum.start_capture(spectrum_zoom_x2 ? 4 : 2); spectrum_capture_active = true; } if (spectrum_capture_active && - channel_spectrum.feed_filtered( + channel_spectrum.feed( audio_decim_0_out, channel_filter_low_f, channel_filter_high_f, diff --git a/firmware/baseband/proc_am_audio.hpp b/firmware/baseband/proc_am_audio.hpp index 4cd60528d..7ccf37054 100644 --- a/firmware/baseband/proc_am_audio.hpp +++ b/firmware/baseband/proc_am_audio.hpp @@ -32,7 +32,7 @@ #include "audio_compressor.hpp" #include "audio_output.hpp" -#include "spectrum_collector.hpp" +#include "filtered_spectrum_collector.hpp" #include @@ -80,7 +80,7 @@ class NarrowbandAMAudio : public BasebandProcessor { FeedForwardCompressor audio_compressor{}; AudioOutput audio_output{}; - SpectrumCollector channel_spectrum{}; + FilteredSpectrumCollector channel_spectrum{}; /* NB: Threads should be the last members in the class definition. */ #ifdef PRALINE diff --git a/firmware/baseband/proc_nfm_audio.cpp b/firmware/baseband/proc_nfm_audio.cpp index 688a2b5ce..3e79afb32 100644 --- a/firmware/baseband/proc_nfm_audio.cpp +++ b/firmware/baseband/proc_nfm_audio.cpp @@ -57,12 +57,12 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) { if (!spectrum_capture_active && spectrum_samples >= spectrum_interval_samples) { spectrum_samples -= spectrum_interval_samples; - channel_spectrum.start_filtered_capture(2); + channel_spectrum.start_capture(2); spectrum_capture_active = true; } if (spectrum_capture_active && - channel_spectrum.feed_filtered( + channel_spectrum.feed( audio_decim_0_out, channel_filter_low_f, channel_filter_high_f, diff --git a/firmware/baseband/proc_nfm_audio.hpp b/firmware/baseband/proc_nfm_audio.hpp index 52b78ae8e..2b44335a7 100644 --- a/firmware/baseband/proc_nfm_audio.hpp +++ b/firmware/baseband/proc_nfm_audio.hpp @@ -33,7 +33,7 @@ #include "dsp_iir.hpp" #include "audio_output.hpp" -#include "spectrum_collector.hpp" +#include "filtered_spectrum_collector.hpp" #include @@ -87,7 +87,7 @@ class NarrowbandFMAudio : public BasebandProcessor { AudioOutput audio_output{}; - SpectrumCollector channel_spectrum{}; + FilteredSpectrumCollector channel_spectrum{}; size_t spectrum_interval_samples{0}; size_t spectrum_samples{0}; bool spectrum_capture_active{false}; diff --git a/firmware/baseband/spectrum_collector.cpp b/firmware/baseband/spectrum_collector.cpp index 4e116bd04..31d5780b9 100644 --- a/firmware/baseband/spectrum_collector.cpp +++ b/firmware/baseband/spectrum_collector.cpp @@ -22,7 +22,6 @@ #include "spectrum_collector.hpp" #include "dsp_fft.hpp" -#include "dsp_fir_taps.hpp" #include "utility.hpp" #include "event_m4.hpp" @@ -80,9 +79,10 @@ bool SpectrumCollector::feed( const int32_t filter_high_frequency, const int32_t filter_transition) { // Called from baseband processing thread. - channel_filter_low_frequency = filter_low_frequency; - channel_filter_high_frequency = filter_high_frequency; - channel_filter_transition = filter_transition; + set_filter( + filter_low_frequency, + filter_high_frequency, + filter_transition); bool block_completed = false; channel_spectrum_decimator.feed( @@ -94,40 +94,13 @@ bool SpectrumCollector::feed( return block_completed; } -void SpectrumCollector::start_filtered_capture( - const size_t decimation_factor) { - filtered_capture_decimation_ = decimation_factor; - filtered_capture_count_ = 0; - filtered_capture_ready_ = false; -} - -bool SpectrumCollector::feed_filtered( - const buffer_c16_t& channel, +void SpectrumCollector::set_filter( const int32_t filter_low_frequency, const int32_t filter_high_frequency, const int32_t filter_transition) { channel_filter_low_frequency = filter_low_frequency; channel_filter_high_frequency = filter_high_frequency; channel_filter_transition = filter_transition; - - const size_t required_samples = 256 * filtered_capture_decimation_; - const size_t copy_count = std::min( - channel.count, required_samples - filtered_capture_count_); - std::copy_n( - channel.p, - copy_count, - filtered_capture_.begin() + filtered_capture_count_); - filtered_capture_count_ += copy_count; - - if (filtered_capture_count_ == required_samples) { - channel_spectrum_sampling_rate = - channel.sampling_rate / filtered_capture_decimation_; - filtered_capture_ready_ = true; - channel_spectrum_request_update = true; - EventDispatcher::events_flag(EVT_MASK_SPECTRUM); - return true; - } - return false; } void SpectrumCollector::post_message(const buffer_c16_t& data) { @@ -171,31 +144,6 @@ static typename T::value_type spectrum_window_blackman_3(const T& s, const size_ void SpectrumCollector::update() { // Called from idle thread (after EVT_MASK_SPECTRUM is flagged) if (streaming && channel_spectrum_request_update) { - if (filtered_capture_ready_) { - filtered_decim_0_.configure(taps_audio_spectrum_halfband.taps); - const buffer_c16_t capture{ - filtered_capture_.data(), - 256 * filtered_capture_decimation_, - channel_spectrum_sampling_rate * filtered_capture_decimation_}; - const buffer_c16_t stage_0{ - filtered_stage_0_.data(), - filtered_stage_0_.size()}; - const auto filtered = filtered_decim_0_.execute(capture, stage_0); - - if (filtered_capture_decimation_ == 4) { - filtered_decim_1_.configure(taps_audio_spectrum_halfband.taps); - const buffer_c16_t stage_1{ - filtered_stage_1_.data(), - filtered_stage_1_.size()}; - const auto zoom_filtered = - filtered_decim_1_.execute(filtered, stage_1); - fft_swap(zoom_filtered, channel_spectrum); - } else { - fft_swap(filtered, channel_spectrum); - } - filtered_capture_ready_ = false; - } - /* Decimated buffer is full. Compute spectrum. */ fft_c_preswapped(channel_spectrum, 0, 8); diff --git a/firmware/baseband/spectrum_collector.hpp b/firmware/baseband/spectrum_collector.hpp index 78c173956..89d17142e 100644 --- a/firmware/baseband/spectrum_collector.hpp +++ b/firmware/baseband/spectrum_collector.hpp @@ -29,7 +29,6 @@ #include "complex.hpp" #include "block_decimator.hpp" -#include "dsp_decimate.hpp" #include #include @@ -51,12 +50,12 @@ class SpectrumCollector { const int32_t filter_high_frequency, const int32_t filter_transition); - void start_filtered_capture(const size_t decimation_factor); - bool feed_filtered( - const buffer_c16_t& channel, + protected: + void set_filter( const int32_t filter_low_frequency, const int32_t filter_high_frequency, const int32_t filter_transition); + void post_message(const buffer_c16_t& data); private: BlockDecimator channel_spectrum_decimator{1}; @@ -66,22 +65,12 @@ class SpectrumCollector { volatile bool channel_spectrum_request_update{false}; bool streaming{false}; std::array, 256> channel_spectrum{}; - std::array filtered_capture_{}; - std::array filtered_stage_0_{}; - std::array filtered_stage_1_{}; - dsp::decimate::FIRC16xR16x63HalfbandDecim2 filtered_decim_0_{}; - dsp::decimate::FIRC16xR16x63HalfbandDecim2 filtered_decim_1_{}; - size_t filtered_capture_count_{0}; - size_t filtered_capture_decimation_{1}; - bool filtered_capture_ready_{false}; uint32_t channel_spectrum_sampling_rate{0}; int32_t channel_filter_low_frequency{0}; int32_t channel_filter_high_frequency{0}; int32_t channel_filter_transition{0}; int32_t channel_filter_offset{0}; - void post_message(const buffer_c16_t& data); - void set_state(const SpectrumStreamingConfigMessage& message); void start(); void stop();