aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gr-usrptest/python/flowgraphs
diff options
context:
space:
mode:
authorAndrej Rode <andrej.rode@ettus.com>2016-10-24 10:25:42 -0700
committerMartin Braun <martin.braun@ettus.com>2017-05-26 16:01:37 -0700
commit76e9e6393fe1d5a0ccc9e05deb431694921850ec (patch)
treeb7f1097a04fd7a7d0a423a353fbeba037746b782 /tools/gr-usrptest/python/flowgraphs
parent06ff34eaa9e147b11d2698308fa91a5260fee2d2 (diff)
downloaduhd-76e9e6393fe1d5a0ccc9e05deb431694921850ec.tar.gz
uhd-76e9e6393fe1d5a0ccc9e05deb431694921850ec.tar.bz2
uhd-76e9e6393fe1d5a0ccc9e05deb431694921850ec.zip
gr-usrptest: Initial creation
- new OOT-blocks: phase_calc_ccf hier-block, measurement_sink_f - new python submodules: flowgraphs, functions, rts_tests - new apps: usrp_phasealignment.py - cmdline example for manual testing OOT-Blocks: - phase_calc_ccf takes two complex input streams and conjugate multiplys them and extracts the phase from the result and converts it to degree scale - measurement_sink_f: takes a float input stream and calculates average and stddev for a specified number of samples. Start of a measurement is invoked by a call of start_run() on the block. After a couple of runs average and stddev can be extracted. Python modules: - flowgrahps contains reconfigurable flowgraphs for different GNU Radio RF test cases - functions contains functions which are used in different apps/RTS scripts - rts_tests contains test cases which are meant to be executed from the RTS system. Depends on TinyDB, labview_automation Apps: - usrp_phasealignment.py is an example how to use the underlying flowgraph to measure phase differences. Commandline arguments of uhd_app can be used and several additional arguments can/have to be specified. Runs a phase difference measurement --runs number of times and averages phase difference over --duration seconds. Between measurements USRP sinks are retuned to random frequencies in daughterboard range. Results are displayed using motherboard serial and daughterboard serial
Diffstat (limited to 'tools/gr-usrptest/python/flowgraphs')
-rw-r--r--tools/gr-usrptest/python/flowgraphs/CMakeLists.txt28
-rw-r--r--tools/gr-usrptest/python/flowgraphs/__init__.py14
-rw-r--r--tools/gr-usrptest/python/flowgraphs/phasealignment_fg.py119
-rw-r--r--tools/gr-usrptest/python/flowgraphs/selftest_fg.py122
4 files changed, 283 insertions, 0 deletions
diff --git a/tools/gr-usrptest/python/flowgraphs/CMakeLists.txt b/tools/gr-usrptest/python/flowgraphs/CMakeLists.txt
new file mode 100644
index 000000000..7ea94b505
--- /dev/null
+++ b/tools/gr-usrptest/python/flowgraphs/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+# Install python sources
+########################################################################
+GR_PYTHON_INSTALL(
+ FILES
+ __init__.py
+ selftest_fg.py
+ phasealignment_fg.py DESTINATION ${GR_PYTHON_DIR}/usrptest/flowgraphs
+)
diff --git a/tools/gr-usrptest/python/flowgraphs/__init__.py b/tools/gr-usrptest/python/flowgraphs/__init__.py
new file mode 100644
index 000000000..048e5638a
--- /dev/null
+++ b/tools/gr-usrptest/python/flowgraphs/__init__.py
@@ -0,0 +1,14 @@
+"""
+usrptest.flowgraphs
+======================================
+
+Contents
+--------
+
+Subpackages
+-----------
+::
+
+The existance of the file turns the folder into a Python module.
+
+"""
diff --git a/tools/gr-usrptest/python/flowgraphs/phasealignment_fg.py b/tools/gr-usrptest/python/flowgraphs/phasealignment_fg.py
new file mode 100644
index 000000000..f120e2421
--- /dev/null
+++ b/tools/gr-usrptest/python/flowgraphs/phasealignment_fg.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python2
+
+from gnuradio import gr
+from gnuradio import uhd
+from gnuradio import analog
+from usrptest import phase_calc_ccf, measurement_sink_f
+from usrptest.functions import log_level
+from random import uniform
+from ast import literal_eval
+import copy
+import logging
+import sys
+
+
+class phasealignment_fg(gr.top_block):
+ def __init__(self, uhd_app):
+ gr.top_block.__init__(self, "Calculate dphi for all USRPs (Rx only)")
+ ##############################
+ # Block dicts
+ ##############################
+ self.log = logging.getLogger(__name__)
+ [self.log.removeHandler(h) for h in self.log.handlers]
+ self.log.addHandler(logging.StreamHandler(sys.stdout))
+ self.log.setLevel(log_level(uhd_app.args.log_level))
+ self.rx_streams = list()
+ self.phase_diff_calc = list()
+ self.measurement_sink = list()
+ self.uhd_app = copy.copy(uhd_app)
+ self.tx_app = copy.copy(uhd_app)
+ self.samp_rate = uhd_app.args.samp_rate
+ # Create all devices specified in --receiver
+ # Create all remaining blocks and connect devices to the first port and
+ # sink
+ self.uhd_app.args.num_chan = len(self.uhd_app.args.channels)
+ self.log.info('setting up usrp....')
+ ##############################
+ # Setup RX
+ ##############################
+ self.log.debug("RX-Setup with args: {}".format(self.uhd_app.args))
+ self.uhd_app.setup_usrp(uhd.usrp_source, self.uhd_app.args)
+ if self.uhd_app.args.measurement_setup is not None:
+ self.measurement_channels = self.uhd_app.args.measurement_setup.strip(
+ ).split(',')
+ # make sure every channels is listed in measurement_channels at least once
+ if len(set(
+ self.measurement_channels)) != self.uhd_apps.args.num_chan:
+ self.uhd_app.vprint(
+ "[{prefix}] Number of measurement channels has to be the number of used channels."
+ )
+ self.uhd_app.exit(1)
+ self.measurement_channels = [self.uhd_app.args.channels.index(m) for m in self.measurement_channels]
+ else:
+ self.measurement_channels = range(self.uhd_app.args.num_chan)
+
+ self.measurement_channels_names = list()
+ for chan in self.measurement_channels:
+ usrp_info = self.uhd_app.usrp.get_usrp_info(chan)
+ self.measurement_channels_names.append("_".join(
+ [usrp_info['mboard_serial'], usrp_info['rx_serial']]))
+
+ #Connect channels to first port of d_phi_calc_block and to measurement_sink
+ for num, chan in enumerate(self.measurement_channels[:-1]):
+ self.phase_diff_calc.append(phase_calc_ccf())
+ self.measurement_sink.append(
+ measurement_sink_f(
+ int(self.uhd_app.args.samp_rate *
+ self.uhd_app.args.duration), self.uhd_app.args.runs))
+ self.connect((self.uhd_app.usrp, chan),
+ (self.phase_diff_calc[num], 0))
+ self.connect((self.phase_diff_calc[num], 0),
+ (self.measurement_sink[num], 0))
+ # Connect devices to second port of d_phi_block
+ for num, chan in enumerate(self.measurement_channels[1:]):
+ self.connect((self.uhd_app.usrp, chan),
+ (self.phase_diff_calc[num], 1))
+ ##############################
+ # Setup TX
+ ##############################
+ if self.uhd_app.args.tx_channels is not None:
+ self.tx_app.args.antenna = self.tx_app.args.tx_antenna
+ self.tx_app.args.channels = [
+ int(chan.strip())
+ for chan in self.tx_app.args.tx_channels.split(',')
+ ]
+ self.tx_app.usrp = None
+ self.log.debug("TX-Setup with args: {}".format(self.tx_app.args))
+ self.tx_app.setup_usrp(uhd.usrp_sink, self.tx_app.args)
+ self.siggen = analog.sig_source_c(self.samp_rate,
+ analog.GR_COS_WAVE,
+ self.tx_app.args.tx_offset, 1.0)
+ for chan in range(len(self.tx_app.channels)):
+ self.connect((self.siggen, 0), (self.tx_app.usrp, chan))
+
+
+ def get_samp_rate(self):
+ return self.samp_rate
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+
+ def retune_frequency(self, band_num=1, bands=1):
+ ref_chan = self.uhd_app.channels[0]
+ freq_range = literal_eval(
+ self.uhd_app.usrp.get_freq_range(ref_chan).__str__(
+ )) # returns tuple with (start_freq, end_freq, step)
+
+ if bands > 1:
+ bw = (freq_range[1] - freq_range[0])/bands
+ freq_range = list(freq_range)
+ freq_range[0] = freq_range[0] + ((band_num-1) % bands)*bw
+ freq_range[1] = freq_range[0] + bw
+
+ retune_freq = uniform(freq_range[0], freq_range[1])
+ self.log.info('tune all channels to: {:f} MHz'.format(retune_freq /
+ 1e6))
+ self.uhd_app.set_freq(retune_freq)
+ self.log.info('tune all channels to: {:f} MHz'.format(
+ self.uhd_app.args.freq / 1e6))
+ self.uhd_app.set_freq(self.uhd_app.args.freq)
diff --git a/tools/gr-usrptest/python/flowgraphs/selftest_fg.py b/tools/gr-usrptest/python/flowgraphs/selftest_fg.py
new file mode 100644
index 000000000..cdfc35e74
--- /dev/null
+++ b/tools/gr-usrptest/python/flowgraphs/selftest_fg.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+from gnuradio import blocks
+from gnuradio import gr
+from gnuradio import uhd
+from usrptest import phase_calc_ccf
+from gnuradio.uhd.uhd_app import UHDApp
+import numpy as np
+
+class selftest_fg(gr.top_block):
+
+ def __init__(self, freq, samp_rate, dphase, devices=list()):
+ gr.top_block.__init__(self, "Generate Signal extract phase")
+
+ ##################################################
+ # Variables
+ ##################################################
+ self.samp_rate = samp_rate
+ self.freq = 10e3
+ self.devices = devices
+ self.dphase = dphase
+ self.tx_gain = 50
+ self.rx_gain = 50
+ self.center_freq = freq
+ self.omega = 2*np.pi*self.freq
+ self.steps = np.arange(
+ self.samp_rate)*float(self.omega)/float(self.samp_rate)
+ self.reference = self.complex_sine(self.steps)
+ self.test_signal = self.complex_sine(self.steps+0.5*np.pi)
+ self.device_test = False
+
+ ##################################################
+ # Block dicts
+ ##################################################
+ self.rx_devices = dict()
+ self.tx_devices = dict()
+ self.sink_dict = dict()
+ self.phase_dict = dict()
+ self.reference_source = blocks.vector_source_c(self.reference)
+
+ if len(self.devices):
+ ##################################################
+ # Devices
+ ##################################################
+ self.device_test = True
+ #To reuse existing setup_usrp() command
+ for device in self.devices:
+ # Create and configure all devices
+ self.rx_devices[device] = uhd.usrp_source(
+ device, uhd.stream_args(
+ cpu_format="fc32", channel=range(1)))
+ self.tx_devices[device] = uhd.usrp_sink(
+ device, uhd.stream_args(
+ cpu_format="fc32", channel=range(1)))
+ self.rx_devices[device].set_samp_rate(self.samp_rate)
+ self.rx_devices[device].set_center_freq(self.center_freq, 0)
+ self.rx_devices[device].set_gain(self.rx_gain, 0)
+ self.tx_devices[device].set_samp_rate(self.samp_rate)
+ self.tx_devices[device].set_center_freq(self.center_freq, 0)
+ self.tx_devices[device].set_gain(self.tx_gain, 0)
+ self.sink_dict[device] = blocks.vector_sink_f()
+ self.phase_dict[device] = phase_calc_ccf(
+ self.samp_rate, self.freq)
+ for device in self.tx_devices.values():
+ self.connect((self.reference_source, 0), (device, 0))
+
+ for device_key in self.rx_devices.keys():
+ self.connect(
+ (self.rx_devices[device_key], 0), (self.phase_dict[device_key], 0))
+ self.connect((self.reference_source, 0),
+ (self.phase_dict[device_key], 1))
+ self.connect(
+ (self.phase_dict[device_key], 0), (self.sink_dict[device_key], 0))
+ # Debug options
+ # self.sink_list.append(blocks.vector_sink_c())
+ #self.connect((device, 0), (self.sink_list[-1], 0))
+ # self.sink_list.append(blocks.vector_sink_c())
+ #self.connect((self.reference_source, 0), (self.sink_list[-1], 0))
+ else:
+ ##################################################
+ # Blocks
+ ##################################################
+ self.result = blocks.vector_sink_f(1)
+ self.test_source = blocks.vector_source_c(self.test_signal)
+ self.block_phase_calc = phase_calc_ccf(
+ self.samp_rate, self.freq)
+
+ ##################################################
+ # Connections
+ ##################################################
+ self.connect((self.reference_source, 0), (self.block_phase_calc, 1))
+ self.connect((self.test_source, 0), (self.block_phase_calc, 0))
+ self.connect((self.block_phase_calc, 0), (self.result, 0))
+ def complex_sine(self, steps):
+ return np.exp(1j*steps)
+
+ def get_samp_rate(self):
+ return self.samp_rate
+
+ def set_samp_rate(self, samp_rate):
+ self.samp_rate = samp_rate
+
+ def run(self):
+ self.start()
+ self.wait()
+ if self.device_test:
+ data = dict()
+ for device_key in self.sink_dict.keys():
+ curr_data = self.sink_dict[device_key].data()
+ curr_data = curr_data[int(0.2*self.samp_rate):-int(0.2*self.samp_rate)]
+ phase_avg = np.average(curr_data)
+ if (np.max(curr_data) < phase_avg+self.dphase*0.5) and (np.min(curr_data) > phase_avg-self.dphase*0.5):
+ data[device_key] = phase_avg
+ else:
+ print("Error phase not settled")
+
+ #Debug
+ # plt.ylim(-1, 1)
+ # plt.xlim(self.samp_rate/2.), (self.samp_rate/2.)+1000)
+ #for key in data:
+ # plt.plot(data[key])
+ return data