forked from sdr/gr-osmosdr
bladerf: implement DC offset and IQ imbalance correction
This patch has been provided by Brent J.
This commit is contained in:
parent
80c4af4f31
commit
e68f8505df
|
@ -43,6 +43,15 @@
|
||||||
/* We currently read/write 1024 samples (pairs of 16-bit signed ints) */
|
/* We currently read/write 1024 samples (pairs of 16-bit signed ints) */
|
||||||
#define BLADERF_SAMPLE_BLOCK_SIZE (1024)
|
#define BLADERF_SAMPLE_BLOCK_SIZE (1024)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BladeRF IQ correction defines
|
||||||
|
*/
|
||||||
|
#define BLADERF_RX_DC_RANGE 63
|
||||||
|
#define BLADERF_TX_DC_RANGE 127
|
||||||
|
#define BLADERF_GAIN_ZERO 4096
|
||||||
|
#define BLADERF_GAIN_RANGE 4096
|
||||||
|
#define BLADERF_PHASE_RANGE 2048
|
||||||
|
|
||||||
typedef boost::shared_ptr<struct bladerf> bladerf_sptr;
|
typedef boost::shared_ptr<struct bladerf> bladerf_sptr;
|
||||||
|
|
||||||
class bladerf_common
|
class bladerf_common
|
||||||
|
|
|
@ -520,6 +520,50 @@ std::string bladerf_sink_c::get_antenna( size_t chan )
|
||||||
return "TX";
|
return "TX";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bladerf_sink_c::set_dc_offset( const std::complex<double> &offset, size_t chan )
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int16_t val_i,val_q;
|
||||||
|
|
||||||
|
//the lms dc correction provides for 6 bits of DC correction and 1 sign bit
|
||||||
|
//scale the correction appropriately
|
||||||
|
val_i = (int16_t)(fabs(offset.real()) * BLADERF_TX_DC_RANGE);
|
||||||
|
val_q = (int16_t)(fabs(offset.imag()) * BLADERF_TX_DC_RANGE);
|
||||||
|
|
||||||
|
|
||||||
|
val_i = (offset.real() > 0) ? val_i : -val_i;
|
||||||
|
val_q = (offset.imag() > 0) ? val_q : -val_q;
|
||||||
|
|
||||||
|
ret = bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_TX_DC_I, val_i);
|
||||||
|
ret |= bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_TX_DC_Q, val_q);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
|
"could not set dc offset: " +
|
||||||
|
std::string(bladerf_strerror(ret)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bladerf_sink_c::set_iq_balance( const std::complex<double> &balance, size_t chan )
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int16_t val_gain,val_phase;
|
||||||
|
|
||||||
|
//FPGA gain correction defines 0.0 as BLADERF_GAIN_ZERO, scale the offset range to +/- BLADERF_GAIN_RANGE
|
||||||
|
val_gain = (int16_t)(balance.real() * (int16_t)BLADERF_GAIN_RANGE) + BLADERF_GAIN_ZERO;
|
||||||
|
//FPGA phase correction steps from -45 to 45 degrees
|
||||||
|
val_phase = (int16_t)(balance.imag() * BLADERF_PHASE_RANGE);
|
||||||
|
|
||||||
|
ret = bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_TX_GAIN, val_gain);
|
||||||
|
ret |= bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_TX_PHASE, val_phase);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
|
"could not set iq balance: " +
|
||||||
|
std::string(bladerf_strerror(ret)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double bladerf_sink_c::set_bandwidth( double bandwidth, size_t chan )
|
double bladerf_sink_c::set_bandwidth( double bandwidth, size_t chan )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -531,8 +575,8 @@ double bladerf_sink_c::set_bandwidth( double bandwidth, size_t chan )
|
||||||
ret = bladerf_set_bandwidth( _dev.get(), BLADERF_MODULE_TX, (uint32_t)bandwidth, &actual );
|
ret = bladerf_set_bandwidth( _dev.get(), BLADERF_MODULE_TX, (uint32_t)bandwidth, &actual );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"Could not set bandwidth, error " +
|
"could not set bandwidth:" +
|
||||||
boost::lexical_cast<std::string>(ret) );
|
std::string(bladerf_strerror(ret)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_bandwidth();
|
return get_bandwidth();
|
||||||
|
@ -546,8 +590,8 @@ double bladerf_sink_c::get_bandwidth( size_t chan )
|
||||||
ret = bladerf_get_bandwidth( _dev.get(), BLADERF_MODULE_TX, &bandwidth );
|
ret = bladerf_get_bandwidth( _dev.get(), BLADERF_MODULE_TX, &bandwidth );
|
||||||
if( ret ) {
|
if( ret ) {
|
||||||
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
"Could not get bandwidth, error " +
|
"could not get bandwidth: " +
|
||||||
boost::lexical_cast<std::string>(ret) );
|
std::string(bladerf_strerror(ret)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return (double)bandwidth;
|
return (double)bandwidth;
|
||||||
|
|
|
@ -102,6 +102,9 @@ public:
|
||||||
std::string set_antenna( const std::string & antenna, size_t chan = 0 );
|
std::string set_antenna( const std::string & antenna, size_t chan = 0 );
|
||||||
std::string get_antenna( size_t chan = 0 );
|
std::string get_antenna( size_t chan = 0 );
|
||||||
|
|
||||||
|
void set_dc_offset( const std::complex<double> &offset, size_t chan );
|
||||||
|
void set_iq_balance( const std::complex<double> &balance, size_t chan );
|
||||||
|
|
||||||
double set_bandwidth( double bandwidth, size_t chan = 0 );
|
double set_bandwidth( double bandwidth, size_t chan = 0 );
|
||||||
double get_bandwidth( size_t chan = 0 );
|
double get_bandwidth( size_t chan = 0 );
|
||||||
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
osmosdr::freq_range_t get_bandwidth_range( size_t chan = 0 );
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
|
|
||||||
#define BLADERF_SAMPLE_FIFO_MIN_SIZE (3 * BLADERF_SAMPLE_BLOCK_SIZE)
|
#define BLADERF_SAMPLE_FIFO_MIN_SIZE (3 * BLADERF_SAMPLE_BLOCK_SIZE)
|
||||||
|
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -561,40 +560,71 @@ std::string bladerf_source_c::get_antenna( size_t chan )
|
||||||
|
|
||||||
void bladerf_source_c::set_dc_offset_mode( int mode, size_t chan )
|
void bladerf_source_c::set_dc_offset_mode( int mode, size_t chan )
|
||||||
{
|
{
|
||||||
std::cerr << __FUNCTION__ << " mode: " << mode << std::endl; /* TODO: remove */
|
|
||||||
|
|
||||||
if ( osmosdr::source::DCOffsetOff == mode ) {
|
if ( osmosdr::source::DCOffsetOff == mode ) {
|
||||||
//_src->set_auto_dc_offset( false, chan );
|
//_src->set_auto_dc_offset( false, chan );
|
||||||
//_src->set_dc_offset( std::complex<double>(0.0, 0.0), chan ); /* TODO: reset to default for off-state */
|
set_dc_offset( std::complex<double>(0.0, 0.0), chan ); /* reset to default for off-state */
|
||||||
} else if ( osmosdr::source::DCOffsetManual == mode ) {
|
} else if ( osmosdr::source::DCOffsetManual == mode ) {
|
||||||
//_src->set_auto_dc_offset( false, chan ); /* disable auto mode, but keep correcting with last known values */
|
//_src->set_auto_dc_offset( false, chan ); /* disable auto mode, but keep correcting with last known values */
|
||||||
} else if ( osmosdr::source::DCOffsetAutomatic == mode ) {
|
} else if ( osmosdr::source::DCOffsetAutomatic == mode ) {
|
||||||
//_src->set_auto_dc_offset( true, chan );
|
//_src->set_auto_dc_offset( true, chan );
|
||||||
|
std::cerr << "Automatic DC correction mode is not implemented." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_source_c::set_dc_offset( const std::complex<double> &offset, size_t chan )
|
void bladerf_source_c::set_dc_offset( const std::complex<double> &offset, size_t chan )
|
||||||
{
|
{
|
||||||
std::cerr << __FUNCTION__ << " offset: " << offset.real() << " " << offset.imag() << std::endl; /* TODO: remove */
|
int ret = 0;
|
||||||
|
int16_t val_i,val_q;
|
||||||
|
|
||||||
|
//the lms dc correction provides for 6 bits of DC correction and 1 sign bit
|
||||||
|
//scale the correction appropriately
|
||||||
|
val_i = (int16_t)(fabs(offset.real()) * BLADERF_RX_DC_RANGE);
|
||||||
|
val_q = (int16_t)(fabs(offset.imag()) * BLADERF_RX_DC_RANGE);
|
||||||
|
|
||||||
|
val_i = (offset.real() > 0) ? val_i : -val_i;
|
||||||
|
val_q = (offset.imag() > 0) ? val_q : -val_q;
|
||||||
|
|
||||||
|
ret = bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_RX_DC_I, val_i);
|
||||||
|
ret |= bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_RX_DC_Q, val_q);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
|
"could not set dc offset: " +
|
||||||
|
std::string(bladerf_strerror(ret)) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_source_c::set_iq_balance_mode( int mode, size_t chan )
|
void bladerf_source_c::set_iq_balance_mode( int mode, size_t chan )
|
||||||
{
|
{
|
||||||
std::cerr << __FUNCTION__ << " mode: " << mode << std::endl; /* TODO: remove */
|
|
||||||
|
|
||||||
if ( osmosdr::source::IQBalanceOff == mode ) {
|
if ( osmosdr::source::IQBalanceOff == mode ) {
|
||||||
//_src->set_auto_iq_balance( false, chan );
|
//_src->set_auto_iq_balance( false, chan );
|
||||||
//_src->set_iq_balance( std::complex<double>(0.0, 0.0), chan ); /* TODO: reset to default for off-state */
|
set_iq_balance( std::complex<double>(0.0, 0.0), chan ); /* reset to default for off-state */
|
||||||
} else if ( osmosdr::source::IQBalanceManual == mode ) {
|
} else if ( osmosdr::source::IQBalanceManual == mode ) {
|
||||||
//_src->set_auto_iq_balance( false, chan ); /* disable auto mode, but keep correcting with last known values */
|
//_src->set_auto_iq_balance( false, chan ); /* disable auto mode, but keep correcting with last known values */
|
||||||
} else if ( osmosdr::source::IQBalanceAutomatic == mode ) {
|
} else if ( osmosdr::source::IQBalanceAutomatic == mode ) {
|
||||||
//_src->set_auto_iq_balance( true, chan );
|
//_src->set_auto_iq_balance( true, chan );
|
||||||
|
std::cerr << "Automatic IQ correction mode is not implemented." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bladerf_source_c::set_iq_balance( const std::complex<double> &balance, size_t chan )
|
void bladerf_source_c::set_iq_balance( const std::complex<double> &balance, size_t chan )
|
||||||
{
|
{
|
||||||
std::cerr << __FUNCTION__ << " balance: " << balance.real() << " " << balance.imag() << std::endl; /* TODO: remove */
|
int ret = 0;
|
||||||
|
int16_t val_gain,val_phase;
|
||||||
|
|
||||||
|
//FPGA gain correction defines 0.0 as BLADERF_GAIN_ZERO, scale the offset range to +/- BLADERF_GAIN_RANGE
|
||||||
|
val_gain = (int16_t)(balance.real() * (int16_t)BLADERF_GAIN_RANGE) + BLADERF_GAIN_ZERO;
|
||||||
|
//FPGA phase correction steps from -45 to 45 degrees
|
||||||
|
val_phase = (int16_t)(balance.imag() * BLADERF_PHASE_RANGE);
|
||||||
|
|
||||||
|
ret = bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_RX_GAIN, val_gain);
|
||||||
|
ret |= bladerf_set_correction(_dev.get(), BLADERF_IQ_CORR_RX_PHASE, val_phase);
|
||||||
|
|
||||||
|
if( ret ) {
|
||||||
|
throw std::runtime_error( std::string(__FUNCTION__) + " " +
|
||||||
|
"could not set iq balance: " +
|
||||||
|
std::string(bladerf_strerror(ret)) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double bladerf_source_c::set_bandwidth( double bandwidth, size_t chan )
|
double bladerf_source_c::set_bandwidth( double bandwidth, size_t chan )
|
||||||
|
|
Loading…
Reference in New Issue