diff options
| author | Martin Braun <martin.braun@ettus.com> | 2020-04-06 11:56:15 -0700 | 
|---|---|---|
| committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-04-17 07:59:50 -0500 | 
| commit | 261ee6d677b83ca15a3d38ddbb0c02ad5d4602fe (patch) | |
| tree | 8ef445531b21cfac4ef151bfbac4bb1f99789acb /host/examples | |
| parent | a63682f981c3d4b828b5454a7d4849d181b9c8b3 (diff) | |
| download | uhd-261ee6d677b83ca15a3d38ddbb0c02ad5d4602fe.tar.gz uhd-261ee6d677b83ca15a3d38ddbb0c02ad5d4602fe.tar.bz2 uhd-261ee6d677b83ca15a3d38ddbb0c02ad5d4602fe.zip | |
examples: Add --power command line option to tx_waveforms
If you run
    tx_waveforms --power -20 [other args]
it will try to set the out power to -20 dBm. The signal amplitude is
factored in, so changing --ampl will not change the actual TX power
unless it causes clipping, or becomes too low.
If the USRP does not support setting a power, the program will terminate
early. If it does support setting a power, but can't reach the requested
power, it will coerce, and print the actual, available power.
Diffstat (limited to 'host/examples')
| -rw-r--r-- | host/examples/tx_waveforms.cpp | 53 | ||||
| -rw-r--r-- | host/examples/wavetable.hpp | 19 | 
2 files changed, 54 insertions, 18 deletions
| diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 173f339e2..53de799be 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -42,7 +42,7 @@ int UHD_SAFE_MAIN(int argc, char* argv[])      std::string args, wave_type, ant, subdev, ref, pps, otw, channel_list;      uint64_t total_num_samps;      size_t spb; -    double rate, freq, gain, wave_freq, bw, lo_offset; +    double rate, freq, gain, power, wave_freq, bw, lo_offset;      float ampl;      // setup the program options @@ -59,6 +59,7 @@ int UHD_SAFE_MAIN(int argc, char* argv[])              "Offset for frontend LO in Hz (optional)")          ("ampl", po::value<float>(&l)->default_value(float(0.3)), "amplitude of the waveform [0 to 0.7]")          ("gain", po::value<double>(&gain), "gain for the RF chain") +        ("power", po::value<double>(&power), "Transmit power (if USRP supports it)")          ("ant", po::value<std::string>(&ant), "antenna selection")          ("subdev", po::value<std::string>(&subdev), "subdevice specification")          ("bw", po::value<double>(&bw), "analog frontend filter bandwidth in Hz") @@ -127,6 +128,22 @@ int UHD_SAFE_MAIN(int argc, char* argv[])          return ~0;      } +    // for the const wave, set the wave freq for small samples per period +    if (wave_freq == 0) { +        if (wave_type == "CONST") { +            wave_freq = usrp->get_tx_rate() / 2; +        } else { +            throw std::runtime_error( +                "wave freq cannot be 0 with wave type other than CONST"); +        } +    } + +    // pre-compute the waveform values +    const wave_table_class wave_table(wave_type, ampl); +    const size_t step = +        boost::math::iround(wave_freq / usrp->get_tx_rate() * wave_table_len); +    size_t index = 0; +      for (size_t ch = 0; ch < channel_nums.size(); ch++) {          std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq / 1e6)                    << std::endl; @@ -142,7 +159,23 @@ int UHD_SAFE_MAIN(int argc, char* argv[])                    << std::endl;          // set the rf gain -        if (vm.count("gain")) { +        if (vm.count("power")) { +            if (!usrp->has_tx_power_reference(ch)) { +                std::cout << "ERROR: USRP does not have a reference power API on channel " +                          << ch << "!" << std::endl; +                return EXIT_FAILURE; +            } +            std::cout << "Setting TX output power: " << power << " dBm..." << std::endl; +            usrp->set_tx_power_reference(power - wave_table.get_power(), ch); +            std::cout << "Actual TX output power: " +                      << usrp->get_tx_power_reference(ch) + wave_table.get_power() +                      << " dBm..." << std::endl; +            if (vm.count("gain")) { +                std::cout << "WARNING: If you specify both --power and --gain, " +                             " the latter will be ignored." +                          << std::endl; +            } +        } else if (vm.count("gain")) {              std::cout << boost::format("Setting TX Gain: %f dB...") % gain << std::endl;              usrp->set_tx_gain(gain, channel_nums[ch]);              std::cout << boost::format("Actual TX Gain: %f dB...") @@ -169,16 +202,6 @@ int UHD_SAFE_MAIN(int argc, char* argv[])      std::this_thread::sleep_for(std::chrono::seconds(1)); // allow for some setup time -    // for the const wave, set the wave freq for small samples per period -    if (wave_freq == 0) { -        if (wave_type == "CONST") { -            wave_freq = usrp->get_tx_rate() / 2; -        } else { -            throw std::runtime_error( -                "wave freq cannot be 0 with wave type other than CONST"); -        } -    } -      // error when the waveform is not possible to generate      if (std::abs(wave_freq) > usrp->get_tx_rate() / 2) {          throw std::runtime_error("wave freq out of Nyquist zone"); @@ -187,12 +210,6 @@ int UHD_SAFE_MAIN(int argc, char* argv[])          throw std::runtime_error("wave freq too small for table");      } -    // pre-compute the waveform values -    const wave_table_class wave_table(wave_type, ampl); -    const size_t step = -        boost::math::iround(wave_freq / usrp->get_tx_rate() * wave_table_len); -    size_t index = 0; -      // create a transmit streamer      // linearly map channels (index0 = channel0, index1 = channel1, ...)      uhd::stream_args_t stream_args("fc32", otw); diff --git a/host/examples/wavetable.hpp b/host/examples/wavetable.hpp index dc2a93c36..d18bd1fa5 100644 --- a/host/examples/wavetable.hpp +++ b/host/examples/wavetable.hpp @@ -27,17 +27,28 @@ public:              // Fill with I == ampl, Q == 0              std::fill(                  _wave_table.begin(), _wave_table.end(), std::complex<float>{ampl, 0.0}); +            _power_dbfs = static_cast<double>(20 * std::log10(ampl));          } else if (wave_type == "SQUARE") {              // Fill the second half of the table with ampl, first half with              // zeros              std::fill(_wave_table.begin() + wave_table_len / 2,                  _wave_table.end(),                  std::complex<float>{ampl, 0.0}); +            _power_dbfs = static_cast<double>(20 * std::log10(ampl)) +                          - static_cast<double>(10 * std::log10(2.0));          } else if (wave_type == "RAMP") {              // Fill I values with ramp from -1 to 1, Q with zero +            float energy_acc = 0.0f;              for (size_t i = 0; i < wave_table_len; i++) {                  _wave_table[i] = {(2.0f * i / (wave_table_len - 1) - 1.0f) * ampl, 0.0}; +                energy_acc += std::norm(_wave_table[i]);              } +            _power_dbfs = static_cast<double>(energy_acc / wave_table_len); +            // Note: The closed-form solution to the average sum of squares of +            // the ramp is: +            // 1.0 / 3 + 2.0 / (3 * N) + 1.0 / (3 * N) + 4.0 / (6 * N^2)) +            // where N == wave_table_len, but it turns out be be less code if we +            // just calculate the power on the fly.          } else if (wave_type == "SINE") {              static const double tau = 2 * std::acos(-1.0);              static const std::complex<float> J(0, 1); @@ -49,6 +60,7 @@ public:                  _wave_table[i] =                      ampl * std::exp(J * static_cast<float>(tau * i / wave_table_len));              } +            _power_dbfs = static_cast<double>(20 * std::log10(ampl));          } else {              throw std::runtime_error("unknown waveform type: " + wave_type);          } @@ -59,6 +71,13 @@ public:          return _wave_table[index % wave_table_len];      } +    //! Return the signal power in dBFS +    inline double get_power() const +    { +        return _power_dbfs; +    } +  private:      std::vector<std::complex<float>> _wave_table; +    double _power_dbfs;  }; | 
