diff options
author | Ian Buckley <github@ionconcepts.com> | 2015-01-02 10:33:14 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-01-19 09:22:25 +0100 |
commit | 6b50a6bcd93bde8bced6adb9b09c6fe247bcde92 (patch) | |
tree | 681ace48f759d3811d644ff38a8bb6a47555fc90 | |
parent | e76ceef05331fcf8bb6d1855f5c06b483851d07b (diff) | |
download | uhd-6b50a6bcd93bde8bced6adb9b09c6fe247bcde92.tar.gz uhd-6b50a6bcd93bde8bced6adb9b09c6fe247bcde92.tar.bz2 uhd-6b50a6bcd93bde8bced6adb9b09c6fe247bcde92.zip |
B200: Bug #656. Added FIR coeffs for filters with Fs/4 stop band.
AD9361 driver can now select coeffs for different interpolation ratios.
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 7 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 39 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 5 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_filter_taps.h | 35 |
4 files changed, 69 insertions, 17 deletions
diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index f94536ed9..85510530d 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -123,6 +123,13 @@ public: const meta_range_t clock_rate_range = ad9361_ctrl::get_clock_rate_range(); const double clipped_rate = clock_rate_range.clip(rate); + if (clipped_rate != rate) { + UHD_MSG(warning) << boost::format( + "The requested master_clock_rate %f MHz exceeds bounds imposed by UHD.\n" + "The master_clock_rate has been forced to %f MHz.\n" + ) % (rate/1e6) % (clipped_rate/1e6) << std::endl; + } + return _device.set_clock_rate(clipped_rate); } diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index b5e116a70..3abcdc157 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -143,22 +143,22 @@ void ad9361_device_t::_program_fir_filter(direction_t direction, int num_taps, b /* Program the RX FIR Filter. */ -void ad9361_device_t::_setup_rx_fir(size_t num_taps) +void ad9361_device_t::_setup_rx_fir(size_t num_taps, boost::int32_t interpolation) { boost::scoped_array<boost::uint16_t> coeffs(new boost::uint16_t[num_taps]); for (size_t i = 0; i < num_taps; i++) { switch (num_taps) { case 128: - coeffs[i] = boost::uint16_t(hb127_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_128_x4_coeffs[i] : hb127_coeffs[i]); break; case 96: - coeffs[i] = boost::uint16_t(hb95_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_96_x4_coeffs[i] : hb95_coeffs[i]); break; case 64: - coeffs[i] = boost::uint16_t(hb63_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_64_x4_coeffs[i] : hb63_coeffs[i]); break; case 48: - coeffs[i] = boost::uint16_t(hb47_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_48_x4_coeffs[i] : hb47_coeffs[i]); break; default: throw uhd::runtime_error("[ad9361_device_t] Unsupported number of Rx FIR taps."); @@ -169,22 +169,22 @@ void ad9361_device_t::_setup_rx_fir(size_t num_taps) } /* Program the TX FIR Filter. */ -void ad9361_device_t::_setup_tx_fir(size_t num_taps) +void ad9361_device_t::_setup_tx_fir(size_t num_taps, boost::int32_t interpolation) { boost::scoped_array<boost::uint16_t> coeffs(new boost::uint16_t[num_taps]); for (size_t i = 0; i < num_taps; i++) { switch (num_taps) { case 128: - coeffs[i] = boost::uint16_t(hb127_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_128_x4_coeffs[i] : hb127_coeffs[i]); break; case 96: - coeffs[i] = boost::uint16_t(hb95_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_96_x4_coeffs[i] : hb95_coeffs[i]); break; case 64: - coeffs[i] = boost::uint16_t(hb63_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_64_x4_coeffs[i] : hb63_coeffs[i]); break; case 48: - coeffs[i] = boost::uint16_t(hb47_coeffs[i]); + coeffs[i] = boost::uint16_t((interpolation==4) ? fir_48_x4_coeffs[i] : hb47_coeffs[i]); break; default: throw uhd::runtime_error("[ad9361_device_t] Unsupported number of Tx FIR taps."); @@ -1231,6 +1231,7 @@ double ad9361_device_t::_setup_rates(const double rate) /* If we make it into this function, then we are tuning to a new rate. * Store the new rate. */ _req_clock_rate = rate; + UHD_LOG << boost::format("[ad9361_device_t::_setup_rates] rate=%d\n") % rate; /* Set the decimation and interpolation values in the RX and TX chains. * This also switches filters in / out. Note that all transmitters and @@ -1239,6 +1240,7 @@ double ad9361_device_t::_setup_rates(const double rate) * user-requested antenna selections. */ int divfactor = 0; _tfir_factor = 0; + _rfir_factor = 0; if (rate < 0.33e6) { // RX1 + RX2 enabled, 3, 2, 2, 4 _regs.rxfilt = B8(11101111); @@ -1247,7 +1249,8 @@ double ad9361_device_t::_setup_rates(const double rate) _regs.txfilt = B8(11101111); divfactor = 48; - _tfir_factor = 2; + _tfir_factor = 4; + _rfir_factor = 4; } else if (rate < 0.66e6) { // RX1 + RX2 enabled, 2, 2, 2, 4 _regs.rxfilt = B8(11011111); @@ -1256,7 +1259,8 @@ double ad9361_device_t::_setup_rates(const double rate) _regs.txfilt = B8(11011111); divfactor = 32; - _tfir_factor = 2; + _tfir_factor = 4; + _rfir_factor = 4; } else if (rate <= 20e6) { // RX1 + RX2 enabled, 2, 2, 2, 2 _regs.rxfilt = B8(11011110); @@ -1266,6 +1270,7 @@ double ad9361_device_t::_setup_rates(const double rate) divfactor = 16; _tfir_factor = 2; + _rfir_factor = 2; } else if ((rate > 20e6) && (rate < 23e6)) { // RX1 + RX2 enabled, 3, 2, 2, 2 _regs.rxfilt = B8(11101110); @@ -1275,6 +1280,7 @@ double ad9361_device_t::_setup_rates(const double rate) divfactor = 24; _tfir_factor = 2; + _rfir_factor = 2; } else if ((rate >= 23e6) && (rate < 41e6)) { // RX1 + RX2 enabled, 2, 2, 2, 2 _regs.rxfilt = B8(11011110); @@ -1284,6 +1290,7 @@ double ad9361_device_t::_setup_rates(const double rate) divfactor = 16; _tfir_factor = 2; + _rfir_factor = 2; } else if ((rate >= 41e6) && (rate <= 56e6)) { // RX1 + RX2 enabled, 3, 1, 2, 2 _regs.rxfilt = B8(11100110); @@ -1293,6 +1300,7 @@ double ad9361_device_t::_setup_rates(const double rate) divfactor = 12; _tfir_factor = 2; + _rfir_factor = 2; } else if ((rate > 56e6) && (rate <= 61.44e6)) { // RX1 + RX2 enabled, 3, 1, 1, 2 _regs.rxfilt = B8(11100010); @@ -1302,6 +1310,7 @@ double ad9361_device_t::_setup_rates(const double rate) divfactor = 6; _tfir_factor = 1; + _rfir_factor = 2; } else { // should never get in here throw uhd::runtime_error("[ad9361_device_t] [_setup_rates] INVALID_CODE_PATH"); @@ -1349,8 +1358,8 @@ double ad9361_device_t::_setup_rates(const double rate) const size_t num_tx_taps = get_num_taps(max_tx_taps); const size_t num_rx_taps = get_num_taps(max_rx_taps); - _setup_tx_fir(num_tx_taps); - _setup_rx_fir(num_rx_taps); + _setup_tx_fir(num_tx_taps,_tfir_factor); + _setup_rx_fir(num_rx_taps,_rfir_factor); return _baseband_bw; } @@ -1604,7 +1613,7 @@ double ad9361_device_t::set_clock_rate(const double req_rate) * starts up. This prevents that, and any bugs in user code that request * the same rate over and over. */ if (freq_is_nearly_equal(req_rate, _req_clock_rate)) { - return _baseband_bw; + return _baseband_bw; // IJB. Should this not return req_rate? } /* We must be in the SLEEP / WAIT state to do this. If we aren't already diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 8c163572c..bd93bd06b 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -73,8 +73,8 @@ public: private: //Methods void _program_fir_filter(direction_t direction, int num_taps, boost::uint16_t *coeffs); - void _setup_tx_fir(size_t num_taps); - void _setup_rx_fir(size_t num_taps); + void _setup_tx_fir(size_t num_taps, boost::int32_t interpolation); + void _setup_rx_fir(size_t num_taps, boost::int32_t interpolation); void _calibrate_lock_bbpll(); void _calibrate_synth_charge_pumps(); double _calibrate_baseband_rx_analog_filter(); @@ -118,6 +118,7 @@ private: //Members boost::uint8_t _curr_gain_table; boost::uint32_t _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain; boost::int32_t _tfir_factor; + boost::int32_t _rfir_factor; //Register soft-copies chip_regs_t _regs; //Synchronization diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_filter_taps.h b/host/lib/usrp/common/ad9361_driver/ad9361_filter_taps.h index 4059ad7ee..a1a85a49a 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_filter_taps.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_filter_taps.h @@ -45,6 +45,9 @@ static uint16_t lte10mhz_tx_coeffs[] = { }; */ +/************************************************************/ +/* These filters suitable for decimation/interpolation by 2 */ +/************************************************************/ /* 127 tap Halfband designed with: round(2^16 * halfgen4(0.9/4,32)) (center tap tweaked to 32767) */ static boost::int16_t hb127_coeffs[] = { @@ -69,5 +72,37 @@ static boost::int16_t hb47_coeffs[] = { -50,0,98,-0,-181,0,307,-0,-489,0,747,-0,-1109,0,1628,-0,-2413,0,3750,-0,-6693,0,20773,32767,20773,0,-6693,-0,3750,0,-2413,-0, 1628,0,-1109,-0,747,0,-489,-0,307,0,-181,-0,98,0,-50,0}; +/************************************************************/ +/* These filters suitable for decimation/interpolation by 4 */ +/* Designed for -3dB rolloff @ Fs/4 */ +/************************************************************/ + +/* 128 tap equiripple FIR low-pass designed with: round(2^16 * fir1(127,0.25)); */ +static boost::int16_t fir_128_x4_coeffs[] = { + -15,-27,-23,-6,17,33,31,9,-23,-47,-45,-13,34,69,67,21,-49,-102,-99,-32,69,146,143,48,-96,-204,-200,-69,129,278,275,97,-170, + -372,-371,-135,222,494,497,187,-288,-654,-665,-258,376,875,902,363,-500,-1201,-1265,-530,699,1748,1906,845,-1089,-2922,-3424, + -1697,2326,7714,12821,15921,15921,12821,7714,2326,-1697,-3424,-2922,-1089,845,1906,1748,699,-530,-1265,-1201,-500,363,902,875, + 376,-258,-665,-654,-288,187,497,494,222,-135,-371,-372,-170,97,275,278,129,-69,-200,-204,-96,48,143,146,69,-32,-99,-102,-49,21, + 67,69,34,-13,-45,-47,-23,9,31,33,17,-6,-23,-27,-15}; + +/* 96 tap equiripple FIR low-pass designed with: round(2^16 * fir1(95,0.25)); */ +static boost::int16_t fir_96_x4_coeffs[] = { + -18,-35,-33,-11,23,50,51,18,-37,-83,-86,-31,62,140,145,54,-98,-224,-232,-88,149,343,356,138,-218,-509,-530,-211,313,743,781, + 320,-447,-1089,-1163,-494,658,1663,1830,819,-1062,-2868,-3379,-1682,2314,7695,12812,15924,15924,12812,7695,2314,-1682,-3379, + -2868,-1062,819,1830,1663,658,-494,-1163,-1089,-447,320,781,743,313,-211,-530,-509,-218,138,356,343,149,-88,-232,-224,-98,54, + 145,140,62,-31,-86,-83,-37,18,51,50,23,-11,-33,-35,-18}; + +/* 64 tap equiripple FIR low-pass designed with: round(2^16 * fir1(63,0.25)); */ +static boost::int16_t fir_64_x4_coeffs[] = { + -25,-54,-56,-22,41,102,117,50,-87,-223,-253,-109,174,443,496,215,-317,-809,-903,-398,550,1434,1623,744,-987,-2715,-3251, + -1640,2279,7638,12782,15928,15928,12782,7638,2279,-1640,-3251,-2715,-987,744,1623,1434,550,-398,-903,-809,-317,215,496, + 443,174,-109,-253,-223,-87,50,117,102,41,-22,-56,-54,-25}; + + /* 48 tap equiripple FIR low-pass designed with: round(2^16 * fir1(47,0.25)); */ +static boost::int16_t fir_48_x4_coeffs[] = { + -32,-74,-84,-39,68,191,237,114,-183,-508,-609,-287,419,1149,1358,647,-887,-2508,-3073,-1580,2230,7555,12736,15928,15928, + 12736,7555,2230,-1580,-3073,-2508,-887,647,1358,1149,419,-287,-609,-508,-183,114,237,191,68,-39,-84,-74,-32}; + +/* NOTE: To write coeffs directly from Octave in a format that's useful in C use: dlmwrite ("file.csv",bb,","); */ #endif // INCLUDED_AD9361_FILTER_TAPS_HPP |