diff options
-rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_3000.cpp | 311 | ||||
-rw-r--r-- | host/lib/usrp/cores/tx_dsp_core_3000.cpp | 187 |
2 files changed, 268 insertions, 230 deletions
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp index 325ff5569..191232541 100644 --- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp +++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp @@ -5,101 +5,103 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/types/dict.hpp> #include <uhd/exception.hpp> -#include <uhd/utils/math.hpp> +#include <uhd/types/dict.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/math.hpp> #include <uhd/utils/safe_call.hpp> -#include <uhdlib/usrp/cores/rx_dsp_core_3000.hpp> #include <uhdlib/usrp/cores/dsp_core_utils.hpp> +#include <uhdlib/usrp/cores/rx_dsp_core_3000.hpp> #include <boost/assign/list_of.hpp> -#include <boost/thread/thread.hpp> //thread sleep #include <boost/math/special_functions/round.hpp> +#include <boost/thread/thread.hpp> //thread sleep #include <algorithm> #include <cmath> -#define REG_DSP_RX_FREQ _dsp_base + 0 -#define REG_DSP_RX_SCALE_IQ _dsp_base + 4 -#define REG_DSP_RX_DECIM _dsp_base + 8 -#define REG_DSP_RX_MUX _dsp_base + 12 -#define REG_DSP_RX_COEFFS _dsp_base + 16 -//FIXME: Add code to support REG_DSP_RX_COEFFS +#define REG_DSP_RX_FREQ _dsp_base + 0 +#define REG_DSP_RX_SCALE_IQ _dsp_base + 4 +#define REG_DSP_RX_DECIM _dsp_base + 8 +#define REG_DSP_RX_MUX _dsp_base + 12 +#define REG_DSP_RX_COEFFS _dsp_base + 16 +// FIXME: Add code to support REG_DSP_RX_COEFFS -#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) +#define FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) #define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) -#define FLAG_DSP_RX_MUX_INVERT_Q (1 << 2) -#define FLAG_DSP_RX_MUX_INVERT_I (1 << 3) +#define FLAG_DSP_RX_MUX_INVERT_Q (1 << 2) +#define FLAG_DSP_RX_MUX_INVERT_I (1 << 3) -template <class T> T ceil_log2(T num){ - return std::ceil(std::log(num)/std::log(T(2))); +template <class T> +T ceil_log2(T num) +{ + return std::ceil(std::log(num) / std::log(T(2))); } using namespace uhd; const double rx_dsp_core_3000::DEFAULT_CORDIC_FREQ = 0.0; -const double rx_dsp_core_3000::DEFAULT_RATE = 1e6; +const double rx_dsp_core_3000::DEFAULT_RATE = 1e6; -rx_dsp_core_3000::~rx_dsp_core_3000(void){ +rx_dsp_core_3000::~rx_dsp_core_3000(void) +{ /* NOP */ } -class rx_dsp_core_3000_impl : public rx_dsp_core_3000{ +class rx_dsp_core_3000_impl : public rx_dsp_core_3000 +{ public: - rx_dsp_core_3000_impl( - wb_iface::sptr iface, - const size_t dsp_base, - const bool is_b200 - ): - _iface(iface), _dsp_base(dsp_base), _is_b200(is_b200) + rx_dsp_core_3000_impl(wb_iface::sptr iface, const size_t dsp_base, const bool is_b200) + : _iface(iface), _dsp_base(dsp_base), _is_b200(is_b200) { // previously uninitialized - assuming zero for all _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0; - //init to something so update method has reasonable defaults + // init to something so update method has reasonable defaults _scaling_adjustment = 1.0; - _dsp_extra_scaling = 1.0; - _tick_rate = 1.0; - _dsp_freq_offset = 0.0; + _dsp_extra_scaling = 1.0; + _tick_rate = 1.0; + _dsp_freq_offset = 0.0; } ~rx_dsp_core_3000_impl(void) { - UHD_SAFE_CALL - ( - ;//NOP + UHD_SAFE_CALL(; // NOP ) } - void set_mux(const uhd::usrp::fe_connection_t& fe_conn){ + void set_mux(const uhd::usrp::fe_connection_t& fe_conn) + { uint32_t reg_val = 0; switch (fe_conn.get_sampling_mode()) { - case uhd::usrp::fe_connection_t::REAL: - case uhd::usrp::fe_connection_t::HETERODYNE: - reg_val = FLAG_DSP_RX_MUX_REAL_MODE; - break; - default: - reg_val = 0; - break; + case uhd::usrp::fe_connection_t::REAL: + case uhd::usrp::fe_connection_t::HETERODYNE: + reg_val = FLAG_DSP_RX_MUX_REAL_MODE; + break; + default: + reg_val = 0; + break; } - if (fe_conn.is_iq_swapped()) reg_val |= FLAG_DSP_RX_MUX_SWAP_IQ; - if (fe_conn.is_i_inverted()) reg_val |= FLAG_DSP_RX_MUX_INVERT_I; - if (fe_conn.is_q_inverted()) reg_val |= FLAG_DSP_RX_MUX_INVERT_Q; + if (fe_conn.is_iq_swapped()) + reg_val |= FLAG_DSP_RX_MUX_SWAP_IQ; + if (fe_conn.is_i_inverted()) + reg_val |= FLAG_DSP_RX_MUX_INVERT_I; + if (fe_conn.is_q_inverted()) + reg_val |= FLAG_DSP_RX_MUX_INVERT_Q; _iface->poke32(REG_DSP_RX_MUX, reg_val); if (fe_conn.get_sampling_mode() == uhd::usrp::fe_connection_t::HETERODYNE) { - //1. Remember the sign of the IF frequency. + // 1. Remember the sign of the IF frequency. // It will be discarded in the next step int if_freq_sign = boost::math::sign(fe_conn.get_if_freq()); - //2. Map IF frequency to the range [0, _tick_rate) + // 2. Map IF frequency to the range [0, _tick_rate) double if_freq = std::abs(std::fmod(fe_conn.get_if_freq(), _tick_rate)); - //3. Map IF frequency to the range [-_tick_rate/2, _tick_rate/2) + // 3. Map IF frequency to the range [-_tick_rate/2, _tick_rate/2) // This is the aliased frequency if (if_freq > (_tick_rate / 2.0)) { if_freq -= _tick_rate; } - //4. Set DSP offset to spin the signal in the opposite + // 4. Set DSP offset to spin the signal in the opposite // direction as the aliased frequency _dsp_freq_offset = if_freq * (-if_freq_sign); } else { @@ -107,166 +109,193 @@ public: } } - void set_tick_rate(const double rate){ + void set_tick_rate(const double rate) + { _tick_rate = rate; set_freq(_current_freq); } - void set_link_rate(const double rate){ + void set_link_rate(const double rate) + { //_link_rate = rate/sizeof(uint32_t); //in samps/s - _link_rate = rate/sizeof(uint16_t); //in samps/s (allows for 8sc) + _link_rate = rate / sizeof(uint16_t); // in samps/s (allows for 8sc) } - uhd::meta_range_t get_host_rates(void){ + uhd::meta_range_t get_host_rates(void) + { meta_range_t range; if (!_is_b200) { - for (int rate = 1024; rate > 512; rate -= 8){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 1024; rate > 512; rate -= 8) { + range.push_back(range_t(_tick_rate / rate)); } } - for (int rate = 512; rate > 256; rate -= 4){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 512; rate > 256; rate -= 4) { + range.push_back(range_t(_tick_rate / rate)); } - for (int rate = 256; rate > 128; rate -= 2){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 256; rate > 128; rate -= 2) { + range.push_back(range_t(_tick_rate / rate)); } - for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 128; rate >= int(std::ceil(_tick_rate / _link_rate)); rate -= 1) { + range.push_back(range_t(_tick_rate / rate)); } return range; } - double set_host_rate(const double rate){ - const size_t decim_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true)); + double set_host_rate(const double rate) + { + const size_t decim_rate = + boost::math::iround(_tick_rate / this->get_host_rates().clip(rate, true)); size_t decim = decim_rate; - //determine which half-band filters are activated - int hb0 = 0, hb1 = 0, hb2 = 0, hb_enable=0; - if (decim % 2 == 0){ + // determine which half-band filters are activated + int hb0 = 0, hb1 = 0, hb2 = 0, hb_enable = 0; + if (decim % 2 == 0) { hb0 = 1; decim /= 2; } - if (decim % 2 == 0){ + if (decim % 2 == 0) { hb1 = 1; decim /= 2; } - //the third half-band is not supported by the B200 - if (decim % 2 == 0 && !_is_b200){ + // the third half-band is not supported by the B200 + if (decim % 2 == 0 && !_is_b200) { hb2 = 1; decim /= 2; } if (_is_b200) { - _iface->poke32(REG_DSP_RX_DECIM, (hb0 << 9) /*small HB */ | (hb1 << 8) /*large HB*/ | (decim & 0xff)); + _iface->poke32(REG_DSP_RX_DECIM, + (hb0 << 9) /*small HB */ | (hb1 << 8) /*large HB*/ | (decim & 0xff)); if (decim > 1 and hb0 == 0 and hb1 == 0) { - UHD_LOGGER_WARNING("CORES") << boost::format( - "The requested decimation is odd; the user should expect CIC rolloff.\n" - "Select an even decimation to ensure that a halfband filter is enabled.\n" - "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n" - ) % decim_rate % (_tick_rate/1e6) % (rate/1e6); + UHD_LOGGER_WARNING("CORES") + << boost::format( + "The requested decimation is odd; the user should expect CIC " + "rolloff.\n" + "Select an even decimation to ensure that a halfband filter " + "is enabled.\n" + "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n") + % decim_rate % (_tick_rate / 1e6) % (rate / 1e6); } } else { // Encode Halfband config for setting register programming. if (hb2) { // Implies HB1 and HB0 also asserted - hb_enable=3; + hb_enable = 3; } else if (hb1) { // Implies HB0 is also asserted - hb_enable=2; + hb_enable = 2; } else if (hb0) { - hb_enable=1; + hb_enable = 1; } else { - hb_enable=0; + hb_enable = 0; } - _iface->poke32(REG_DSP_RX_DECIM, (hb_enable << 8) | (decim & 0xff)); + _iface->poke32(REG_DSP_RX_DECIM, (hb_enable << 8) | (decim & 0xff)); if (decim > 1 and hb0 == 0 and hb1 == 0 and hb2 == 0) { - UHD_LOGGER_WARNING("CORES") << boost::format( - "The requested decimation is odd; the user should expect passband CIC rolloff.\n" - "Select an even decimation to ensure that a halfband filter is enabled.\n" - "Decimations factorable by 4 will enable 2 halfbands, those factorable by 8 will enable 3 halfbands.\n" - "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n" - ) % decim_rate % (_tick_rate/1e6) % (rate/1e6); + UHD_LOGGER_WARNING("CORES") + << boost::format( + "The requested decimation is odd; the user should expect " + "passband CIC rolloff.\n" + "Select an even decimation to ensure that a halfband filter " + "is enabled.\n" + "Decimations factorable by 4 will enable 2 halfbands, those " + "factorable by 8 will enable 3 halfbands.\n" + "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n") + % decim_rate % (_tick_rate / 1e6) % (rate / 1e6); } } // Caclulate algorithmic gain of CIC for a given decimation. // For Ettus CIC R=decim, M=1, N=4. Gain = (R * M) ^ N const double rate_pow = std::pow(double(decim & 0xff), 4); - // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking into account - // gain compensation blocks already hardcoded in place in DDC (that provide simple 1/2^n gain compensation). - // CORDIC algorithmic gain limits asymptotically around 1.647 after many iterations. + // Calculate compensation gain values for algorithmic gain of CORDIC and CIC + // taking into account gain compensation blocks already hardcoded in place in DDC + // (that provide simple 1/2^n gain compensation). CORDIC algorithmic gain limits + // asymptotically around 1.647 after many iterations. // - // The polar rotation of [I,Q] = [1,1] by Pi/8 also yields max magnitude of SQRT(2) (~1.4142) however - // input to the CORDIC thats outside the unit circle can only be sourced from a saturated RF frontend. - // To provide additional dynamic range head room accordingly using scale factor applied at egress from DDC would - // cost us small signal performance, thus we do no provide compensation gain for a saturated front end and allow - // the signal to clip in the H/W as needed. If we wished to avoid the signal clipping in these circumstances then adjust code to read: - // _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.648*rate_pow*1.415); - _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.648*rate_pow); + // The polar rotation of [I,Q] = [1,1] by Pi/8 also yields max magnitude of + // SQRT(2) (~1.4142) however input to the CORDIC thats outside the unit circle can + // only be sourced from a saturated RF frontend. To provide additional dynamic + // range head room accordingly using scale factor applied at egress from DDC would + // cost us small signal performance, thus we do no provide compensation gain for a + // saturated front end and allow the signal to clip in the H/W as needed. If we + // wished to avoid the signal clipping in these circumstances then adjust code to + // read: _scaling_adjustment = std::pow(2, + // ceil_log2(rate_pow))/(1.648*rate_pow*1.415); + _scaling_adjustment = std::pow(2, ceil_log2(rate_pow)) / (1.648 * rate_pow); this->update_scalar(); - return _tick_rate/decim_rate; + return _tick_rate / decim_rate; } - // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking into account - // gain compensation blocks already hardcoded in place in DDC (that provide simple 1/2^n gain compensation). - // Further more factor in OTW format which adds further gain factor to weight output samples correctly. - void update_scalar(void){ - const double target_scalar = (1 << (_is_b200 ? 16 : 15))*_scaling_adjustment/_dsp_extra_scaling; + // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking + // into account gain compensation blocks already hardcoded in place in DDC (that + // provide simple 1/2^n gain compensation). Further more factor in OTW format which + // adds further gain factor to weight output samples correctly. + void update_scalar(void) + { + const double target_scalar = + (1 << (_is_b200 ? 16 : 15)) * _scaling_adjustment / _dsp_extra_scaling; const int32_t actual_scalar = boost::math::iround(target_scalar); - // Calculate the error introduced by using integer representation for the scalar, can be corrected in host later. - _fxpt_scalar_correction = target_scalar/actual_scalar; - // Write DDC with scaling correction for CIC and CORDIC that maximizes dynamic range in 32/16/12/8bits. + // Calculate the error introduced by using integer representation for the scalar, + // can be corrected in host later. + _fxpt_scalar_correction = target_scalar / actual_scalar; + // Write DDC with scaling correction for CIC and CORDIC that maximizes dynamic + // range in 32/16/12/8bits. _iface->poke32(REG_DSP_RX_SCALE_IQ, actual_scalar); } - double get_scaling_adjustment(void){ - return _fxpt_scalar_correction*_host_extra_scaling/32767.; + double get_scaling_adjustment(void) + { + return _fxpt_scalar_correction * _host_extra_scaling / 32767.; } - double set_freq(const double requested_freq){ + double set_freq(const double requested_freq) + { double actual_freq; int32_t freq_word; - get_freq_and_freq_word(requested_freq + _dsp_freq_offset, _tick_rate, actual_freq, freq_word); + get_freq_and_freq_word( + requested_freq + _dsp_freq_offset, _tick_rate, actual_freq, freq_word); _iface->poke32(REG_DSP_RX_FREQ, uint32_t(freq_word)); _current_freq = actual_freq; return actual_freq; } - double get_freq(void){ + double get_freq(void) + { return _current_freq; } - uhd::meta_range_t get_freq_range(void){ - //Too keep the DSP range symmetric about 0, we use abs(_dsp_freq_offset) + uhd::meta_range_t get_freq_range(void) + { + // Too keep the DSP range symmetric about 0, we use abs(_dsp_freq_offset) const double offset = std::abs<double>(_dsp_freq_offset); - return uhd::meta_range_t(-(_tick_rate-offset)/2, +(_tick_rate-offset)/2, _tick_rate/std::pow(2.0, 32)); + return uhd::meta_range_t(-(_tick_rate - offset) / 2, + +(_tick_rate - offset) / 2, + _tick_rate / std::pow(2.0, 32)); } - void setup(const uhd::stream_args_t &stream_args){ - - if (stream_args.otw_format == "sc16"){ - _dsp_extra_scaling = 1.0; + void setup(const uhd::stream_args_t& stream_args) + { + if (stream_args.otw_format == "sc16") { + _dsp_extra_scaling = 1.0; _host_extra_scaling = 1.0; - } - else if (stream_args.otw_format == "sc8"){ - double peak = stream_args.args.cast<double>("peak", 1.0); - peak = std::max(peak, 1.0/256); - _host_extra_scaling = peak*256; - _dsp_extra_scaling = peak; - } - else if (stream_args.otw_format == "sc12"){ - double peak = stream_args.args.cast<double>("peak", 1.0); - peak = std::max(peak, 1.0/16); - _host_extra_scaling = peak*16; - _dsp_extra_scaling = peak; - } - else if (stream_args.otw_format == "fc32"){ + } else if (stream_args.otw_format == "sc8") { + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0 / 256); + _host_extra_scaling = peak * 256; + _dsp_extra_scaling = peak; + } else if (stream_args.otw_format == "sc12") { + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0 / 16); + _host_extra_scaling = peak * 16; + _dsp_extra_scaling = peak; + } else if (stream_args.otw_format == "fc32") { _host_extra_scaling = 1.0; - _dsp_extra_scaling = 1.0; - } - else throw uhd::value_error("USRP RX cannot handle requested wire format: " + stream_args.otw_format); + _dsp_extra_scaling = 1.0; + } else + throw uhd::value_error( + "USRP RX cannot handle requested wire format: " + stream_args.otw_format); _host_extra_scaling *= stream_args.args.cast<double>("fullscale", 1.0); @@ -276,33 +305,31 @@ public: void populate_subtree(property_tree::sptr subtree) { subtree->create<meta_range_t>("rate/range") - .set_publisher(boost::bind(&rx_dsp_core_3000::get_host_rates, this)) - ; + .set_publisher(boost::bind(&rx_dsp_core_3000::get_host_rates, this)); subtree->create<double>("rate/value") .set(DEFAULT_RATE) - .set_coercer(boost::bind(&rx_dsp_core_3000::set_host_rate, this, _1)) - ; + .set_coercer(boost::bind(&rx_dsp_core_3000::set_host_rate, this, _1)); subtree->create<double>("freq/value") .set(DEFAULT_CORDIC_FREQ) .set_coercer(boost::bind(&rx_dsp_core_3000::set_freq, this, _1)) - .set_publisher([this](){ return this->get_freq(); }) - ; + .set_publisher([this]() { return this->get_freq(); }); subtree->create<meta_range_t>("freq/range") - .set_publisher(boost::bind(&rx_dsp_core_3000::get_freq_range, this)) - ; + .set_publisher(boost::bind(&rx_dsp_core_3000::get_freq_range, this)); } private: wb_iface::sptr _iface; const size_t _dsp_base; - const bool _is_b200; //TODO: Obsolete this when we switch to the new DDC on the B200 + const bool _is_b200; // TODO: Obsolete this when we switch to the new DDC on the B200 double _tick_rate, _link_rate; - double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction; + double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, + _fxpt_scalar_correction; double _dsp_freq_offset; double _current_freq; }; -rx_dsp_core_3000::sptr rx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base, const bool is_b200 /* = false */) +rx_dsp_core_3000::sptr rx_dsp_core_3000::make( + wb_iface::sptr iface, const size_t dsp_base, const bool is_b200 /* = false */) { return sptr(new rx_dsp_core_3000_impl(iface, dsp_base, is_b200)); } diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.cpp b/host/lib/usrp/cores/tx_dsp_core_3000.cpp index af0587c7f..029ca5c3d 100644 --- a/host/lib/usrp/cores/tx_dsp_core_3000.cpp +++ b/host/lib/usrp/cores/tx_dsp_core_3000.cpp @@ -5,129 +5,142 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhdlib/usrp/cores/tx_dsp_core_3000.hpp> -#include <uhdlib/usrp/cores/dsp_core_utils.hpp> -#include <uhd/types/dict.hpp> #include <uhd/exception.hpp> -#include <uhd/utils/math.hpp> +#include <uhd/types/dict.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/math.hpp> +#include <uhdlib/usrp/cores/dsp_core_utils.hpp> +#include <uhdlib/usrp/cores/tx_dsp_core_3000.hpp> #include <boost/assign/list_of.hpp> #include <boost/math/special_functions/round.hpp> #include <boost/thread/thread.hpp> //sleep #include <algorithm> #include <cmath> -#define REG_DSP_TX_FREQ _dsp_base + 0 -#define REG_DSP_TX_SCALE_IQ _dsp_base + 4 -#define REG_DSP_TX_INTERP _dsp_base + 8 +#define REG_DSP_TX_FREQ _dsp_base + 0 +#define REG_DSP_TX_SCALE_IQ _dsp_base + 4 +#define REG_DSP_TX_INTERP _dsp_base + 8 -template <class T> T ceil_log2(T num){ - return std::ceil(std::log(num)/std::log(T(2))); +template <class T> +T ceil_log2(T num) +{ + return std::ceil(std::log(num) / std::log(T(2))); } using namespace uhd; const double tx_dsp_core_3000::DEFAULT_CORDIC_FREQ = 0.0; -const double tx_dsp_core_3000::DEFAULT_RATE = 1e6; +const double tx_dsp_core_3000::DEFAULT_RATE = 1e6; -tx_dsp_core_3000::~tx_dsp_core_3000(void){ +tx_dsp_core_3000::~tx_dsp_core_3000(void) +{ /* NOP */ } -class tx_dsp_core_3000_impl : public tx_dsp_core_3000{ +class tx_dsp_core_3000_impl : public tx_dsp_core_3000 +{ public: - tx_dsp_core_3000_impl( - wb_iface::sptr iface, - const size_t dsp_base - ): - _iface(iface), _dsp_base(dsp_base) + tx_dsp_core_3000_impl(wb_iface::sptr iface, const size_t dsp_base) + : _iface(iface), _dsp_base(dsp_base) { // previously uninitialized - assuming zero for all _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0; - //init to something so update method has reasonable defaults + // init to something so update method has reasonable defaults _scaling_adjustment = 1.0; - _dsp_extra_scaling = 1.0; + _dsp_extra_scaling = 1.0; this->set_tick_rate(1.0); } - void set_tick_rate(const double rate){ + void set_tick_rate(const double rate) + { _tick_rate = rate; set_freq(_current_freq); } - void set_link_rate(const double rate){ + void set_link_rate(const double rate) + { //_link_rate = rate/sizeof(uint32_t); //in samps/s - _link_rate = rate/sizeof(uint16_t); //in samps/s (allows for 8sc) + _link_rate = rate / sizeof(uint16_t); // in samps/s (allows for 8sc) } - uhd::meta_range_t get_host_rates(void){ + uhd::meta_range_t get_host_rates(void) + { meta_range_t range; - for (int rate = 512; rate > 256; rate -= 4){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 512; rate > 256; rate -= 4) { + range.push_back(range_t(_tick_rate / rate)); } - for (int rate = 256; rate > 128; rate -= 2){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 256; rate > 128; rate -= 2) { + range.push_back(range_t(_tick_rate / rate)); } - for (int rate = 128; rate >= int(std::ceil(_tick_rate/_link_rate)); rate -= 1){ - range.push_back(range_t(_tick_rate/rate)); + for (int rate = 128; rate >= int(std::ceil(_tick_rate / _link_rate)); rate -= 1) { + range.push_back(range_t(_tick_rate / rate)); } return range; } - double set_host_rate(const double rate){ - const size_t interp_rate = boost::math::iround(_tick_rate/this->get_host_rates().clip(rate, true)); + double set_host_rate(const double rate) + { + const size_t interp_rate = + boost::math::iround(_tick_rate / this->get_host_rates().clip(rate, true)); size_t interp = interp_rate; - //determine which half-band filters are activated + // determine which half-band filters are activated int hb0 = 0, hb1 = 0; - if (interp % 2 == 0){ + if (interp % 2 == 0) { hb0 = 1; interp /= 2; } - if (interp % 2 == 0){ + if (interp % 2 == 0) { hb1 = 1; interp /= 2; } _iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff)); - if (interp > 1 and hb0 == 0 and hb1 == 0) - { - UHD_LOGGER_WARNING("CORES") << boost::format( - "The requested interpolation is odd; the user should expect CIC rolloff.\n" - "Select an even interpolation to ensure that a halfband filter is enabled.\n" - "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n" - ) % interp_rate % (_tick_rate/1e6) % (rate/1e6); + if (interp > 1 and hb0 == 0 and hb1 == 0) { + UHD_LOGGER_WARNING("CORES") + << boost::format( + "The requested interpolation is odd; the user should expect CIC " + "rolloff.\n" + "Select an even interpolation to ensure that a halfband filter is " + "enabled.\n" + "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n") + % interp_rate % (_tick_rate / 1e6) % (rate / 1e6); } // Caclulate algorithmic gain of CIC for a given interpolation // For Ettus CIC R=decim, M=1, N=3. Gain = (R * M) ^ N const double rate_pow = std::pow(double(interp & 0xff), 3); - // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking into account - // gain compensation blocks already hardcoded in place in DDC (that provide simple 1/2^n gain compensation). - // CORDIC algorithmic gain limits asymptotically around 1.647 after many iterations. - _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.648*rate_pow); + // Calculate compensation gain values for algorithmic gain of CORDIC and CIC + // taking into account gain compensation blocks already hardcoded in place in DDC + // (that provide simple 1/2^n gain compensation). CORDIC algorithmic gain limits + // asymptotically around 1.647 after many iterations. + _scaling_adjustment = std::pow(2, ceil_log2(rate_pow)) / (1.648 * rate_pow); this->update_scalar(); - return _tick_rate/interp_rate; + return _tick_rate / interp_rate; } - // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking into account - // gain compensation blocks already hardcoded in place in DDC (that provide simple 1/2^n gain compensation). - // Further more factor in OTW format which adds further gain factor to weight output samples correctly. - void update_scalar(void){ - const double target_scalar = (1 << 16)*_scaling_adjustment/_dsp_extra_scaling; + // Calculate compensation gain values for algorithmic gain of CORDIC and CIC taking + // into account gain compensation blocks already hardcoded in place in DDC (that + // provide simple 1/2^n gain compensation). Further more factor in OTW format which + // adds further gain factor to weight output samples correctly. + void update_scalar(void) + { + const double target_scalar = (1 << 16) * _scaling_adjustment / _dsp_extra_scaling; const int32_t actual_scalar = boost::math::iround(target_scalar); - _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small + _fxpt_scalar_correction = target_scalar / actual_scalar; // should be small _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar); } - double get_scaling_adjustment(void){ - return _fxpt_scalar_correction*_host_extra_scaling*32767.; + double get_scaling_adjustment(void) + { + return _fxpt_scalar_correction * _host_extra_scaling * 32767.; } - double set_freq(const double requested_freq) { + double set_freq(const double requested_freq) + { double actual_freq; int32_t freq_word; get_freq_and_freq_word(requested_freq, _tick_rate, actual_freq, freq_word); @@ -136,37 +149,38 @@ public: return actual_freq; } - double get_freq(void){ + double get_freq(void) + { return _current_freq; } - uhd::meta_range_t get_freq_range(void){ - return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32)); + uhd::meta_range_t get_freq_range(void) + { + return uhd::meta_range_t( + -_tick_rate / 2, +_tick_rate / 2, _tick_rate / std::pow(2.0, 32)); } - void setup(const uhd::stream_args_t &stream_args){ - - if (stream_args.otw_format == "sc16"){ - _dsp_extra_scaling = 1.0; + void setup(const uhd::stream_args_t& stream_args) + { + if (stream_args.otw_format == "sc16") { + _dsp_extra_scaling = 1.0; _host_extra_scaling = 1.0; - } - else if (stream_args.otw_format == "sc8"){ - double peak = stream_args.args.cast<double>("peak", 1.0); - peak = std::max(peak, 1.0/256); - _host_extra_scaling = 1.0/peak/256; - _dsp_extra_scaling = 1.0/peak; - } - else if (stream_args.otw_format == "sc12"){ - double peak = stream_args.args.cast<double>("peak", 1.0); - peak = std::max(peak, 1.0/16); - _host_extra_scaling = 1.0/peak/16; - _dsp_extra_scaling = 1.0/peak; - } - else if (stream_args.otw_format == "fc32"){ + } else if (stream_args.otw_format == "sc8") { + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0 / 256); + _host_extra_scaling = 1.0 / peak / 256; + _dsp_extra_scaling = 1.0 / peak; + } else if (stream_args.otw_format == "sc12") { + double peak = stream_args.args.cast<double>("peak", 1.0); + peak = std::max(peak, 1.0 / 16); + _host_extra_scaling = 1.0 / peak / 16; + _dsp_extra_scaling = 1.0 / peak; + } else if (stream_args.otw_format == "fc32") { _host_extra_scaling = 1.0; - _dsp_extra_scaling = 1.0; - } - else throw uhd::value_error("USRP TX cannot handle requested wire format: " + stream_args.otw_format); + _dsp_extra_scaling = 1.0; + } else + throw uhd::value_error( + "USRP TX cannot handle requested wire format: " + stream_args.otw_format); _host_extra_scaling /= stream_args.args.cast<double>("fullscale", 1.0); @@ -176,27 +190,24 @@ public: void populate_subtree(property_tree::sptr subtree) { subtree->create<meta_range_t>("rate/range") - .set_publisher(boost::bind(&tx_dsp_core_3000::get_host_rates, this)) - ; + .set_publisher(boost::bind(&tx_dsp_core_3000::get_host_rates, this)); subtree->create<double>("rate/value") .set(DEFAULT_RATE) - .set_coercer(boost::bind(&tx_dsp_core_3000::set_host_rate, this, _1)) - ; + .set_coercer(boost::bind(&tx_dsp_core_3000::set_host_rate, this, _1)); subtree->create<double>("freq/value") .set(DEFAULT_CORDIC_FREQ) .set_coercer(boost::bind(&tx_dsp_core_3000::set_freq, this, _1)) - .set_publisher([this](){ return this->get_freq(); }) - ; + .set_publisher([this]() { return this->get_freq(); }); subtree->create<meta_range_t>("freq/range") - .set_publisher(boost::bind(&tx_dsp_core_3000::get_freq_range, this)) - ; + .set_publisher(boost::bind(&tx_dsp_core_3000::get_freq_range, this)); } private: wb_iface::sptr _iface; const size_t _dsp_base; double _tick_rate, _link_rate; - double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction; + double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, + _fxpt_scalar_correction; double _current_freq; }; |