forked from sdr/gr-osmosdr
add support for software IQ imbalance correction
this functionality depend on the gr-iqbal blocks developed by Sylvain Munaut and is a compile time dependency: http://cgit.osmocom.org/cgit/gr-iqbalgr3.6
parent
ede9c80455
commit
e415d843c7
|
@ -109,6 +109,7 @@ set(GRC_BLOCKS_DIR ${GR_PKG_DATA_DIR}/grc/blocks)
|
|||
########################################################################
|
||||
find_package(Gruel)
|
||||
find_package(GnuradioCore)
|
||||
find_package(GnuradioIQBalance)
|
||||
find_package(UHD)
|
||||
find_package(GnuradioUHD)
|
||||
find_package(GnuradioFCD)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(PC_GNURADIO_IQBALANCE gnuradio-iqbalance)
|
||||
|
||||
FIND_PATH(
|
||||
GNURADIO_IQBALANCE_INCLUDE_DIRS
|
||||
NAMES iqbalance_api.h
|
||||
HINTS $ENV{GNURADIO_IQBALANCE_DIR}/include/iqbalance
|
||||
${PC_GNURADIO_IQBALANCE_INCLUDEDIR}
|
||||
${CMAKE_INSTALL_PREFIX}/include/iqbalance
|
||||
PATHS /usr/local/include/iqbalance
|
||||
/usr/include/iqbalance
|
||||
)
|
||||
|
||||
FIND_LIBRARY(
|
||||
GNURADIO_IQBALANCE_LIBRARIES
|
||||
NAMES gnuradio-iqbalance
|
||||
HINTS $ENV{GNURADIO_IQBALANCE_DIR}/lib
|
||||
${PC_GNURADIO_IQBALANCE_LIBDIR}
|
||||
${CMAKE_INSTALL_PREFIX}/lib64
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
PATHS /usr/local/lib
|
||||
/usr/local/lib64
|
||||
/usr/lib
|
||||
/usr/lib64
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_IQBALANCE DEFAULT_MSG GNURADIO_IQBALANCE_LIBRARIES GNURADIO_IQBALANCE_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(GNURADIO_IQBALANCE_LIBRARIES GNURADIO_IQBALANCE_INCLUDE_DIRS)
|
|
@ -32,6 +32,7 @@ self.\$(id).set_sample_rate(\$sample_rate)
|
|||
\#if \$nchan() > $n
|
||||
self.\$(id).set_center_freq(\$freq$(n), $n)
|
||||
self.\$(id).set_freq_corr(\$corr$(n), $n)
|
||||
self.\$(id).set_iq_balance_mode(\$iq_balance_mode$(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)
|
||||
|
@ -45,6 +46,7 @@ self.\$(id).set_antenna(\$ant$(n), $n)
|
|||
#for $n in range($max_nchan)
|
||||
<callback>set_center_freq(\$freq$(n), $n)</callback>
|
||||
<callback>set_freq_corr(\$corr$(n), $n)</callback>
|
||||
<callback>set_iq_balance_mode(\$iq_balance_mode$(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>
|
||||
|
@ -149,6 +151,14 @@ The center frequency is the frequency the RF chain is tuned to.
|
|||
Freq. Corr.:
|
||||
The frequency correction factor in parts per million (ppm). Set to 0 if unknown.
|
||||
|
||||
IQ Balance Mode:
|
||||
Controls the behavior of software IQ imbalance corrrection.
|
||||
Off: Disable correction algorithm (pass through)
|
||||
Manual: Keep last estimated correction when switched from Automatic to Manual
|
||||
Automatic: Find the best solution to compensate for image signals.
|
||||
|
||||
This functionality depends on http://cgit.osmocom.org/cgit/gr-iqbal/
|
||||
|
||||
Gain Mode:
|
||||
Chooses between the manual (default) and automatic gain mode where appropriate.
|
||||
Currently, only rtlsdr devices support automatic gain mode.
|
||||
|
@ -187,6 +197,25 @@ PARAMS_TMPL = """
|
|||
<type>real</type>
|
||||
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
|
||||
</param>
|
||||
<param>
|
||||
<name>Ch$(n): IQ Balance Mode</name>
|
||||
<key>iq_balance_mode$(n)</key>
|
||||
<value>0</value>
|
||||
<type>int</type>
|
||||
<hide>\#if \$nchan() > $n then 'none' else 'all'#</hide>
|
||||
<option>
|
||||
<name>Off</name>
|
||||
<key>0</key>
|
||||
</option>
|
||||
<option>
|
||||
<name>Manual</name>
|
||||
<key>1</key>
|
||||
</option>
|
||||
<option>
|
||||
<name>Automatic</name>
|
||||
<key>2</key>
|
||||
</option>
|
||||
</param>
|
||||
<param>
|
||||
<name>Ch$(n): Gain Mode</name>
|
||||
<key>gain_mode$(n)</key>
|
||||
|
@ -198,7 +227,7 @@ PARAMS_TMPL = """
|
|||
<key>0</key>
|
||||
</option>
|
||||
<option>
|
||||
<name>Auto</name>
|
||||
<name>Automatic</name>
|
||||
<key>1</key>
|
||||
</option>
|
||||
</param>
|
||||
|
|
|
@ -229,6 +229,30 @@ public:
|
|||
* \return antenna the actual antenna's name
|
||||
*/
|
||||
virtual std::string get_antenna( size_t chan = 0 ) = 0;
|
||||
|
||||
enum IQBalanceMode {
|
||||
IQBalanceOff = 0,
|
||||
IQBalanceManual,
|
||||
IQBalanceAutomatic
|
||||
};
|
||||
|
||||
/*!
|
||||
* Set the RX frontend IQ balance mode.
|
||||
*
|
||||
* \param mode iq balance correction mode: 0 = Off, 1 = Manual, 2 = Automatic
|
||||
* \param chan the channel index 0 to N-1
|
||||
*/
|
||||
virtual void set_iq_balance_mode( int mode, size_t chan = 0 ) = 0;
|
||||
|
||||
/*!
|
||||
* Set the RX frontend IQ balance correction.
|
||||
* Use this to adjust the magnitude and phase of I and Q.
|
||||
*
|
||||
* \param correction the complex correction value
|
||||
* \param chan the channel index 0 to N-1
|
||||
*/
|
||||
virtual void set_iq_balance( const std::complex<double> &correction,
|
||||
size_t chan = 0 ) = 0;
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_OSMOSDR_SOURCE_C_H */
|
||||
|
|
|
@ -47,6 +47,13 @@ GR_OSMOSDR_APPEND_LIBS(
|
|||
${GNURADIO_CORE_LIBRARIES}
|
||||
)
|
||||
|
||||
if(GNURADIO_IQBALANCE_FOUND)
|
||||
message(STATUS "Will build with gnuradio iqbalance support.")
|
||||
add_definitions(-DHAVE_IQBALANCE=1)
|
||||
include_directories(APPEND ${GNURADIO_IQBALANCE_INCLUDE_DIRS})
|
||||
GR_OSMOSDR_APPEND_LIBS(${GNURADIO_IQBALANCE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Setup OsmoSDR component
|
||||
########################################################################
|
||||
|
|
|
@ -173,70 +173,81 @@ osmosdr_source_c_impl::osmosdr_source_c_impl (const std::string &args)
|
|||
// BOOST_FOREACH( dict_t::value_type &entry, dict )
|
||||
// std::cerr << "'" << entry.first << "' = '" << entry.second << "'" << std::endl;
|
||||
|
||||
osmosdr_src_iface *iface = NULL;
|
||||
gr_basic_block_sptr block;
|
||||
|
||||
#ifdef ENABLE_OSMOSDR
|
||||
if ( dict.count("osmosdr") ) {
|
||||
osmosdr_src_c_sptr src = osmosdr_make_src_c( arg );
|
||||
|
||||
for (size_t i = 0; i < src->get_num_channels(); i++)
|
||||
connect(src, i, self(), channel++);
|
||||
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FCD
|
||||
if ( dict.count("fcd") ) {
|
||||
fcd_source_sptr src = make_fcd_source( arg );
|
||||
connect(src, 0, self(), channel++);
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FILE
|
||||
if ( dict.count("file") ) {
|
||||
file_source_c_sptr src = make_file_source_c( arg );
|
||||
connect(src, 0, self(), channel++);
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_RTL
|
||||
if ( dict.count("rtl") ) {
|
||||
rtl_source_c_sptr src = make_rtl_source_c( arg );
|
||||
connect(src, 0, self(), channel++);
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_RTL_TCP
|
||||
if ( dict.count("rtl_tcp") ) {
|
||||
rtl_tcp_source_c_sptr src = make_rtl_tcp_source_c( arg );
|
||||
connect(src, 0, self(), channel++);
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UHD
|
||||
if ( dict.count("uhd") ) {
|
||||
uhd_source_c_sptr src = make_uhd_source_c( arg );
|
||||
|
||||
for (size_t i = 0; i < src->get_num_channels(); i++)
|
||||
connect(src, i, self(), channel++);
|
||||
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MIRI
|
||||
if ( dict.count("miri") ) {
|
||||
miri_source_c_sptr src = make_miri_source_c( arg );
|
||||
|
||||
for (size_t i = 0; i < src->get_num_channels(); i++)
|
||||
connect(src, i, self(), channel++);
|
||||
|
||||
_devs.push_back( src.get() );
|
||||
block = src; iface = src.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( iface != NULL && long(block.get()) != 0 ) {
|
||||
_devs.push_back( iface );
|
||||
|
||||
for (size_t i = 0; i < iface->get_num_channels(); i++) {
|
||||
#ifdef HAVE_IQBALANCE
|
||||
iqbalance_optimize_c_sptr iq_opt = iqbalance_make_optimize_c( 0 );
|
||||
iqbalance_fix_cc_sptr iq_fix = iqbalance_make_fix_cc();
|
||||
|
||||
connect(block, i, iq_fix, 0);
|
||||
connect(iq_fix, 0, self(), channel++);
|
||||
|
||||
connect(block, i, iq_opt, 0);
|
||||
msg_connect(iq_opt, "iqbal_corr", iq_fix, "iqbal_corr");
|
||||
|
||||
_iq_opt.push_back( iq_opt.get() );
|
||||
_iq_fix.push_back( iq_fix.get() );
|
||||
#else
|
||||
connect(block, i, self(), channel++);
|
||||
#endif
|
||||
}
|
||||
} else if ( (iface != NULL) || (long(block.get()) != 0) )
|
||||
throw std::runtime_error("Eitner iface or block are NULL.");
|
||||
|
||||
}
|
||||
|
||||
if (!_devs.size())
|
||||
|
@ -305,6 +316,24 @@ double osmosdr_source_c_impl::set_sample_rate(double rate)
|
|||
BOOST_FOREACH( osmosdr_src_iface *dev, _devs )
|
||||
sample_rate = dev->set_sample_rate(rate);
|
||||
|
||||
#ifdef HAVE_IQBALANCE
|
||||
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 ( channel < _iq_opt.size() ) {
|
||||
iqbalance_optimize_c *opt = _iq_opt[channel];
|
||||
|
||||
if ( opt->period() > 0 ) { /* optimize is enabled */
|
||||
opt->set_period( dev->get_sample_rate() / 5 );
|
||||
opt->reset();
|
||||
}
|
||||
}
|
||||
|
||||
channel++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_sample_rate = sample_rate;
|
||||
}
|
||||
|
||||
|
@ -542,3 +571,61 @@ std::string osmosdr_source_c_impl::get_antenna( size_t chan )
|
|||
|
||||
return "";
|
||||
}
|
||||
|
||||
void osmosdr_source_c_impl::set_iq_balance_mode( int mode, size_t chan )
|
||||
{
|
||||
#ifdef HAVE_IQBALANCE
|
||||
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 ( chan < _iq_opt.size() && chan < _iq_fix.size() ) {
|
||||
iqbalance_optimize_c *opt = _iq_opt[chan];
|
||||
iqbalance_fix_cc *fix = _iq_fix[chan];
|
||||
|
||||
if ( IQBalanceOff == mode ) {
|
||||
opt->set_period( 0 );
|
||||
/* store current values in order to be able to restore them later */
|
||||
_vals[ chan ] = std::pair< float, float >( fix->mag(), fix->phase() );
|
||||
fix->set_mag( 0.0f );
|
||||
fix->set_phase( 0.0f );
|
||||
} else if ( IQBalanceManual == mode ) {
|
||||
if ( opt->period() == 0 ) { /* transition from Off to Manual */
|
||||
/* restore previous values */
|
||||
std::pair< float, float > val = _vals[ chan ];
|
||||
fix->set_mag( val.first );
|
||||
fix->set_phase( val.second );
|
||||
}
|
||||
opt->set_period( 0 );
|
||||
} else if ( IQBalanceAutomatic == mode ) {
|
||||
opt->set_period( dev->get_sample_rate() / 5 );
|
||||
opt->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void osmosdr_source_c_impl::set_iq_balance( const std::complex<double> &correction, size_t chan )
|
||||
{
|
||||
#ifdef HAVE_IQBALANCE
|
||||
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 ( chan < _iq_opt.size() && chan < _iq_fix.size() ) {
|
||||
iqbalance_optimize_c *opt = _iq_opt[chan];
|
||||
iqbalance_fix_cc *fix = _iq_fix[chan];
|
||||
|
||||
if ( opt->period() == 0 ) { /* automatic optimization desabled */
|
||||
fix->set_mag( correction.real() );
|
||||
fix->set_phase( correction.imag() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
|
||||
#include <osmosdr_source_c.h>
|
||||
|
||||
#ifdef HAVE_IQBALANCE
|
||||
#include <iqbalance_optimize_c.h>
|
||||
#include <iqbalance_fix_cc.h>
|
||||
#endif
|
||||
|
||||
#include <osmosdr_src_iface.h>
|
||||
|
||||
#include <map>
|
||||
|
@ -57,6 +62,9 @@ public:
|
|||
std::string set_antenna( const std::string & antenna, size_t chan = 0 );
|
||||
std::string get_antenna( size_t chan = 0 );
|
||||
|
||||
void set_iq_balance_mode( int mode, size_t chan = 0 );
|
||||
void set_iq_balance( const std::complex<double> &correction, size_t chan = 0 );
|
||||
|
||||
private:
|
||||
osmosdr_source_c_impl (const std::string & args); // private constructor
|
||||
|
||||
|
@ -72,6 +80,11 @@ private:
|
|||
std::map< size_t, double > _if_gain;
|
||||
std::map< size_t, std::string > _antenna;
|
||||
std::vector< osmosdr_src_iface * > _devs;
|
||||
#ifdef HAVE_IQBALANCE
|
||||
std::vector< iqbalance_fix_cc * > _iq_fix;
|
||||
std::vector< iqbalance_optimize_c * > _iq_opt;
|
||||
std::map< size_t, std::pair<float, float> > _vals;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_OSMOSDR_SOURCE_C_IMPL_H */
|
||||
|
|
Loading…
Reference in New Issue