aboutsummaryrefslogtreecommitdiffstats
path: root/host/python
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2021-09-23 09:51:35 +0200
committerAaron Rossetto <aaron.rossetto@ni.com>2021-10-06 11:57:25 -0700
commit9650342c12f95811f670a179494f43717788e6ed (patch)
tree1d0635effefcaccbada741915aebd991da3e17b8 /host/python
parent1beeca2bbafed1681518785530d3dfb9b2c56f42 (diff)
downloaduhd-9650342c12f95811f670a179494f43717788e6ed.tar.gz
uhd-9650342c12f95811f670a179494f43717788e6ed.tar.bz2
uhd-9650342c12f95811f670a179494f43717788e6ed.zip
python: multi_usrp: Fix issues with recv_num_samps()
- This function didn't set the time properly for multi-chan rx - There was no way to set a start time manually - It relied on garbage collection and correct destruction of streamers when being called multiple times. Addressed this by adding an option to pass in an existing streamer object. - Linter wasn't too happy with this function.
Diffstat (limited to 'host/python')
-rw-r--r--host/python/uhd/usrp/multi_usrp.py87
1 files changed, 63 insertions, 24 deletions
diff --git a/host/python/uhd/usrp/multi_usrp.py b/host/python/uhd/usrp/multi_usrp.py
index 7fb73c97e..a025b10d1 100644
--- a/host/python/uhd/usrp/multi_usrp.py
+++ b/host/python/uhd/usrp/multi_usrp.py
@@ -36,53 +36,92 @@ class MultiUSRP(lib.usrp.multi_usrp):
self.get_tree().access_device_addr("/mboards/0/args").get().to_dict()
setattr(self, 'get_mpm_client', lambda: _get_mpm_client(token, mb_args))
- def recv_num_samps(self, num_samps, freq, rate=1e6, channels=(0,), gain=10):
+ def recv_num_samps(self,
+ num_samps,
+ freq,
+ rate=1e6,
+ channels=(0,),
+ gain=10,
+ start_time=None,
+ streamer=None):
"""
RX a finite number of samples from the USRP
+
+ This is a convenience function to minimize the amount of code required
+ for just capturing samples. When calling this function more than once
+ in a script, pass in a streamer object to avoid recreating streamers
+ more than once.
+
:param num_samps: number of samples to RX
:param freq: RX frequency (Hz)
:param rate: RX sample rate (Hz)
:param channels: list of channels to RX on
:param gain: RX gain (dB)
+ :param start_time: A valid TimeSpec object with the starting time. If
+ None, then streaming starts immediately.
+ :param streamer: An RX streamer object. If None, this function will create
+ one locally and attempt to destroy it afterwards.
:return: numpy array of complex floating-point samples (fc32)
"""
- result = np.empty((len(channels), num_samps), dtype=np.complex64)
-
+ def _config_streamer(streamer):
+ """
+ Set up the correct streamer
+ """
+ if streamer is None:
+ st_args = lib.usrp.stream_args("fc32", "sc16")
+ st_args.channels = channels
+ streamer = super(MultiUSRP, self).get_rx_stream(st_args)
+ return streamer
+ def _start_stream(streamer):
+ """
+ Issue the start-stream command.
+ """
+ stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.start_cont)
+ stream_cmd.stream_now = (len(channels) == 1) and start_time is None
+ if not stream_cmd.stream_now:
+ if start_time is not None:
+ stream_cmd.time_spec = start_time
+ else:
+ stream_cmd.time_spec = lib.types.time_spec(
+ super(MultiUSRP, self).get_time_now().get_real_secs() + 0.05)
+ streamer.issue_stream_cmd(stream_cmd)
+ def _stop_stream(streamer):
+ """
+ Issue the start-stream command and flush the queue.
+ """
+ metadata = lib.types.rx_metadata()
+ stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.stop_cont)
+ streamer.issue_stream_cmd(stream_cmd)
+ while streamer.recv(recv_buffer, metadata):
+ pass
+ ## And go!
+ # Configure USRP
for chan in channels:
super(MultiUSRP, self).set_rx_rate(rate, chan)
super(MultiUSRP, self).set_rx_freq(lib.types.tune_request(freq), chan)
super(MultiUSRP, self).set_rx_gain(gain, chan)
-
- st_args = lib.usrp.stream_args("fc32", "sc16")
- st_args.channels = channels
+ # Configure streamer
+ streamer = _config_streamer(streamer)
metadata = lib.types.rx_metadata()
- streamer = super(MultiUSRP, self).get_rx_stream(st_args)
- buffer_samps = streamer.get_max_num_samps()
+ # Set up buffers and counters
+ result = np.empty((len(channels), num_samps), dtype=np.complex64)
recv_buffer = np.zeros(
- (len(channels), buffer_samps), dtype=np.complex64)
-
+ (len(channels), streamer.get_max_num_samps()), dtype=np.complex64)
recv_samps = 0
- stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.start_cont)
- stream_cmd.stream_now = True
- streamer.issue_stream_cmd(stream_cmd)
-
- samps = np.array([], dtype=np.complex64)
+ samps = 0
+ # Now stream
+ _start_stream(streamer)
while recv_samps < num_samps:
samps = streamer.recv(recv_buffer, metadata)
-
if metadata.error_code != lib.types.rx_metadata_error_code.none:
print(metadata.strerror())
if samps:
real_samps = min(num_samps - recv_samps, samps)
- result[:, recv_samps:recv_samps + real_samps] = recv_buffer[:, 0:real_samps]
+ result[:, recv_samps:recv_samps + real_samps] = \
+ recv_buffer[:, 0:real_samps]
recv_samps += real_samps
-
- stream_cmd = lib.types.stream_cmd(lib.types.stream_mode.stop_cont)
- streamer.issue_stream_cmd(stream_cmd)
-
- while samps:
- samps = streamer.recv(recv_buffer, metadata)
-
+ # Stop and clean up
+ _stop_stream(streamer)
# Help the garbage collection
streamer = None
return result