From 86ec5d3b7383b31a493ac0a122386abb56be5bb4 Mon Sep 17 00:00:00 2001 From: Dimitri Stolnikov Date: Wed, 18 Jul 2012 21:24:57 +0200 Subject: [PATCH] add if gain setter API for rtl-sdr and OsmoSDR devices Observations lead to an useful gain range from 15 to 30dB, a value of 24dB is used by default. --- grc/gen_osmosdr_blocks.py | 50 ++++++++----- include/osmosdr/osmosdr_source_c.h | 10 +++ lib/osmosdr/osmosdr_src_c.cc | 113 +++++++++++++++-------------- lib/osmosdr/osmosdr_src_c.h | 2 + lib/osmosdr_source_c_impl.cc | 22 +++++- lib/osmosdr_source_c_impl.h | 3 + lib/osmosdr_src_iface.h | 10 +++ lib/rtl/rtl_source_c.cc | 113 +++++++++++++++-------------- lib/rtl/rtl_source_c.h | 2 + 9 files changed, 195 insertions(+), 130 deletions(-) diff --git a/grc/gen_osmosdr_blocks.py b/grc/gen_osmosdr_blocks.py index 8e9fbc2..d5631ca 100644 --- a/grc/gen_osmosdr_blocks.py +++ b/grc/gen_osmosdr_blocks.py @@ -26,7 +26,7 @@ MAIN_TMPL = """\ Sources 1 import osmosdr - osmosdr.$(sourk)_c( args="nchan=" + str(\$nchan) + " " + \$args ) + osmosdr.$(sourk)_c( args="nchan=" + str(\$nchan) + " " + \$args ) self.\$(id).set_sample_rate(\$sample_rate) #for $n in range($max_nchan) \#if \$nchan() > $n @@ -34,18 +34,20 @@ self.\$(id).set_center_freq(\$freq$(n), $n) self.\$(id).set_freq_corr(\$corr$(n), $n) self.\$(id).set_gain_mode(\$gain_mode$(n), $n) self.\$(id).set_gain(\$gain$(n), $n) +self.\$(id).set_if_gain(\$if_gain$(n), $n) \#if \$ant$(n)() self.\$(id).set_antenna(\$ant$(n), $n) \#end if \#end if #end for - + set_sample_rate(\$sample_rate) #for $n in range($max_nchan) set_center_freq(\$freq$(n), $n) set_freq_corr(\$corr$(n), $n) set_gain_mode(\$gain_mode$(n), $n) set_gain(\$gain$(n), $n) + set_if_gain(\$if_gain$(n), $n) set_antenna(\$ant$(n), $n) #end for @@ -100,18 +102,15 @@ self.\$(id).set_antenna(\$ant$(n), $n) The OsmoSDR $sourk.title() block: -While primarily being developed for the OsmoSDR hardware, this block also -supports the FunCube Dongle, Ettus UHD, rtl-sdr radios and cfile source. -By using the OsmoSDR block you can take advantage of a common software api in -your application(s) independent of the underlying radio hardware. +While primarily being developed for the OsmoSDR hardware, this block also supports the FunCube Dongle, Ettus UHD, rtl-sdr radios and cfile source. +By using the OsmoSDR block you can take advantage of a common software api in your application(s) independent of the underlying radio hardware. Output Type: This parameter controls the data type of the stream in gnuradio. Device Arguments: The device argument is a delimited string used to locate devices on your system. -Use the device id or name (if applicable) to specify a certain device or list -of devices. If left blank, the first device found will be used. +Use the device id or name (if applicable) to specify a certain device or list of devices. If left blank, the first device found will be used. Examples (some arguments may be optional): fcd=0 @@ -133,14 +132,18 @@ The center frequency is the overall frequency of the RF chain. Freq. Corr.: The frequency correction factor in parts per million (ppm). Leave 0 if unknown. -Gain: -Overall gain of the device's signal path. For the new gain value to be applied, -the manual gain mode must be enabled first. - Gain Mode: Chooses between the manual (default) and automatic gain mode where appropriate. Currently, only rtlsdr devices support automatic gain mode. +Gain: +Overall gain of the device's signal path. For the new gain value to be applied, the manual gain mode must be enabled first. + +IF Gain: +Overall IF gain of the device's signal path. For the new gain value to be applied, the manual gain mode must be enabled first. +This setting has only effect for rtl-sdr and OsmoSDR devices with E4000 tuners. +Observations lead to an useful gain range from 15 to 30dB. + Antenna: For devices with only one antenna, this may be left blank. Otherwise, the user should specify one of the possible antenna choices. @@ -157,7 +160,7 @@ PARAMS_TMPL = """ Ch$(n): Frequency (Hz) freq$(n) - 0 + 100e6 real \#if \$nchan() > $n then 'none' else 'all'# @@ -168,13 +171,6 @@ PARAMS_TMPL = """ real \#if \$nchan() > $n then 'none' else 'all'# - - Ch$(n): Gain (dB) - gain$(n) - 0 - real - \#if \$nchan() > $n then 'none' else 'all'# - Ch$(n): Gain Mode gain_mode$(n) @@ -190,6 +186,20 @@ PARAMS_TMPL = """ 1 + + Ch$(n): Gain (dB) + gain$(n) + 10 + real + \#if \$nchan() > $n then 'none' else 'all'# + + + Ch$(n): IF Gain (dB) + if_gain$(n) + 20 + real + \#if \$nchan() > $n then 'none' else 'all'# + Ch$(n): Antenna ant$(n) diff --git a/include/osmosdr/osmosdr_source_c.h b/include/osmosdr/osmosdr_source_c.h index 425902d..55a9a0f 100644 --- a/include/osmosdr/osmosdr_source_c.h +++ b/include/osmosdr/osmosdr_source_c.h @@ -197,6 +197,16 @@ public: */ virtual double get_gain( const std::string & name, size_t chan = 0 ) = 0; + /*! + * Set the IF gain for the underlying radio hardware. + * This function will automatically distribute the desired gain value over + * available IF gain stages in an appropriate way and return the actual value. + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_if_gain( double gain, size_t chan = 0 ) = 0; + /*! * Get the available antennas of the underlying radio hardware. * \param chan the channel index 0 to N-1 diff --git a/lib/osmosdr/osmosdr_src_c.cc b/lib/osmosdr/osmosdr_src_c.cc index bba0550..68c4a27 100644 --- a/lib/osmosdr/osmosdr_src_c.cc +++ b/lib/osmosdr/osmosdr_src_c.cc @@ -131,6 +131,8 @@ osmosdr_src_c::osmosdr_src_c (const std::string &args) if (ret < 0) throw std::runtime_error("Failed to reset usb buffers."); + set_if_gain( 24 ); /* preset to a reasonable default (non-GRC use case) */ + _buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *)); for(unsigned int i = 0; i < _buf_num; ++i) @@ -410,61 +412,9 @@ bool osmosdr_src_c::get_gain_mode( size_t chan ) double osmosdr_src_c::set_gain( double gain, size_t chan ) { osmosdr::gain_range_t rf_gains = osmosdr_src_c::get_gain_range( chan ); - std::vector< osmosdr::gain_range_t > if_gains; - if_gains += osmosdr::gain_range_t(-3, 6, 9); - if_gains += osmosdr::gain_range_t(0, 9, 3); - if_gains += osmosdr::gain_range_t(0, 9, 3); - if_gains += osmosdr::gain_range_t(0, 2, 1); - if_gains += osmosdr::gain_range_t(3, 15, 3); - if_gains += osmosdr::gain_range_t(3, 15, 3); - - double rf_gain = rf_gains.clip(gain); - double missing_gain = gain - rf_gain; - - std::map< int, double > gains; - - /* initialize with min gains */ - for (unsigned int i = 0; i < if_gains.size(); i++) { - gains[ i + 1 ] = if_gains[ i ].start(); - } - - for (int i = if_gains.size() - 1; i >= 0; i--) { - osmosdr::gain_range_t range = if_gains[ i ]; - - double error = missing_gain; - - for( double g = range.start(); g <= range.stop(); g += range.step() ) { - - double sum = 0; - for (int j = 0; j < int(gains.size()); j++) { - if ( i == j ) - sum += g; - else - sum += gains[ j + 1 ]; - } - - double err = abs(missing_gain - sum); - if (err < error) { - error = err; - gains[ i + 1 ] = g; - } - } - } -#if 0 - std::cerr << missing_gain << " => "; double sum = 0; - for (unsigned int i = 0; i < gains.size(); i++) { - sum += gains[ i + 1 ]; - std::cerr << gains[ i + 1 ] << " "; - } - std::cerr << " = " << sum << std::endl; -#endif if (_dev) { - osmosdr_set_tuner_gain( _dev, int(rf_gain * 10.0) ); - - for (unsigned int stage = 1; stage <= gains.size(); stage++) { - osmosdr_set_tuner_if_gain( _dev, stage, int(gains[ stage ] * 10.0)); - } + osmosdr_set_tuner_gain( _dev, int(rf_gains.clip(gain) * 10.0) ); } return get_gain( chan ); @@ -488,6 +438,63 @@ double osmosdr_src_c::get_gain( const std::string & name, size_t chan ) return get_gain( chan ); } +double osmosdr_src_c::set_if_gain(double gain, size_t chan) +{ + std::vector< osmosdr::gain_range_t > if_gains; + + if_gains += osmosdr::gain_range_t(-3, 6, 9); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 2, 1); + if_gains += osmosdr::gain_range_t(3, 15, 3); + if_gains += osmosdr::gain_range_t(3, 15, 3); + + std::map< int, double > gains; + + /* initialize with min gains */ + for (unsigned int i = 0; i < if_gains.size(); i++) { + gains[ i + 1 ] = if_gains[ i ].start(); + } + + for (int i = if_gains.size() - 1; i >= 0; i--) { + osmosdr::gain_range_t range = if_gains[ i ]; + + double error = gain; + + for( double g = range.start(); g <= range.stop(); g += range.step() ) { + + double sum = 0; + for (int j = 0; j < int(gains.size()); j++) { + if ( i == j ) + sum += g; + else + sum += gains[ j + 1 ]; + } + + double err = abs(gain - sum); + if (err < error) { + error = err; + gains[ i + 1 ] = g; + } + } + } +#if 0 + std::cerr << gain << " => "; double sum = 0; + for (unsigned int i = 0; i < gains.size(); i++) { + sum += gains[ i + 1 ]; + std::cerr << gains[ i + 1 ] << " "; + } + std::cerr << " = " << sum << std::endl; +#endif + if (_dev) { + for (unsigned int stage = 1; stage <= gains.size(); stage++) { + osmosdr_set_tuner_if_gain( _dev, stage, int(gains[ stage ] * 10.0)); + } + } + + return gain; +} + std::vector< std::string > osmosdr_src_c::get_antennas( size_t chan ) { std::vector< std::string > antennas; diff --git a/lib/osmosdr/osmosdr_src_c.h b/lib/osmosdr/osmosdr_src_c.h index 227ccae..9156454 100644 --- a/lib/osmosdr/osmosdr_src_c.h +++ b/lib/osmosdr/osmosdr_src_c.h @@ -105,6 +105,8 @@ private: double get_gain( size_t chan = 0 ); double get_gain( const std::string & name, size_t chan = 0 ); + double set_if_gain( double gain, size_t chan = 0 ); + std::vector< std::string > get_antennas( size_t chan = 0 ); std::string set_antenna( const std::string & antenna, size_t chan = 0 ); std::string get_antenna( size_t chan = 0 ); diff --git a/lib/osmosdr_source_c_impl.cc b/lib/osmosdr_source_c_impl.cc index 4c5c3f9..5eec5c8 100644 --- a/lib/osmosdr_source_c_impl.cc +++ b/lib/osmosdr_source_c_impl.cc @@ -227,7 +227,7 @@ double osmosdr_source_c_impl::set_sample_rate(double rate) if (_sample_rate != rate) { BOOST_FOREACH( osmosdr_src_iface *dev, _devs ) - sample_rate = dev->set_sample_rate(rate); + sample_rate = dev->set_sample_rate(rate); _sample_rate = sample_rate; } @@ -382,7 +382,7 @@ double osmosdr_source_c_impl::set_gain( double gain, const std::string & name, s BOOST_FOREACH( osmosdr_src_iface *dev, _devs ) for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) - return dev->set_gain( gain, name, dev_chan ); + return dev->set_gain( gain, name, dev_chan ); return 0; } @@ -409,6 +409,20 @@ double osmosdr_source_c_impl::get_gain( const std::string & name, size_t chan ) return 0; } +double osmosdr_source_c_impl::set_if_gain(double gain, size_t chan) +{ + size_t channel = 0; + BOOST_FOREACH( osmosdr_src_iface *dev, _devs ) + for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) + if ( chan == channel++ ) + if ( _if_gain[ chan ] != gain ) { + _if_gain[ chan ] = gain; + return dev->set_if_gain( gain, dev_chan ); + } + + return 0; +} + std::vector< std::string > osmosdr_source_c_impl::get_antennas( size_t chan ) { size_t channel = 0; @@ -427,8 +441,8 @@ std::string osmosdr_source_c_impl::set_antenna( const std::string & antenna, siz for (size_t dev_chan = 0; dev_chan < dev->get_num_channels(); dev_chan++) if ( chan == channel++ ) if ( _antenna[ chan ] != antenna ) { - _antenna[ chan ] = antenna; - return dev->set_antenna( antenna, dev_chan ); + _antenna[ chan ] = antenna; + return dev->set_antenna( antenna, dev_chan ); } return ""; diff --git a/lib/osmosdr_source_c_impl.h b/lib/osmosdr_source_c_impl.h index 1bdf6b3..a34bf3b 100644 --- a/lib/osmosdr_source_c_impl.h +++ b/lib/osmosdr_source_c_impl.h @@ -51,6 +51,8 @@ public: double get_gain( size_t chan = 0 ); double get_gain( const std::string & name, size_t chan = 0 ); + double set_if_gain( double gain, size_t chan = 0 ); + std::vector< std::string > get_antennas( size_t chan = 0 ); std::string set_antenna( const std::string & antenna, size_t chan = 0 ); std::string get_antenna( size_t chan = 0 ); @@ -67,6 +69,7 @@ private: std::map< size_t, double > _freq_corr; std::map< size_t, bool > _gain_mode; std::map< size_t, double > _gain; + std::map< size_t, double > _if_gain; std::map< size_t, std::string > _antenna; std::vector< osmosdr_src_iface * > _devs; }; diff --git a/lib/osmosdr_src_iface.h b/lib/osmosdr_src_iface.h index b9ab9f8..a169e0d 100644 --- a/lib/osmosdr_src_iface.h +++ b/lib/osmosdr_src_iface.h @@ -175,6 +175,16 @@ public: */ virtual double get_gain( const std::string & name, size_t chan = 0 ) = 0; + /*! + * Set the IF gain for the underlying radio hardware. + * This function will automatically distribute the desired gain value over + * available IF gain stages in an appropriate way and return the actual value. + * \param gain the gain in dB + * \param chan the channel index 0 to N-1 + * \return the actual gain in dB + */ + virtual double set_if_gain( double gain, size_t chan = 0 ) { return 0; } + /*! * Get the available antennas of the underlying radio hardware. * \param chan the channel index 0 to N-1 diff --git a/lib/rtl/rtl_source_c.cc b/lib/rtl/rtl_source_c.cc index 3a16bff..18db321 100644 --- a/lib/rtl/rtl_source_c.cc +++ b/lib/rtl/rtl_source_c.cc @@ -158,6 +158,8 @@ rtl_source_c::rtl_source_c (const std::string &args) if (ret < 0) throw std::runtime_error("Failed to reset usb buffers."); + set_if_gain( 24 ); /* preset to a reasonable default (non-GRC use case) */ + _buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *)); for(unsigned int i = 0; i < _buf_num; ++i) @@ -441,61 +443,9 @@ bool rtl_source_c::get_gain_mode( size_t chan ) double rtl_source_c::set_gain( double gain, size_t chan ) { osmosdr::gain_range_t rf_gains = rtl_source_c::get_gain_range( chan ); - std::vector< osmosdr::gain_range_t > if_gains; - if_gains += osmosdr::gain_range_t(-3, 6, 9); - if_gains += osmosdr::gain_range_t(0, 9, 3); - if_gains += osmosdr::gain_range_t(0, 9, 3); - if_gains += osmosdr::gain_range_t(0, 2, 1); - if_gains += osmosdr::gain_range_t(3, 15, 3); - if_gains += osmosdr::gain_range_t(3, 15, 3); - - double rf_gain = rf_gains.clip(gain); - double missing_gain = gain - rf_gain; - - std::map< int, double > gains; - - /* initialize with min gains */ - for (unsigned int i = 0; i < if_gains.size(); i++) { - gains[ i + 1 ] = if_gains[ i ].start(); - } - - for (int i = if_gains.size() - 1; i >= 0; i--) { - osmosdr::gain_range_t range = if_gains[ i ]; - - double error = missing_gain; - - for( double g = range.start(); g <= range.stop(); g += range.step() ) { - - double sum = 0; - for (int j = 0; j < int(gains.size()); j++) { - if ( i == j ) - sum += g; - else - sum += gains[ j + 1 ]; - } - - double err = abs(missing_gain - sum); - if (err < error) { - error = err; - gains[ i + 1 ] = g; - } - } - } -#if 0 - std::cerr << missing_gain << " => "; double sum = 0; - for (unsigned int i = 0; i < gains.size(); i++) { - sum += gains[ i + 1 ]; - std::cerr << gains[ i + 1 ] << " "; - } - std::cerr << " = " << sum << std::endl; -#endif if (_dev) { - rtlsdr_set_tuner_gain( _dev, int(rf_gain * 10.0) ); - - for (unsigned int stage = 1; stage <= gains.size(); stage++) { - rtlsdr_set_tuner_if_gain( _dev, stage, int(gains[ stage ] * 10.0)); - } + rtlsdr_set_tuner_gain( _dev, int(rf_gains.clip(gain) * 10.0) ); } return get_gain( chan ); @@ -519,6 +469,63 @@ double rtl_source_c::get_gain( const std::string & name, size_t chan ) return get_gain( chan ); } +double rtl_source_c::set_if_gain(double gain, size_t chan) +{ + std::vector< osmosdr::gain_range_t > if_gains; + + if_gains += osmosdr::gain_range_t(-3, 6, 9); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 9, 3); + if_gains += osmosdr::gain_range_t(0, 2, 1); + if_gains += osmosdr::gain_range_t(3, 15, 3); + if_gains += osmosdr::gain_range_t(3, 15, 3); + + std::map< int, double > gains; + + /* initialize with min gains */ + for (unsigned int i = 0; i < if_gains.size(); i++) { + gains[ i + 1 ] = if_gains[ i ].start(); + } + + for (int i = if_gains.size() - 1; i >= 0; i--) { + osmosdr::gain_range_t range = if_gains[ i ]; + + double error = gain; + + for( double g = range.start(); g <= range.stop(); g += range.step() ) { + + double sum = 0; + for (int j = 0; j < int(gains.size()); j++) { + if ( i == j ) + sum += g; + else + sum += gains[ j + 1 ]; + } + + double err = abs(gain - sum); + if (err < error) { + error = err; + gains[ i + 1 ] = g; + } + } + } +#if 0 + std::cerr << gain << " => "; double sum = 0; + for (unsigned int i = 0; i < gains.size(); i++) { + sum += gains[ i + 1 ]; + std::cerr << gains[ i + 1 ] << " "; + } + std::cerr << " = " << sum << std::endl; +#endif + if (_dev) { + for (unsigned int stage = 1; stage <= gains.size(); stage++) { + rtlsdr_set_tuner_if_gain( _dev, stage, int(gains[ stage ] * 10.0)); + } + } + + return gain; +} + std::vector< std::string > rtl_source_c::get_antennas( size_t chan ) { std::vector< std::string > antennas; diff --git a/lib/rtl/rtl_source_c.h b/lib/rtl/rtl_source_c.h index 70dcf0e..5f4ccdd 100644 --- a/lib/rtl/rtl_source_c.h +++ b/lib/rtl/rtl_source_c.h @@ -106,6 +106,8 @@ public: double get_gain( size_t chan = 0 ); double get_gain( const std::string & name, size_t chan = 0 ); + double set_if_gain( double gain, size_t chan = 0 ); + std::vector< std::string > get_antennas( size_t chan = 0 ); std::string set_antenna( const std::string & antenna, size_t chan = 0 ); std::string get_antenna( size_t chan = 0 );