aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitri Stolnikov <horiz0n@gmx.net>2013-03-03 18:06:48 +0100
committerDimitri Stolnikov <horiz0n@gmx.net>2013-03-11 21:06:13 +0100
commite415d843c7588d3cd018fe43f139c5429a6a6c18 (patch)
treefeecc7b7d61821902922ef404521ec22a4d4c1e2
parentede9c80455d64d0286c68ce9faaaa7da69aeefd1 (diff)
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-iqbal
-rw-r--r--CMakeLists.txt1
-rw-r--r--cmake/Modules/FindGnuradioIQBalance.cmake29
-rw-r--r--grc/gen_osmosdr_blocks.py31
-rw-r--r--include/osmosdr/osmosdr_source_c.h24
-rw-r--r--lib/CMakeLists.txt7
-rw-r--r--lib/osmosdr_source_c_impl.cc131
-rw-r--r--lib/osmosdr_source_c_impl.h13
7 files changed, 213 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2571f8e..60e0bf4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/cmake/Modules/FindGnuradioIQBalance.cmake b/cmake/Modules/FindGnuradioIQBalance.cmake
new file mode 100644
index 0000000..642ee3f
--- /dev/null
+++ b/cmake/Modules/FindGnuradioIQBalance.cmake
@@ -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)
diff --git a/grc/gen_osmosdr_blocks.py b/grc/gen_osmosdr_blocks.py
index c060d20..e317482 100644
--- a/grc/gen_osmosdr_blocks.py
+++ b/grc/gen_osmosdr_blocks.py
@@ -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.
@@ -188,6 +198,25 @@ PARAMS_TMPL = """
<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>
<value>0</value>
@@ -198,7 +227,7 @@ PARAMS_TMPL = """
<key>0</key>
</option>
<option>
- <name>Auto</name>
+ <name>Automatic</name>
<key>1</key>
</option>
</param>
diff --git a/include/osmosdr/osmosdr_source_c.h b/include/osmosdr/osmosdr_source_c.h
index 55a9a0f..a2b598c 100644
--- a/include/osmosdr/osmosdr_source_c.h
+++ b/include/osmosdr/osmosdr_source_c.h
@@ -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 */
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 494d498..4f9d7d3 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -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
########################################################################
diff --git a/lib/osmosdr_source_c_impl.cc b/lib/osmosdr_source_c_impl.cc
index ba17a83..708831c 100644
--- a/lib/osmosdr_source_c_impl.cc
+++ b/lib/osmosdr_source_c_impl.cc
@@ -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 );
+ block = src; iface = src.get();
+ }
+#endif
- for (size_t i = 0; i < src->get_num_channels(); i++)
- connect(src, i, self(), channel++);
+ if ( iface != NULL && long(block.get()) != 0 ) {
+ _devs.push_back( iface );
- _devs.push_back( src.get() );
- }
+ 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
+}
diff --git a/lib/osmosdr_source_c_impl.h b/lib/osmosdr_source_c_impl.h
index a34bf3b..47d6695 100644
--- a/lib/osmosdr_source_c_impl.h
+++ b/lib/osmosdr_source_c_impl.h
@@ -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 */