diff --git a/lib/osmosdr/osmosdr_src_c.cc b/lib/osmosdr/osmosdr_src_c.cc index 715049c..bba0550 100644 --- a/lib/osmosdr/osmosdr_src_c.cc +++ b/lib/osmosdr/osmosdr_src_c.cc @@ -409,10 +409,63 @@ 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 gains = osmosdr_src_c::get_gain_range( chan ); + osmosdr::gain_range_t rf_gains = osmosdr_src_c::get_gain_range( chan ); + std::vector< osmosdr::gain_range_t > if_gains; - if (_dev) - osmosdr_set_tuner_gain( _dev, int(gains.clip(gain) * 10.0) ); + 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)); + } + } return get_gain( chan ); }