diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-08-12 15:05:46 +0200 |
---|---|---|
committer | Michael Dickens <michael.dickens@ettus.com> | 2020-09-10 14:17:50 -0400 |
commit | 9e4836dc10b2a6ca537d8c290ac668d94692cbe4 (patch) | |
tree | 95957067b5f9e3a3d0489d4a486bdb2e515d7dea /gr-uhd/apps/uhd_siggen_base.py | |
parent | cc4854828366b921f4efbe46e5524be7fe3a6cf8 (diff) |
uhd: Update uhd_siggen_gui to allow setting absolute power
Note: This requires a USRP with power API enabled.
Summary of changes:
- uhd_app now provides the --power argument and applies it as
a reference power level. It clashes with --gain. UHDApp now has two
'modes' for setting the power: Via gain (the previous, standard way)
or by setting a power. UHDApp calls all the right APIs for each use
case.
- uhd_siggen_base is now aware of these settings and will make sure the
output power is correct by combining the requested power and the
requested amplitude (meaning, it sets a ref power that is at the
correct level above the requested power level).
- The GUI can now set either power or gain, depending on command line
arguments. When changing the amplitude in power mode, the ref power is
also changed so the output power (in dBm) stays the same when the
amplitude changes.
- siggen now checks for invalid amplitudes (must be in 0 <= amplitude <=
1).
- --amplitude was moved from uhd_app.py to uhd_siggen_base.py, where it
belongs. uhd_fft for example does not have that argument.
- If --amplitude is set to 0.0, then it now fails in power mode. It's
still possible in gain mode.
Diffstat (limited to 'gr-uhd/apps/uhd_siggen_base.py')
-rw-r--r-- | gr-uhd/apps/uhd_siggen_base.py | 74 |
1 files changed, 70 insertions, 4 deletions
diff --git a/gr-uhd/apps/uhd_siggen_base.py b/gr-uhd/apps/uhd_siggen_base.py index 38d197e3ad..daf8184f56 100644 --- a/gr-uhd/apps/uhd_siggen_base.py +++ b/gr-uhd/apps/uhd_siggen_base.py @@ -22,6 +22,9 @@ from gnuradio import analog from gnuradio import blocks from gnuradio.gr.pubsub import pubsub +# PyLint can't reliably detect C++ exports in modules, so let's disable that +# pylint: disable=no-member + DESC_KEY = 'desc' SAMP_RATE_KEY = 'samp_rate' LINK_RATE_KEY = 'link_rate' @@ -35,7 +38,6 @@ WAVEFORM_FREQ_KEY = 'waveform_freq' WAVEFORM_OFFSET_KEY = 'waveform_offset' WAVEFORM2_FREQ_KEY = 'waveform2_freq' FREQ_RANGE_KEY = 'freq_range' -GAIN_RANGE_KEY = 'gain_range' TYPE_KEY = 'type' WAVEFORMS = { @@ -52,9 +54,25 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): GUI-unaware GNU Radio flowgraph. This may be used either with command line applications or GUI applications. """ + MIN_AMP_POWER_MODE = .001 + def __init__(self, args): gr.top_block.__init__(self) pubsub.__init__(self) + if not 0.0 <= args.amplitude <= 1.0: + raise ValueError( + "Invalid value for amplitude: {}. Must be in [0.0, 1.0]" + .format(args.amplitude)) + # If the power argument is given, we need to turn that into a power + # *reference* level. This is a bit of a hack because we're assuming + # knowledge of UHDApp (i.e. we're leaking abstractions). But it's simple + # and harmless enough. + if args.power: + if args.amplitude < self.MIN_AMP_POWER_MODE: + raise RuntimeError( + "[ERROR] Invalid amplitude: In power mode, amplitude must be " + "larger than {}!".format(self.MIN_AMP_POWER_MODE)) + args.power -= 20 * math.log10(args.amplitude) UHDApp.__init__(self, args=args, prefix="UHD-SIGGEN") self.extra_sink = None @@ -78,8 +96,7 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): self.publish(SAMP_RATE_KEY, lambda: self.usrp.get_samp_rate()) self.publish(DESC_KEY, lambda: self.usrp_description) self.publish(FREQ_RANGE_KEY, lambda: self.usrp.get_freq_range(self.channels[0])) - self.publish(GAIN_RANGE_KEY, lambda: self.usrp.get_gain_range(self.channels[0])) - self.publish(GAIN_KEY, lambda: self.usrp.get_gain(self.channels[0])) + self.publish(GAIN_KEY, lambda: self.get_gain_or_power()) self[SAMP_RATE_KEY] = args.samp_rate self[TX_FREQ_KEY] = args.freq @@ -92,12 +109,13 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): #subscribe set methods self.subscribe(SAMP_RATE_KEY, self.set_samp_rate) - self.subscribe(GAIN_KEY, self.set_gain) + self.subscribe(GAIN_KEY, self.set_gain_or_power) self.subscribe(TX_FREQ_KEY, self.set_freq) self.subscribe(AMPLITUDE_KEY, self.set_amplitude) self.subscribe(WAVEFORM_FREQ_KEY, self.set_waveform_freq) self.subscribe(WAVEFORM2_FREQ_KEY, self.set_waveform2_freq) self.subscribe(TYPE_KEY, self.set_waveform) + self.subscribe(RF_FREQ_KEY, self.update_gain_range) #force update on pubsub keys for key in (SAMP_RATE_KEY, GAIN_KEY, TX_FREQ_KEY, @@ -234,8 +252,51 @@ class USRPSiggen(gr.top_block, pubsub, UHDApp): else: return True # Waveform not yet set self.vprint("Set amplitude to:", amplitude) + self.update_gain_range() return True + def get_gain_or_power(self): + """ + Depending on gain type, return either a power level or the current gain + """ + if self.gain_type == self.GAIN_TYPE_GAIN: + return self.usrp.get_gain(self.channels[0]) + return self.usrp.get_power_reference(self.channels[0]) \ + + 20 * math.log10(self[AMPLITUDE_KEY]) + + def set_gain_or_power(self, gain_or_power): + """ + Call this if a gain or power value changed, but you're not sure which it + is. + + If it's a power, we subtract the signal offset to generate a reference + power. + """ + if self.gain_type == self.GAIN_TYPE_POWER: + self.set_power_reference( + gain_or_power - 20 * math.log10(self[AMPLITUDE_KEY])) + else: + self.set_gain(gain_or_power) + + def update_gain_range(self): + """ + Update self.gain_range. + """ + if self.gain_type == self.GAIN_TYPE_POWER: + if self[AMPLITUDE_KEY] < self.MIN_AMP_POWER_MODE: + raise RuntimeError( + "[ERROR] Invalid amplitude: In power mode, amplitude must be " + "larger than {}!".format(self.MIN_AMP_POWER_MODE)) + power_range = self.usrp.get_power_range(self.channels[0]) + ampl_offset = 20 * math.log10(self[AMPLITUDE_KEY]) + self.gain_range = uhd.meta_range( + math.floor(power_range.start() + ampl_offset), + math.ceil(power_range.stop() + ampl_offset), + power_range.step() + ) + self.vprint("Updated power range to {:.2f} ... {:.2f} dBm.".format( + self.gain_range.start(), self.gain_range.stop())) + def setup_argparser(): """ @@ -246,6 +307,11 @@ def setup_argparser(): tx_or_rx="Tx", ) group = parser.add_argument_group('Siggen Arguments') + group.add_argument("-m", "--amplitude", type=eng_arg.eng_float, default=0.15, + help="Set output amplitude to AMPL (0.0-1.0). Note that " + "if --power is given, UHD will attempt to match the " + "output power regardless of the amplitude.", + metavar="AMPL") group.add_argument("-x", "--waveform-freq", type=eng_arg.eng_float, default=0.0, help="Set baseband waveform frequency to FREQ") group.add_argument("-y", "--waveform2-freq", type=eng_arg.eng_float, default=0.0, |