diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/rfnoc/duc_block_control.hpp | 7 | ||||
-rw-r--r-- | host/lib/rfnoc/ddc_block_control.cpp | 3 | ||||
-rw-r--r-- | host/lib/rfnoc/duc_block_control.cpp | 7 | ||||
-rw-r--r-- | host/tests/rfnoc_block_tests/duc_block_test.cpp | 28 |
4 files changed, 32 insertions, 13 deletions
diff --git a/host/include/uhd/rfnoc/duc_block_control.hpp b/host/include/uhd/rfnoc/duc_block_control.hpp index cf9d3a5d7..7e398454d 100644 --- a/host/include/uhd/rfnoc/duc_block_control.hpp +++ b/host/include/uhd/rfnoc/duc_block_control.hpp @@ -78,6 +78,13 @@ public: /*! Return the range of frequencies that \p chan can be set to. * + * The frequency shifter is the last component in the DUC, and thus can + * shift frequencies (digitally) between -get_output_rate()/2 + * and +get_output_rate()/2. + * + * The returned values are in Hz (not normalized frequencies) and are valid + * inputs for set_freq(). + * * \return The range of frequencies that the DUC can shift the input by */ virtual uhd::freq_range_t get_frequency_range(const size_t chan) const = 0; diff --git a/host/lib/rfnoc/ddc_block_control.cpp b/host/lib/rfnoc/ddc_block_control.cpp index 3326d4e46..dbcb1b763 100644 --- a/host/lib/rfnoc/ddc_block_control.cpp +++ b/host/lib/rfnoc/ddc_block_control.cpp @@ -126,8 +126,7 @@ public: uhd::freq_range_t get_frequency_range(const size_t chan) const override { - const double input_rate = - _samp_rate_in.at(chan).is_valid() ? _samp_rate_in.at(chan).get() : 1.0; + const double input_rate = get_input_rate(chan); // TODO add steps return uhd::freq_range_t(-input_rate / 2, input_rate / 2); } diff --git a/host/lib/rfnoc/duc_block_control.cpp b/host/lib/rfnoc/duc_block_control.cpp index 12937ac21..674e9d309 100644 --- a/host/lib/rfnoc/duc_block_control.cpp +++ b/host/lib/rfnoc/duc_block_control.cpp @@ -123,10 +123,9 @@ public: uhd::freq_range_t get_frequency_range(const size_t chan) const override { - const double input_rate = - _samp_rate_in.at(chan).is_valid() ? _samp_rate_in.at(chan).get() : 1.0; + const double output_rate = get_output_rate(chan); // TODO add steps - return uhd::freq_range_t(-input_rate / 2, input_rate / 2); + return uhd::freq_range_t(-output_rate / 2, output_rate / 2); } double get_input_rate(const size_t chan) const override @@ -241,7 +240,7 @@ private: * Add resolvers *********************************************************************/ // Resolver for _interp: this gets executed when the user directly - // modifies interp. the desired behaviour is to coerce it first, then + // modifies 'interp'. The desired behaviour is to coerce it first, then // keep the output rate constant, and re-calculate the input rate. add_property_resolver({interp, scaling_in}, {interp, samp_rate_out, samp_rate_in, scaling_in}, diff --git a/host/tests/rfnoc_block_tests/duc_block_test.cpp b/host/tests/rfnoc_block_tests/duc_block_test.cpp index 78e988713..6c92c9d91 100644 --- a/host/tests/rfnoc_block_tests/duc_block_test.cpp +++ b/host/tests/rfnoc_block_tests/duc_block_test.cpp @@ -34,6 +34,7 @@ BOOST_AUTO_TEST_CASE(test_duc_block) constexpr size_t num_chans = 4; constexpr noc_id_t noc_id = DUC_BLOCK; constexpr int TEST_INTERP = 20; // 2 halfbands, CIC==5 + constexpr double DEFAULT_RATE = 200e6; // Matches typical MCR of X310 auto block_container = get_mock_block(noc_id, num_chans, num_chans); auto& duc_reg_iface = block_container.reg_iface; @@ -70,14 +71,21 @@ BOOST_AUTO_TEST_CASE(test_duc_block) mock_source_term.set_edge_property<double>( "scaling", 1.0, {res_source_info::OUTPUT_EDGE, 0}); mock_source_term.set_edge_property<double>( - "samp_rate", 1.0, {res_source_info::OUTPUT_EDGE, 0}); + "samp_rate", DEFAULT_RATE / TEST_INTERP, {res_source_info::OUTPUT_EDGE, 0}); UHD_LOG_INFO("TEST", "Priming mock sink node props"); mock_sink_term.set_edge_property<std::string>( "type", "sc16", {res_source_info::INPUT_EDGE, 0}); mock_sink_term.set_edge_property<double>( "scaling", 1.0, {res_source_info::INPUT_EDGE, 0}); mock_sink_term.set_edge_property<double>( - "samp_rate", 1.0, {res_source_info::INPUT_EDGE, 0}); + "samp_rate", DEFAULT_RATE, {res_source_info::INPUT_EDGE, 0}); + +#define CHECK_OUTPUT_RATE(req_rate) \ + BOOST_REQUIRE_CLOSE(mock_sink_term.get_edge_property<double>( \ + "samp_rate", {res_source_info::INPUT_EDGE, 0}), \ + req_rate, \ + 1e-6); + UHD_LOG_INFO("TEST", "Creating graph..."); graph.connect(&mock_source_term, test_duc.get(), edge_info); @@ -85,6 +93,7 @@ BOOST_AUTO_TEST_CASE(test_duc_block) UHD_LOG_INFO("TEST", "Committing graph..."); graph.commit(); UHD_LOG_INFO("TEST", "Commit complete."); + CHECK_OUTPUT_RATE(DEFAULT_RATE); // We need to set the interpation again, because the rates will screw it // change it w.r.t. to the previous setting test_duc->set_property<int>("interp", TEST_INTERP, 0); @@ -94,6 +103,8 @@ BOOST_AUTO_TEST_CASE(test_duc_block) * TEST_INTERP == mock_sink_term.get_edge_property<double>( "samp_rate", {res_source_info::INPUT_EDGE, 0})); + // Output rate should remain unchanged + CHECK_OUTPUT_RATE(DEFAULT_RATE); const double initial_input_scaling = mock_source_term.get_edge_property<double>( "scaling", {res_source_info::OUTPUT_EDGE, 0}); const double initial_output_scaling = mock_sink_term.get_edge_property<double>( @@ -122,25 +133,28 @@ BOOST_AUTO_TEST_CASE(test_duc_block) "scaling", {res_source_info::OUTPUT_EDGE, 0}); BOOST_CHECK_EQUAL(doubled_input_scaling, 2 * initial_input_scaling); - UHD_LOG_INFO("TEST", "Setting freq to 1/8 of input rate"); - constexpr double TEST_FREQ = 1.0 / 8; + BOOST_CHECK_CLOSE(test_duc->get_frequency_range(0).start(), -DEFAULT_RATE / 2, 1e-6); + BOOST_CHECK_CLOSE(test_duc->get_frequency_range(0).stop(), DEFAULT_RATE / 2, 1e-6); + UHD_LOG_INFO("TEST", + "Setting freq to 1/8 of input rate (to " << (DEFAULT_RATE / 8) / 1e6 << " MHz)"); + constexpr double TEST_FREQ = DEFAULT_RATE / 8; test_duc->set_property<double>("freq", TEST_FREQ, 0); const uint32_t freq_word_1 = duc_reg_iface->write_memory.at(duc_block_control::SR_FREQ_ADDR); BOOST_REQUIRE(freq_word_1 != 0); - UHD_LOG_INFO("TEST", "Doubling input rate (to 2.0)"); + UHD_LOG_INFO( + "TEST", "Doubling input rate (to " << (DEFAULT_RATE / 4) / 1e6 << " MHz)"); // Now this should change the freq word, but not the absolute frequency mock_sink_term.set_edge_property<double>("samp_rate", 2 * mock_sink_term.get_edge_property<double>( - "samp_rate", {res_source_info::INPUT_EDGE, 0}), + "samp_rate", {res_source_info::INPUT_EDGE, 0}), {res_source_info::INPUT_EDGE, 0}); const double freq_word_2 = duc_reg_iface->write_memory.at(duc_block_control::SR_FREQ_ADDR); // The frequency word is the phase increment, which will halve. We skirt // around fixpoint/floating point accuracy issues by using CLOSE. BOOST_CHECK_CLOSE(double(freq_word_1) / double(freq_word_2), 2.0, 1e-6); - // Reset the interpolation test_duc->set_property<int>("interp", TEST_INTERP, 0); BOOST_REQUIRE_EQUAL(test_duc->get_property<int>("interp", 0), TEST_INTERP); |