diff --git a/firmware/baseband/dsp_decimate.cpp b/firmware/baseband/dsp_decimate.cpp index c8a70898..6bc2c9b3 100644 --- a/firmware/baseband/dsp_decimate.cpp +++ b/firmware/baseband/dsp_decimate.cpp @@ -618,6 +618,12 @@ buffer_c16_t DecimateBy2CIC3::execute( return { dst.p, src.count / 2, src.sampling_rate / 2 }; } +void FIR64AndDecimateBy2Real::configure( + const std::array& new_taps +) { + std::copy(new_taps.cbegin(), new_taps.cend(), taps.begin()); +} + buffer_s16_t FIR64AndDecimateBy2Real::execute( buffer_s16_t src, buffer_s16_t dst diff --git a/firmware/baseband/dsp_decimate.hpp b/firmware/baseband/dsp_decimate.hpp index 97f02703..6922999b 100644 --- a/firmware/baseband/dsp_decimate.hpp +++ b/firmware/baseband/dsp_decimate.hpp @@ -76,11 +76,9 @@ class FIR64AndDecimateBy2Real { public: static constexpr size_t taps_count = 64; - FIR64AndDecimateBy2Real( + void configure( const std::array& taps - ) : taps(taps) - { - } + ); buffer_s16_t execute( buffer_s16_t src, @@ -89,7 +87,7 @@ public: private: std::array z; - const std::array& taps; + std::array taps; }; class FIRC8xR16x24FS4Decim4 { diff --git a/firmware/baseband/dsp_fir_taps.hpp b/firmware/baseband/dsp_fir_taps.hpp index 68ea1ea8..8b7b6fea 100644 --- a/firmware/baseband/dsp_fir_taps.hpp +++ b/firmware/baseband/dsp_fir_taps.hpp @@ -182,6 +182,27 @@ constexpr fir_taps_real<32> taps_6k0_channel { } }, }; +// WFM 200KF8E emission type ////////////////////////////////////////////// + +constexpr fir_taps_real<24> taps_200k_wfm_decim_0 = { + .pass_frequency_normalized = 100000.0f / 3072000.0f, + .stop_frequency_normalized = 484000.0f / 3072000.0f, + .taps = { { + 48, -18, -151, -364, -557, -548, -139, 789, + 2187, 3800, 5230, 6071, 6071, 5230, 3800, 2187, + 789, -139, -548, -557, -364, -151, -18, 48, + } }, +}; + +constexpr fir_taps_real<16> taps_200k_wfm_decim_1 = { + .pass_frequency_normalized = 100000.0f / 768000.0f, + .stop_frequency_normalized = 284000.0f / 768000.0f, + .taps = { { + -67, -123, 388, 622, -1342, -2185, 4599, 14486, + 14486, 4599, -2185, -1342, 622, 388, -123, -67, + } }, +}; + /* Wideband audio filter */ /* 96kHz int16_t input * -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop diff --git a/firmware/baseband/proc_wfm_audio.cpp b/firmware/baseband/proc_wfm_audio.cpp index d1bc8fe9..9f0639cc 100644 --- a/firmware/baseband/proc_wfm_audio.cpp +++ b/firmware/baseband/proc_wfm_audio.cpp @@ -23,8 +23,34 @@ #include +WidebandFMAudio::WidebandFMAudio() { + constexpr size_t baseband_fs = 3072000; + + constexpr size_t decim_0_input_fs = baseband_fs; + constexpr size_t decim_0_decimation_factor = 4; + constexpr size_t decim_0_output_fs = decim_0_input_fs / decim_0_decimation_factor; + + constexpr size_t decim_1_input_fs = decim_0_output_fs; + constexpr size_t decim_1_decimation_factor = 2; + constexpr size_t decim_1_output_fs = decim_1_input_fs / decim_1_decimation_factor; + + constexpr size_t demod_input_fs = decim_1_output_fs; + + decim_0.configure(taps_200k_wfm_decim_0.taps, 33554432); + decim_1.configure(taps_200k_wfm_decim_1.taps, 131072); + demod.configure(demod_input_fs, 75000); + audio_filter.configure(taps_64_lp_156_198.taps); +} + void WidebandFMAudio::execute(const buffer_c8_t& buffer) { - auto decimator_out = decimator.execute(buffer); + const buffer_c16_t dst_buffer { + dst.data(), + dst.size() + }; + + const auto decim_0_out = decim_0.execute(buffer, dst_buffer); + const auto decim_1_out = decim_1.execute(decim_0_out, dst_buffer); + const auto decimator_out = decim_1_out; const buffer_s16_t work_audio_buffer { (int16_t*)decimator_out.p, @@ -37,29 +63,24 @@ void WidebandFMAudio::execute(const buffer_c8_t& buffer) { feed_channel_stats(channel); //feed_channel_spectrum(channel); - /* 768kHz complex[512] + /* 384kHz complex[256] * -> FM demodulation - * -> 768kHz int16_t[512] */ + * -> 384kHz int16_t[256] */ /* TODO: To improve adjacent channel rejection, implement complex channel filter: * pass < +/- 100kHz, stop > +/- 200kHz */ auto audio_oversampled = demod.execute(decimator_out, work_audio_buffer); - /* 768kHz int16_t[512] - * -> 4th order CIC decimation by 2, gain of 1 - * -> 384kHz int16_t[256] */ - auto audio_8fs = audio_dec_1.execute(audio_oversampled, work_audio_buffer); - /* 384kHz int16_t[256] * -> 4th order CIC decimation by 2, gain of 1 * -> 192kHz int16_t[128] */ - auto audio_4fs = audio_dec_2.execute(audio_8fs, work_audio_buffer); + auto audio_4fs = audio_dec_1.execute(audio_oversampled, work_audio_buffer); /* 192kHz int16_t[128] * -> 4th order CIC decimation by 2, gain of 1 * -> 96kHz int16_t[64] */ - auto audio_2fs = audio_dec_3.execute(audio_4fs, work_audio_buffer); + auto audio_2fs = audio_dec_2.execute(audio_4fs, work_audio_buffer); /* 96kHz int16_t[64] * -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop, gain of 1 diff --git a/firmware/baseband/proc_wfm_audio.hpp b/firmware/baseband/proc_wfm_audio.hpp index 91965cc7..b45cc717 100644 --- a/firmware/baseband/proc_wfm_audio.hpp +++ b/firmware/baseband/proc_wfm_audio.hpp @@ -33,21 +33,19 @@ class WidebandFMAudio : public BasebandProcessor { public: - WidebandFMAudio() { - decimator.set_decimation_factor(ChannelDecimator::DecimationFactor::By4); - } + WidebandFMAudio(); void execute(const buffer_c8_t& buffer) override; private: - ChannelDecimator decimator; + std::array dst; + dsp::decimate::FIRC8xR16x24FS4Decim4 decim_0; + dsp::decimate::FIRC16xR16x16Decim2 decim_1; - dsp::demodulate::FM demod { 768000, 75000 }; + dsp::demodulate::FM demod; dsp::decimate::DecimateBy2CIC4Real audio_dec_1; dsp::decimate::DecimateBy2CIC4Real audio_dec_2; - dsp::decimate::DecimateBy2CIC4Real audio_dec_3; - const fir_taps_real<64>& audio_filter_taps = taps_64_lp_156_198; - dsp::decimate::FIR64AndDecimateBy2Real audio_filter { audio_filter_taps.taps }; + dsp::decimate::FIR64AndDecimateBy2Real audio_filter; IIRBiquadFilter audio_hpf { audio_hpf_30hz_config }; IIRBiquadFilter audio_deemph { audio_deemph_2122_6_config };