From f3b0631ec6a4759cc0a2c178c6f0a0b3a8659d52 Mon Sep 17 00:00:00 2001 From: Vladisslav P Date: Fri, 18 Feb 2022 01:40:14 +0300 Subject: [PATCH] New rx_agc implementation (4/4) Move common code from nbrx/wfmrx to receiver_base Move all agc processing into block class rx_agc_2f and eliminate CAgc class Remove CurrentGainDb and move processing to get_current_gain Rename SetParameters to set_parameters Remove ProcessData and move all processing to work Fix tag propagation setting sample delay Workaroung GNU Radio < 3.8 tag propagation bug: manually calculate new tag offsets Small cleanup Set audio mute by disconnecting audio_snk Switch to using history to improve performance Prefill magnitude buffer on buffer size change in running state Prefill magnitude buffer on enabled state change in running state --- src/applications/gqrx/mainwindow.cpp | 16 +- src/applications/gqrx/receiver.cpp | 65 +++++- src/applications/gqrx/receiver.h | 4 + src/dsp/CMakeLists.txt | 2 - src/dsp/agc_impl.cpp | 290 ------------------------ src/dsp/agc_impl.h | 65 ------ src/dsp/rx_agc_xx.cpp | 323 +++++++++++++++++++++++++-- src/dsp/rx_agc_xx.h | 35 ++- src/receivers/nbrx.cpp | 75 +------ src/receivers/nbrx.h | 25 --- src/receivers/receiver_base.cpp | 50 +++-- src/receivers/receiver_base.h | 21 +- src/receivers/wfmrx.cpp | 93 +------- src/receivers/wfmrx.h | 23 -- 14 files changed, 446 insertions(+), 641 deletions(-) delete mode 100644 src/dsp/agc_impl.cpp delete mode 100644 src/dsp/agc_impl.h diff --git a/src/applications/gqrx/mainwindow.cpp b/src/applications/gqrx/mainwindow.cpp index 76c8a48948..95a15419e8 100644 --- a/src/applications/gqrx/mainwindow.cpp +++ b/src/applications/gqrx/mainwindow.cpp @@ -1194,7 +1194,7 @@ void MainWindow::selectDemod(int mode_idx) //Call wrapper to update enable/disabled state setAgcOn(uiDockRxOpt->getAgcOn()); rx->set_agc_target_level(uiDockRxOpt->getAgcTargetLevel()); - rx->set_agc_manual_gain(uiDockAudio->audioGain()); + rx->set_agc_manual_gain(uiDockAudio->audioGain() / 10.0); rx->set_agc_max_gain(uiDockRxOpt->getAgcMaxGain()); rx->set_agc_attack(uiDockRxOpt->getAgcAttack()); rx->set_agc_decay(uiDockRxOpt->getAgcDecay()); @@ -1285,19 +1285,7 @@ void MainWindow::setAudioGain(float value) */ void MainWindow::setAudioMute(bool mute) { - if(mute) - { - rx->set_agc_target_level(-80); - rx->set_agc_manual_gain(-80); - if(!uiDockRxOpt->getAgcOn()) - uiDockAudio->setGainEnabled(false); - }else{ - rx->set_agc_target_level(uiDockRxOpt->getAgcTargetLevel()); - rx->set_agc_manual_gain(uiDockAudio->audioGain() / 10.0); - if(!uiDockRxOpt->getAgcOn()) - uiDockAudio->setGainEnabled(true); - } - + rx->set_mute(mute); } /** Set AGC ON/OFF. */ diff --git a/src/applications/gqrx/receiver.cpp b/src/applications/gqrx/receiver.cpp index 9269f8f769..d9b3d3a967 100644 --- a/src/applications/gqrx/receiver.cpp +++ b/src/applications/gqrx/receiver.cpp @@ -70,6 +70,7 @@ receiver::receiver(const std::string input_device, d_iq_rev(false), d_dc_cancel(false), d_iq_balance(false), + d_mute(false), d_demod(RX_DEMOD_OFF) { @@ -285,7 +286,7 @@ void receiver::set_output_device(const std::string device) audio_snk = gr::audio::sink::make(d_audio_rate, device, true); #endif - if (d_demod != RX_DEMOD_OFF) + if ((d_demod != RX_DEMOD_OFF) && !d_mute) { tb->connect(rx, 0, audio_snk, 0); tb->connect(rx, 1, audio_snk, 1); @@ -870,6 +871,33 @@ float receiver::get_agc_gain() return 0; } +/** Set audio mute. */ +receiver::status receiver::set_mute(bool mute) +{ + if (d_mute == mute) + return STATUS_OK; + tb->lock(); + if (mute) + { + tb->disconnect(rx, 0, audio_snk, 0); + tb->disconnect(rx, 1, audio_snk, 1); + } + else + { + tb->connect(rx, 0, audio_snk, 0); + tb->connect(rx, 1, audio_snk, 1); + } + tb->unlock(); + d_mute = mute; + return STATUS_OK; +} + +/** Get audio mute. */ +bool receiver::get_mute() +{ + return d_mute; +} + receiver::status receiver::set_demod(rx_demod demod, bool force) { status ret = STATUS_OK; @@ -1121,15 +1149,21 @@ receiver::status receiver::start_audio_playback(const std::string filename) stop(); /* route demodulator output to null sink */ - tb->disconnect(rx, 0, audio_snk, 0); - tb->disconnect(rx, 1, audio_snk, 1); + if (!d_mute) + { + tb->disconnect(rx, 0, audio_snk, 0); + tb->disconnect(rx, 1, audio_snk, 1); + } tb->disconnect(rx, 0, audio_fft, 0); tb->disconnect(rx, 0, audio_udp_sink, 0); tb->disconnect(rx, 1, audio_udp_sink, 1); tb->connect(rx, 0, audio_null_sink0, 0); /** FIXME: other channel? */ tb->connect(rx, 1, audio_null_sink1, 0); /** FIXME: other channel? */ - tb->connect(wav_src, 0, audio_snk, 0); - tb->connect(wav_src, 1, audio_snk, 1); + if (!d_mute) + { + tb->connect(wav_src, 0, audio_snk, 0); + tb->connect(wav_src, 1, audio_snk, 1); + } tb->connect(wav_src, 0, audio_fft, 0); tb->connect(wav_src, 0, audio_udp_sink, 0); tb->connect(wav_src, 1, audio_udp_sink, 1); @@ -1145,15 +1179,21 @@ receiver::status receiver::stop_audio_playback() { /* disconnect wav source and reconnect receiver */ stop(); - tb->disconnect(wav_src, 0, audio_snk, 0); - tb->disconnect(wav_src, 1, audio_snk, 1); + if (!d_mute) + { + tb->disconnect(wav_src, 0, audio_snk, 0); + tb->disconnect(wav_src, 1, audio_snk, 1); + } tb->disconnect(wav_src, 0, audio_fft, 0); tb->disconnect(wav_src, 0, audio_udp_sink, 0); tb->disconnect(wav_src, 1, audio_udp_sink, 1); tb->disconnect(rx, 0, audio_null_sink0, 0); tb->disconnect(rx, 1, audio_null_sink1, 0); - tb->connect(rx, 0, audio_snk, 0); - tb->connect(rx, 1, audio_snk, 1); + if (!d_mute) + { + tb->connect(rx, 0, audio_snk, 0); + tb->connect(rx, 1, audio_snk, 1); + } tb->connect(rx, 0, audio_fft, 0); /** FIXME: other channel? */ tb->connect(rx, 0, audio_udp_sink, 0); tb->connect(rx, 1, audio_udp_sink, 1); @@ -1381,8 +1421,11 @@ void receiver::connect_all(rx_chain type) tb->connect(rx, 0, audio_fft, 0); tb->connect(rx, 0, audio_udp_sink, 0); tb->connect(rx, 1, audio_udp_sink, 1); - tb->connect(rx, 0, audio_snk, 0); - tb->connect(rx, 1, audio_snk, 1); + if (!d_mute) + { + tb->connect(rx, 0, audio_snk, 0); + tb->connect(rx, 1, audio_snk, 1); + } // Recorders and sniffers if (d_recording_wav) { diff --git a/src/applications/gqrx/receiver.h b/src/applications/gqrx/receiver.h index 1fdb45bdc0..5f995a5763 100644 --- a/src/applications/gqrx/receiver.h +++ b/src/applications/gqrx/receiver.h @@ -188,6 +188,9 @@ class receiver status set_agc_hang(int hang_ms); float get_agc_gain(); + status set_mute(bool mute); + bool get_mute(); + status set_demod(rx_demod demod, bool force=false); /* FM parameters */ @@ -253,6 +256,7 @@ class receiver bool d_iq_rev; /*!< Whether I/Q is reversed or not. */ bool d_dc_cancel; /*!< Enable automatic DC removal. */ bool d_iq_balance; /*!< Enable automatic IQ balance. */ + bool d_mute; /*!< Enable audio mute. */ std::string input_devstr; /*!< Current input device string. */ std::string output_devstr; /*!< Current output device string. */ diff --git a/src/dsp/CMakeLists.txt b/src/dsp/CMakeLists.txt index 3f8e38e808..8555509bee 100644 --- a/src/dsp/CMakeLists.txt +++ b/src/dsp/CMakeLists.txt @@ -17,8 +17,6 @@ add_source_files(SRCS_LIST rds/parser_impl.h rds/parser.h rds/tmc_events.h - agc_impl.cpp - agc_impl.h correct_iq_cc.cpp correct_iq_cc.h downconverter.cpp diff --git a/src/dsp/agc_impl.cpp b/src/dsp/agc_impl.cpp deleted file mode 100644 index f54c3bd295..0000000000 --- a/src/dsp/agc_impl.cpp +++ /dev/null @@ -1,290 +0,0 @@ -////////////////////////////////////////////////////////////////////// -// agc_impl.cpp: implementation of the CAgc class. -// -// This class implements an automatic gain function. -// -// History: -// 2010-09-15 Initial creation MSW -// 2011-03-27 Initial release -// 2011-09-24 Adapted for gqrx -// 2022-01-10 Rewritten with low complexity alogo -////////////////////////////////////////////////////////////////////// -//========================================================================================== -// + + + This Software is released under the "Simplified BSD License" + + + -//Copyright 2010 Moe Wheatley. All rights reserved. -// -//Redistribution and use in source and binary forms, with or without modification, are -//permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other materials -// provided with the distribution. -// -//THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR IMPLIED -//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR -//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -//The views and conclusions contained in the software and documentation are those of the -//authors and should not be interpreted as representing official policies, either expressed -//or implied, of Moe Wheatley. -//========================================================================================== - -#include -#include -#include -#include -#include - -#define AGC_DEBUG - -#define MIN_GAIN_DB (-20.0f) -#define MIN_GAIN powf(10.0, MIN_GAIN_DB) - -CAgc::CAgc(): - d_sample_rate(0), - d_agc_on(false), - d_target_level(0), - d_manual_gain(0), - d_max_gain(-1), - d_attack(0), - d_decay(0), - d_hang(0), - d_target_mag(1), - d_buf_size(0), - d_buf_p(0) -{ - SetParameters(2000, 0, 0, 0, 100, 50, 50, 0, true); -} - -CAgc::~CAgc() -{ - -} - -void CAgc::SetParameters(double sample_rate, bool agc_on, int target_level, - float manual_gain, int max_gain, int attack, int decay, - int hang, bool force) -{ - bool samp_rate_changed = false; - bool agc_on_changed = false; - bool target_level_changed = false; - bool manual_gain_changed = false; - bool max_gain_changed = false; - bool attack_changed = false; - bool decay_changed = false; - bool hang_changed = false; - if (d_sample_rate != sample_rate || force) - { - d_sample_rate = sample_rate; - samp_rate_changed = true; - } - if (d_agc_on != agc_on || force) - { - d_agc_on = agc_on; - agc_on_changed = true; - } - if (d_target_level != target_level || force) - { - d_target_level = target_level; - d_target_mag = powf(10.0, TYPEFLOAT(d_target_level) / 20.0); - target_level_changed = true; - } - if (d_manual_gain != manual_gain || force) - { - d_manual_gain = manual_gain; - manual_gain_changed = true; - } - if (d_max_gain != max_gain || force) - { - d_max_gain = max_gain; - if(d_max_gain < 1) - d_max_gain = 1; - d_max_gain_mag = powf(10.0, d_max_gain / 20.0); - max_gain_changed = true; - } - if (d_attack != attack || force) - { - d_attack = attack; - attack_changed = true; - } - if (d_decay != decay || force) - { - d_decay = decay; - decay_changed = true; - } - if (d_hang != hang || force) - { - d_hang = hang; - hang_changed = true; - } - if (samp_rate_changed || attack_changed) - { - d_buf_samples = sample_rate * d_attack / 1000.0; - int buf_size = 1; - for(unsigned int k = 0; k < sizeof(int) * 8; k++) - { - buf_size *= 2; - if(buf_size >= d_buf_samples) - break; - } - if (d_buf_p >= d_buf_samples) - d_buf_p %= d_buf_samples; - if(d_buf_size != buf_size) - { - d_buf_size = buf_size; - d_sample_buf.clear(); - d_sample_buf.resize(d_buf_size, 0); - d_mag_buf.clear(); - d_mag_buf.resize(d_buf_size * 2, 0); - d_buf_p = 0; - d_max_idx = d_buf_size * 2 - 2; - } - } - if ((manual_gain_changed || agc_on_changed) && !agc_on) - d_current_gain = powf(10.0, TYPEFLOAT(d_manual_gain) / 20.0); - if (max_gain_changed || attack_changed || samp_rate_changed) - d_attack_step = 1.0 / powf(10.0, std::max(TYPEFLOAT(d_max_gain), - MIN_GAIN_DB) / TYPEFLOAT(d_buf_samples) / 20.0); - if (max_gain_changed || decay_changed || samp_rate_changed) - d_decay_step = powf(10.0, TYPEFLOAT(d_max_gain) / TYPEFLOAT(sample_rate * d_decay / 1000.0) / 20.0); - if (hang_changed || samp_rate_changed) - d_hang_samp = sample_rate * d_hang / 1000.0; - - if (target_level_changed || max_gain_changed) - d_floor = powf(10.0, TYPEFLOAT(d_target_level - d_max_gain) / 20.0); - #ifdef AGC_DEBUG - std::cerr< 1) - { - float max_p = std::max(d_mag_buf[ofs + p], d_mag_buf[ofs + (p ^ 1)]); - p = p >> 1; - ofs += base; - if(d_mag_buf[ofs + p] != max_p) - d_mag_buf[ofs + p] = max_p; - else - break; - base = base >> 1; - } - -} - -void CAgc::ProcessData(float * pOutData0,float * pOutData1, const float * pInData0, const float * pInData1, int Length) -{ - int k; - TYPEFLOAT max_out = 0; - TYPEFLOAT mag_in = 0; - if (d_agc_on) - { -// float * mag_vect = &((float *)pOutData)[Length]; -// volk_32fc_magnitude_32f(mag_vect, pInData, Length); - for (k = 0; k < Length; k++) - { - float sample_in0 = pInData0[k]; - float sample_in1 = pInData1[k]; -// mag_in = mag_vect[k]; - mag_in = std::max(fabs(sample_in0),fabs(sample_in1)); - float sample_out0 = d_sample_buf[d_buf_p].real(); - float sample_out1 = d_sample_buf[d_buf_p].imag(); - - d_sample_buf[d_buf_p] = TYPECPX(sample_in0, sample_in1); - d_mag_buf[d_buf_p] = mag_in; - update_buffer(d_buf_p); - max_out = get_peak(); - - int buf_p_next = d_buf_p + 1; - if (buf_p_next >= d_buf_samples) - buf_p_next = 0; - - if (max_out > d_floor) - { - float new_target = d_target_mag / max_out; - if (new_target < d_target_gain) - { - if (d_current_gain > d_target_gain) - d_hang_counter = d_buf_samples + d_hang_samp; - d_target_gain = new_target; - } - else - if (!d_hang_counter) - d_target_gain = new_target; - } - else - { - d_target_gain = d_max_gain_mag; - d_hang_counter = 0; - } - if (d_current_gain > d_target_gain) - { - //attack, decrease gain one step per sample - d_current_gain *= d_attack_step; - } - else - { - if (d_hang_counter <= 0) - { - //decay, increase gain one step per sample until we reach d_max_gain - if (d_current_gain < d_target_gain) - d_current_gain *= d_decay_step; - if (d_current_gain > d_target_gain) - d_current_gain = d_target_gain; - } - } - if (d_hang_counter > 0) - d_hang_counter--; - if (d_current_gain < MIN_GAIN) - d_current_gain = MIN_GAIN; - pOutData0[k] = sample_out0 * d_current_gain; - pOutData1[k] = sample_out1 * d_current_gain; - d_buf_p = buf_p_next; - } - } - else{ - volk_32f_s32f_multiply_32f((float *)pOutData0, (float *)pInData0, d_current_gain, Length); - volk_32f_s32f_multiply_32f((float *)pOutData1, (float *)pInData1, d_current_gain, Length); - } - #ifdef AGC_DEBUG2 - if(d_prev_dbg != d_target_gain) - { - std::cerr<<"------ d_target_gain="< 1) + { + float max_p = std::max(d_mag_buf[ofs + p], d_mag_buf[ofs + (p ^ 1)]); + p = p >> 1; + ofs += base; + if(d_mag_buf[ofs + p] != max_p) + d_mag_buf[ofs + p] = max_p; + else + break; + base = base >> 1; + } + +} diff --git a/src/dsp/rx_agc_xx.h b/src/dsp/rx_agc_xx.h index 8d80ed6d0c..7261cb5fb7 100644 --- a/src/dsp/rx_agc_xx.h +++ b/src/dsp/rx_agc_xx.h @@ -26,7 +26,9 @@ #include #include #include -#include + +#define TYPECPX std::complex +#define TYPEFLOAT float class rx_agc_2f; @@ -81,6 +83,8 @@ class rx_agc_2f : public gr::sync_block public: ~rx_agc_2f(); + bool start() override; + bool stop() override; int work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); @@ -94,11 +98,11 @@ class rx_agc_2f : public gr::sync_block void set_decay(int decay); void set_hang(int hang); float get_current_gain(); - private: - void reconfigure(); + void set_parameters(double sample_rate, bool agc_on, int target_level, + float manual_gain, int max_gain, int attack, int decay, + int hang, bool force = false); - CAgc *d_agc; std::mutex d_mutex; /*! Used to lock internal data while processing or setting parameters. */ bool d_agc_on; /*! Current AGC status (true/false). */ @@ -109,6 +113,29 @@ class rx_agc_2f : public gr::sync_block int d_attack; /*! Current AGC attack (20...5000 ms). */ int d_decay; /*! Current AGC decay (20...5000 ms). */ int d_hang; /*! Current AGC hang (0...5000 ms). */ +private: + float get_peak(); + void update_buffer(int p); + + TYPEFLOAT d_target_mag; + int d_hang_samp; + int d_buf_samples; + int d_buf_size; + int d_max_idx; + int d_buf_p; + int d_hang_counter; + TYPEFLOAT d_max_gain_mag; + TYPEFLOAT d_current_gain; + TYPEFLOAT d_target_gain; + TYPEFLOAT d_decay_step; + TYPEFLOAT d_attack_step; + TYPEFLOAT d_floor; + + std::vector d_mag_buf; + bool d_refill; + bool d_running; + + TYPEFLOAT d_prev_dbg; }; #endif /* RX_AGC_XX_H */ diff --git a/src/receivers/nbrx.cpp b/src/receivers/nbrx.cpp index a12519b5a8..e6a9904499 100644 --- a/src/receivers/nbrx.cpp +++ b/src/receivers/nbrx.cpp @@ -34,19 +34,13 @@ nbrx_sptr make_nbrx(float quad_rate, float audio_rate) } nbrx::nbrx(float quad_rate, float audio_rate) - : receiver_base_cf("NBRX"), + : receiver_base_cf("NBRX", PREF_QUAD_RATE, quad_rate, audio_rate), d_running(false), - d_quad_rate(quad_rate), - d_audio_rate(audio_rate), d_demod(NBRX_DEMOD_FM) { - iq_resamp = make_resampler_cc(PREF_QUAD_RATE/d_quad_rate); nb = make_rx_nb_cc(PREF_QUAD_RATE, 3.3, 2.5); filter = make_rx_filter(PREF_QUAD_RATE, -5000.0, 5000.0, 1000.0); - agc = make_rx_agc_2f(d_audio_rate, true, 0, 0, 100, 500, 500, 0); - sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001); - meter = make_rx_meter_c(PREF_QUAD_RATE); demod_raw = gr::blocks::complex_to_float::make(1); demod_ssb = gr::blocks::complex_to_real::make(1); demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, 5000.0, 75.0e-6); @@ -103,18 +97,6 @@ bool nbrx::stop() return true; } -void nbrx::set_quad_rate(float quad_rate) -{ - if (std::abs(d_quad_rate-quad_rate) > 0.5) - { - qDebug() << "Changing NB_RX quad rate:" << d_quad_rate << "->" << quad_rate; - d_quad_rate = quad_rate; - lock(); - iq_resamp->set_rate(PREF_QUAD_RATE/d_quad_rate); - unlock(); - } -} - void nbrx::set_filter(double low, double high, double tw) { filter->set_param(low, high, tw); @@ -125,11 +107,6 @@ void nbrx::set_cw_offset(double offset) filter->set_cw_offset(offset); } -float nbrx::get_signal_level() -{ - return meter->get_level_db(); -} - void nbrx::set_nb_on(int nbid, bool on) { if (nbid == 1) @@ -146,56 +123,6 @@ void nbrx::set_nb_threshold(int nbid, float threshold) nb->set_threshold2(threshold); } -void nbrx::set_sql_level(double level_db) -{ - sql->set_threshold(level_db); -} - -void nbrx::set_sql_alpha(double alpha) -{ - sql->set_alpha(alpha); -} - -void nbrx::set_agc_on(bool agc_on) -{ - agc->set_agc_on(agc_on); -} - -void nbrx::set_agc_target_level(int target_level) -{ - agc->set_target_level(target_level); -} - -void nbrx::set_agc_manual_gain(float gain) -{ - agc->set_manual_gain(gain); -} - -void nbrx::set_agc_max_gain(int gain) -{ - agc->set_max_gain(gain); -} - -void nbrx::set_agc_attack(int attack_ms) -{ - agc->set_attack(attack_ms); -} - -void nbrx::set_agc_decay(int decay_ms) -{ - agc->set_decay(decay_ms); -} - -void nbrx::set_agc_hang(int hang_ms) -{ - agc->set_hang(hang_ms); -} - -float nbrx::get_agc_gain() -{ - return agc->get_current_gain(); -} - void nbrx::set_demod(int rx_demod) { nbrx_demod current_demod = d_demod; diff --git a/src/receivers/nbrx.h b/src/receivers/nbrx.h index 6bb635aec3..55e0dd97b3 100644 --- a/src/receivers/nbrx.h +++ b/src/receivers/nbrx.h @@ -23,19 +23,14 @@ #ifndef NBRX_H #define NBRX_H -#include #include #include #include #include "receivers/receiver_base.h" #include "dsp/rx_noise_blanker_cc.h" #include "dsp/rx_filter.h" -#include "dsp/rx_meter.h" -#include "dsp/rx_agc_xx.h" #include "dsp/rx_demod_fm.h" #include "dsp/rx_demod_am.h" -//#include "dsp/resampler_ff.h" -#include "dsp/resampler_xx.h" class nbrx; @@ -73,13 +68,9 @@ class nbrx : public receiver_base_cf bool start(); bool stop(); - void set_quad_rate(float quad_rate); - void set_filter(double low, double high, double tw); void set_cw_offset(double offset); - float get_signal_level(); - /* Noise blanker */ bool has_nb() { return true; } void set_nb_on(int nbid, bool on); @@ -87,19 +78,9 @@ class nbrx : public receiver_base_cf /* Squelch parameter */ bool has_sql() { return true; } - void set_sql_level(double level_db); - void set_sql_alpha(double alpha); /* AGC */ bool has_agc() { return true; } - void set_agc_on(bool agc_on); - void set_agc_target_level(int target_level); - void set_agc_manual_gain(float gain); - void set_agc_max_gain(int gain); - void set_agc_attack(int attack_ms); - void set_agc_decay(int decay_ms); - void set_agc_hang(int hang_ms); - float get_agc_gain(); void set_demod(int demod); @@ -119,18 +100,12 @@ class nbrx : public receiver_base_cf private: bool d_running; /*!< Whether receiver is running or not. */ - float d_quad_rate; /*!< Input sample rate. */ - int d_audio_rate; /*!< Audio output rate. */ nbrx_demod d_demod; /*!< Current demodulator. */ - resampler_cc_sptr iq_resamp; /*!< Baseband resampler. */ rx_filter_sptr filter; /*!< Non-translating bandpass filter.*/ rx_nb_cc_sptr nb; /*!< Noise blanker. */ - rx_meter_c_sptr meter; /*!< Signal strength. */ - rx_agc_2f_sptr agc; /*!< Receiver AGC. */ - gr::analog::simple_squelch_cc::sptr sql; /*!< Squelch. */ gr::blocks::complex_to_float::sptr demod_raw; /*!< Raw I/Q passthrough. */ gr::blocks::complex_to_real::sptr demod_ssb; /*!< SSB demodulator. */ rx_demod_fm_sptr demod_fm; /*!< FM demodulator. */ diff --git a/src/receivers/receiver_base.cpp b/src/receivers/receiver_base.cpp index 42d6806292..1d3f8013be 100644 --- a/src/receivers/receiver_base.cpp +++ b/src/receivers/receiver_base.cpp @@ -22,6 +22,7 @@ */ #include #include "receivers/receiver_base.h" +#include static const int MIN_IN = 1; /* Minimum number of input streams. */ @@ -29,12 +30,18 @@ static const int MAX_IN = 1; /* Maximum number of input streams. */ static const int MIN_OUT = 2; /* Minimum number of output streams. */ static const int MAX_OUT = 2; /* Maximum number of output streams. */ -receiver_base_cf::receiver_base_cf(std::string src_name) +receiver_base_cf::receiver_base_cf(std::string src_name, float pref_quad_rate, float quad_rate, int audio_rate) : gr::hier_block2 (src_name, gr::io_signature::make (MIN_IN, MAX_IN, sizeof(gr_complex)), - gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof(float))) + gr::io_signature::make (MIN_OUT, MAX_OUT, sizeof(float))), + d_quad_rate(quad_rate), + d_audio_rate(audio_rate), + d_pref_quad_rate(pref_quad_rate) { - + iq_resamp = make_resampler_cc(d_pref_quad_rate/d_quad_rate); + agc = make_rx_agc_2f(d_audio_rate, false, 0, 0, 100, 500, 500, 0); + sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001); + meter = make_rx_meter_c(d_pref_quad_rate); } receiver_base_cf::~receiver_base_cf() @@ -42,6 +49,23 @@ receiver_base_cf::~receiver_base_cf() } +void receiver_base_cf::set_quad_rate(float quad_rate) +{ + if (std::abs(d_quad_rate-quad_rate) > 0.5) + { + qDebug() << "Changing RX quad rate:" << d_quad_rate << "->" << quad_rate; + d_quad_rate = quad_rate; + lock(); + iq_resamp->set_rate(d_pref_quad_rate/d_quad_rate); + unlock(); + } +} + +float receiver_base_cf::get_signal_level() +{ + return meter->get_level_db(); +} + bool receiver_base_cf::has_nb() { return false; @@ -66,12 +90,12 @@ bool receiver_base_cf::has_sql() void receiver_base_cf::set_sql_level(double level_db) { - (void) level_db; + sql->set_threshold(level_db); } void receiver_base_cf::set_sql_alpha(double alpha) { - (void) alpha; + sql->set_alpha(alpha); } bool receiver_base_cf::has_agc() @@ -81,42 +105,42 @@ bool receiver_base_cf::has_agc() void receiver_base_cf::set_agc_on(bool agc_on) { - (void) agc_on; + agc->set_agc_on(agc_on); } void receiver_base_cf::set_agc_target_level(int target_level) { - (void) target_level; + agc->set_target_level(target_level); } void receiver_base_cf::set_agc_manual_gain(float gain) { - (void) gain; + agc->set_manual_gain(gain); } void receiver_base_cf::set_agc_max_gain(int gain) { - (void) gain; + agc->set_max_gain(gain); } void receiver_base_cf::set_agc_attack(int attack_ms) { - (void) attack_ms; + agc->set_attack(attack_ms); } void receiver_base_cf::set_agc_decay(int decay_ms) { - (void) decay_ms; + agc->set_decay(decay_ms); } void receiver_base_cf::set_agc_hang(int hang_ms) { - (void) hang_ms; + agc->set_hang(hang_ms); } float receiver_base_cf::get_agc_gain() { - return 0; + return agc->get_current_gain(); } bool receiver_base_cf::has_fm() diff --git a/src/receivers/receiver_base.h b/src/receivers/receiver_base.h index e9d8873db0..53785a14ba 100644 --- a/src/receivers/receiver_base.h +++ b/src/receivers/receiver_base.h @@ -24,6 +24,10 @@ #define RECEIVER_BASE_H #include +#include +#include "dsp/resampler_xx.h" +#include "dsp/rx_meter.h" +#include "dsp/rx_agc_xx.h" class receiver_base_cf; @@ -49,18 +53,18 @@ class receiver_base_cf : public gr::hier_block2 /*! \brief Public constructor. * \param src_name Descriptive name used in the constructor of gr::hier_block2 */ - receiver_base_cf(std::string src_name); + receiver_base_cf(std::string src_name, float pref_quad_rate, float quad_rate, int audio_rate); virtual ~receiver_base_cf(); virtual bool start() = 0; virtual bool stop() = 0; - virtual void set_quad_rate(float quad_rate) = 0; + virtual void set_quad_rate(float quad_rate); virtual void set_filter(double low, double high, double tw) = 0; virtual void set_cw_offset(double offset) = 0; - virtual float get_signal_level() = 0; + virtual float get_signal_level(); virtual void set_demod(int demod) = 0; @@ -106,7 +110,16 @@ class receiver_base_cf : public gr::hier_block2 virtual void stop_rds_decoder(); virtual void reset_rds_parser(); virtual bool is_rds_decoder_active(); - +protected: + float d_quad_rate; /*!< Input sample rate. */ + int d_audio_rate; /*!< Audio output rate. */ + + resampler_cc_sptr iq_resamp; /*!< Baseband resampler. */ + rx_meter_c_sptr meter; /*!< Signal strength. */ + rx_agc_2f_sptr agc; /*!< Receiver AGC. */ + gr::analog::simple_squelch_cc::sptr sql; /*!< Squelch. */ +private: + float d_pref_quad_rate; }; #endif // RECEIVER_BASE_H diff --git a/src/receivers/wfmrx.cpp b/src/receivers/wfmrx.cpp index 28e969bb4b..b35aa78089 100644 --- a/src/receivers/wfmrx.cpp +++ b/src/receivers/wfmrx.cpp @@ -34,18 +34,12 @@ wfmrx_sptr make_wfmrx(float quad_rate, float audio_rate) } wfmrx::wfmrx(float quad_rate, float audio_rate) - : receiver_base_cf("WFMRX"), + : receiver_base_cf("WFMRX", PREF_QUAD_RATE, quad_rate, audio_rate), d_running(false), - d_quad_rate(quad_rate), - d_audio_rate(audio_rate), d_demod(WFMRX_DEMOD_MONO) { - iq_resamp = make_resampler_cc(PREF_QUAD_RATE/d_quad_rate); filter = make_rx_filter(PREF_QUAD_RATE, -80000.0, 80000.0, 20000.0); - agc = make_rx_agc_2f(d_audio_rate, true, 0, 0, 100, 500, 500, 0); - sql = gr::analog::simple_squelch_cc::make(-150.0, 0.001); - meter = make_rx_meter_c(PREF_QUAD_RATE); demod_fm = make_rx_demod_fm(PREF_QUAD_RATE, 75000.0, 0.0); stereo = make_stereo_demod(PREF_QUAD_RATE, d_audio_rate, true); stereo_oirt = make_stereo_demod(PREF_QUAD_RATE, d_audio_rate, true, true); @@ -89,96 +83,11 @@ bool wfmrx::stop() return true; } -void wfmrx::set_quad_rate(float quad_rate) -{ - if (std::abs(d_quad_rate-quad_rate) > 0.5) - { - qDebug() << "Changing WFM RX quad rate:" << d_quad_rate << "->" << quad_rate; - d_quad_rate = quad_rate; - lock(); - iq_resamp->set_rate(PREF_QUAD_RATE/d_quad_rate); - unlock(); - } -} - void wfmrx::set_filter(double low, double high, double tw) { filter->set_param(low, high, tw); } -float wfmrx::get_signal_level() -{ - return meter->get_level_db(); -} - -/* -void wfmrx::set_nb_on(int nbid, bool on) -{ - if (nbid == 1) - nb->set_nb1_on(on); - else if (nbid == 2) - nb->set_nb2_on(on); -} - -void wfmrx::set_nb_threshold(int nbid, float threshold) -{ - if (nbid == 1) - nb->set_threshold1(threshold); - else if (nbid == 2) - nb->set_threshold2(threshold); -} -*/ - -void wfmrx::set_sql_level(double level_db) -{ - sql->set_threshold(level_db); -} - -void wfmrx::set_sql_alpha(double alpha) -{ - sql->set_alpha(alpha); -} - -void wfmrx::set_agc_on(bool agc_on) -{ - agc->set_agc_on(agc_on); -} - -void wfmrx::set_agc_target_level(int target_level) -{ - agc->set_target_level(target_level); -} - -void wfmrx::set_agc_manual_gain(float gain) -{ - agc->set_manual_gain(gain); -} - -void wfmrx::set_agc_max_gain(int gain) -{ - agc->set_max_gain(gain); -} - -void wfmrx::set_agc_attack(int attack_ms) -{ - agc->set_attack(attack_ms); -} - -void wfmrx::set_agc_decay(int decay_ms) -{ - agc->set_decay(decay_ms); -} - -void wfmrx::set_agc_hang(int hang_ms) -{ - agc->set_hang(hang_ms); -} - -float wfmrx::get_agc_gain() -{ - return agc->get_current_gain(); -} - void wfmrx::set_demod(int demod) { /* check if new demodulator selection is valid */ diff --git a/src/receivers/wfmrx.h b/src/receivers/wfmrx.h index e0f1643560..2c05a12fc1 100644 --- a/src/receivers/wfmrx.h +++ b/src/receivers/wfmrx.h @@ -24,18 +24,14 @@ #ifndef WFMRX_H #define WFMRX_H -#include #include "receivers/receiver_base.h" #include "dsp/rx_noise_blanker_cc.h" #include "dsp/rx_filter.h" -#include "dsp/rx_meter.h" #include "dsp/rx_demod_fm.h" #include "dsp/stereo_demod.h" -#include "dsp/resampler_xx.h" #include "dsp/rx_rds.h" #include "dsp/rds/decoder.h" #include "dsp/rds/parser.h" -#include "dsp/rx_agc_xx.h" class wfmrx; @@ -70,13 +66,10 @@ class wfmrx : public receiver_base_cf bool start(); bool stop(); - void set_quad_rate(float quad_rate); void set_filter(double low, double high, double tw); void set_cw_offset(double offset) { (void)offset; } - float get_signal_level(); - /* Noise blanker */ bool has_nb() { return false; } //void set_nb_on(int nbid, bool on); @@ -84,19 +77,9 @@ class wfmrx : public receiver_base_cf /* Squelch parameter */ bool has_sql() { return true; } - void set_sql_level(double level_db); - void set_sql_alpha(double alpha); /* AGC */ bool has_agc() { return true; } - void set_agc_on(bool agc_on); - void set_agc_target_level(int target_level); - void set_agc_manual_gain(float gain); - void set_agc_max_gain(int gain); - void set_agc_attack(int attack_ms); - void set_agc_decay(int decay_ms); - void set_agc_hang(int hang_ms); - float get_agc_gain(); void set_demod(int demod); @@ -113,17 +96,11 @@ class wfmrx : public receiver_base_cf private: bool d_running; /*!< Whether receiver is running or not. */ - float d_quad_rate; /*!< Input sample rate. */ - int d_audio_rate; /*!< Audio output rate. */ wfmrx_demod d_demod; /*!< Current demodulator. */ - resampler_cc_sptr iq_resamp; /*!< Baseband resampler. */ rx_filter_sptr filter; /*!< Non-translating bandpass filter.*/ - rx_meter_c_sptr meter; /*!< Signal strength. */ - rx_agc_2f_sptr agc; /*!< Receiver AGC. */ - gr::analog::simple_squelch_cc::sptr sql; /*!< Squelch. */ rx_demod_fm_sptr demod_fm; /*!< FM demodulator. */ stereo_demod_sptr stereo; /*!< FM stereo demodulator. */ stereo_demod_sptr stereo_oirt; /*!< FM stereo oirt demodulator. */