aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2020-04-06 11:56:15 -0700
committerAaron Rossetto <aaron.rossetto@ni.com>2020-04-17 07:59:50 -0500
commit261ee6d677b83ca15a3d38ddbb0c02ad5d4602fe (patch)
tree8ef445531b21cfac4ef151bfbac4bb1f99789acb /host
parenta63682f981c3d4b828b5454a7d4849d181b9c8b3 (diff)
downloaduhd-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')
-rw-r--r--host/examples/tx_waveforms.cpp53
-rw-r--r--host/examples/wavetable.hpp19
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>(&ampl)->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;
};