diff options
| author | Ian Buckley <github@ionconcepts.com> | 2015-09-03 15:55:05 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2015-09-08 09:24:15 -0700 | 
| commit | cc6c82befcf30f0b8488be918f817b3b9a3e7808 (patch) | |
| tree | d1f7b85fb77cb660806c2b91cc746dfafdb4830e | |
| parent | 43fdc0e84ba577adc799a159c28016bd09a8992d (diff) | |
| download | uhd-cc6c82befcf30f0b8488be918f817b3b9a3e7808.tar.gz uhd-cc6c82befcf30f0b8488be918f817b3b9a3e7808.tar.bz2 uhd-cc6c82befcf30f0b8488be918f817b3b9a3e7808.zip | |
cores: Corrected scaling_adjustment calculation
Compensate for headroom required to rotate a signal in
the CORDIC. Fixes some CORDIC-related clipping issues,
that reduced ENOB to 15 or 14.5 bits.
| -rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_3000.cpp | 27 | ||||
| -rw-r--r-- | host/lib/usrp/cores/tx_dsp_core_3000.cpp | 17 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 2 | 
4 files changed, 42 insertions, 12 deletions
| diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp index 18dabade0..035bc6a3f 100644 --- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp +++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp @@ -173,20 +173,35 @@ public:              }          } -        // Calculate CIC decimation (i.e., without halfband decimators) -        // Calculate closest multiplier constant to reverse gain absent scale multipliers +        // 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); -        _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*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. +        // +        // 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;      } +    // 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 factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0); -        const double target_scalar = (1 << (_is_b200 ? 17 : 15))*_scaling_adjustment/_dsp_extra_scaling/factor; +        const double target_scalar = (1 << (_is_b200 ? 16 : 15))*_scaling_adjustment/_dsp_extra_scaling;          const boost::int32_t actual_scalar = boost::math::iround(target_scalar); -        _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small +        // 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);      } diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.cpp b/host/lib/usrp/cores/tx_dsp_core_3000.cpp index 93b70435f..7e447ae7d 100644 --- a/host/lib/usrp/cores/tx_dsp_core_3000.cpp +++ b/host/lib/usrp/cores/tx_dsp_core_3000.cpp @@ -110,20 +110,25 @@ public:              ) % interp_rate % (_tick_rate/1e6) % (rate/1e6);          } -        // Calculate CIC interpolation (i.e., without halfband interpolators) -        // Calculate closest multiplier constant to reverse gain absent scale multipliers +        // 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); -        _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*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;      } +  // 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 factor = 1.0 + std::max(ceil_log2(_scaling_adjustment), 0.0); -        const double target_scalar = (1 << 17)*_scaling_adjustment/_dsp_extra_scaling/factor; +        const double target_scalar = (1 << 16)*_scaling_adjustment/_dsp_extra_scaling;          const boost::int32_t actual_scalar = boost::math::iround(target_scalar); -        _fxpt_scalar_correction = target_scalar/actual_scalar*factor; //should be small +        _fxpt_scalar_correction = target_scalar/actual_scalar; //should be small          _iface->poke32(REG_DSP_TX_SCALE_IQ, actual_scalar);      } diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index f57556a8b..1e424414e 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -1334,6 +1334,14 @@ void x300_impl::register_loopback_self_test(wb_iface::sptr iface)      UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl;  } +void x300_impl::radio_loopback(wb_iface::sptr iface, const bool on) +{ +  iface->poke32(radio::sr_addr(radio::LOOPBACK), (on ? 0x1 : 0x0)); +  UHD_MSG(status) << ((on)? "Radio Loopback On" : "Radio Loopback Off") << std::endl; +} + + +  /***********************************************************************   * clock and time control logic   **********************************************************************/ diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 78c497ad9..1630047af 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -250,6 +250,8 @@ private:      void register_loopback_self_test(uhd::wb_iface::sptr iface); +    void radio_loopback(uhd::wb_iface::sptr iface, const bool on); +       /*! \brief Initialize the radio component on a given slot.        *        * Call this function once per slot (A and B) and motherboard to initialize all the radio components. | 
