diff options
author | Andrej Rode <andrej.rode@ettus.com> | 2016-10-24 10:25:42 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-05-26 16:01:37 -0700 |
commit | 76e9e6393fe1d5a0ccc9e05deb431694921850ec (patch) | |
tree | b7f1097a04fd7a7d0a423a353fbeba037746b782 /tools/gr-usrptest/python/flowgraphs | |
parent | 06ff34eaa9e147b11d2698308fa91a5260fee2d2 (diff) | |
download | uhd-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.txt | 28 | ||||
-rw-r--r-- | tools/gr-usrptest/python/flowgraphs/__init__.py | 14 | ||||
-rw-r--r-- | tools/gr-usrptest/python/flowgraphs/phasealignment_fg.py | 119 | ||||
-rw-r--r-- | tools/gr-usrptest/python/flowgraphs/selftest_fg.py | 122 |
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 |