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.
This commit is contained in:
Dimitri Stolnikov 2012-07-18 21:24:57 +02:00
parent 0b5f48eb07
commit 86ec5d3b73
9 changed files with 195 additions and 130 deletions

View File

@ -26,7 +26,7 @@ MAIN_TMPL = """\
<category>Sources</category>
<throttle>1</throttle>
<import>import osmosdr</import>
<make>osmosdr.$(sourk)_c( args="nchan=" + str(\$nchan) + " " + \$args )
<make>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
</make>
</make>
<callback>set_sample_rate(\$sample_rate)</callback>
#for $n in range($max_nchan)
<callback>set_center_freq(\$freq$(n), $n)</callback>
<callback>set_freq_corr(\$corr$(n), $n)</callback>
<callback>set_gain_mode(\$gain_mode$(n), $n)</callback>
<callback>set_gain(\$gain$(n), $n)</callback>
<callback>set_if_gain(\$if_gain$(n), $n)</callback>
<callback>set_antenna(\$ant$(n), $n)</callback>
#end for
<param>
@ -100,18 +102,15 @@ self.\$(id).set_antenna(\$ant$(n), $n)
<doc>
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 = """
<param>
<name>Ch$(n): Frequency (Hz)</name>
<key>freq$(n)</key>
<value>0</value>
<value>100e6</value>
<type>real</type>
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
</param>
@ -168,13 +171,6 @@ PARAMS_TMPL = """
<type>real</type>
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
</param>
<param>
<name>Ch$(n): Gain (dB)</name>
<key>gain$(n)</key>
<value>0</value>
<type>real</type>
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
</param>
<param>
<name>Ch$(n): Gain Mode</name>
<key>gain_mode$(n)</key>
@ -190,6 +186,20 @@ PARAMS_TMPL = """
<key>1</key>
</option>
</param>
<param>
<name>Ch$(n): Gain (dB)</name>
<key>gain$(n)</key>
<value>10</value>
<type>real</type>
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
</param>
<param>
<name>Ch$(n): IF Gain (dB)</name>
<key>if_gain$(n)</key>
<value>20</value>
<type>real</type>
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
</param>
<param>
<name>Ch$(n): Antenna</name>
<key>ant$(n)</key>

View File

@ -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

View File

@ -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;

View File

@ -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 );

View File

@ -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 "";

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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 );