Table of Contents

From A to Z: GNU Radio with CorteXlab using USRPs

In the first tutorial we introduced the way to construct a CorteXlab “task” given a ready-made GNU Radio script.

This tutorial goes one step deeper, through the process of running an experiment on CorteXlab starting from an empty GNU Radio project on your computer.

For practical purposes, we will use a readily available GNU Radio example instead of starting from a clean sheet, but this will introduce the same procedure you'll use when you want to run your own project on CorteXlab.

Setup

The purpose of this tutorial is to execute an OFDM transmission between two USRP nodes. One node will be the transmitter and the other one will be the receiver. Instead of starting from an empty project, we are going to use the GNU Radio examples for an OFDM transmitter and receiver.

Let us start by copying the files tx_ofdm.grc and rx_ofdm.grc located in <path_to_gnuradio>/examples/digital/ofdm to a new folder of your choice. This folder will be your task folder. (Important note: <path_to_gnuradio> varies depending upon the way you are using GNURadio: If you have installed GNURadio on your workstation, you know where you choose to install it. If using the GNURadio instance which is part of CorteXlab toolchain on airlock, then the exact location is: /cortexlab/toolchains/current/share/gnuradio/examples/digital/ofdm/)

As you can guess tx_ofdm.grc will be used for the OFDM transmitter and rx_ofdm.grc for the OFDM receiver.

The file tree should look like that:

...
├── tuto_ofdm
│   ├── tx_ofdm.grc
│   └── rx_ofdm.grc
...

Editing the .grc files

The .grc files we copied from the examples folder were made to work in simulation mode, i.e. without actual transmissions and through a simulated channel. We will need to modify them to stream the waveforms to and from the USRPs through the UHD blocks {UHD: USRP Sink and UHD: USRP Source}

Using GNU Radio Companion (GRC) we are going to open and edit the two .grc files in order to use them with USRP nodes.

tx_ofdm.grc

Open tx_ofdm.grc with GRC. As you can see all the signal processing blocks that perform OFDM encoding and decoding are present, but the actual transmission section is based on a simulated channel model.

The first thing to do is to change the generate options in order to have a 'No GUI' project (the results will be stored in a file). Open the Options block (in the top left corner) and switch the Generate Options from QT GUI to No GUI. By doing this the blocks QT GUI Time Sink and QT GUI Frequency Sink can't be generated anymore (their names turn red with an error message if you open them) so we have to remove them from the graph.

The next thing to do is to replace the transmission and decoding parts to put an USRP Sink block instead. You can remove the throttle, Channel Model, OFDM Receiver and Tag Debug blocks. The Throttle is not needed anymore because the USRP Sink block will cadence our graph. In replacement for these blocks, put and connect an USRP Sink block.

The last thing to do is to configure USRP parameters. Open the USRP Sink block. We have nothing to change in the General tab. We don't have to specify a device address because we only have one USRP per node so it can be discovered automatically by the system. The Samp Rate should be binded with the samp_rate variable (We will change it later). Switch to the RF Options tab. The Center Freq value is of type float. You can set the Center Freq to 2.49e9 (2.49 GHz). We are going to use an absolute gain of 20 dB. The antenna to use is 'TX/RX' and the Bandwidth parameter should remain at 0. Finally, set the samp_rate variable to 5000000 (5 MHz) using the corresponding variable block located at the top of the flow graph.

In the end your graph should look like this :

rx_ofdm.grc

Open rx_ofdm.grc with GRC. As you can see it's quite similar to tx_ofdm, except this time the encoder part is a model and the decoder part faithfully describes the decoding process.

The first thing to do is to change the generate options in order to have a 'No GUI' project (the results will be stored in a file). Open the Options block (in the top left corner) and switch the Generate Options from QT GUI to No GUI.

The next thing to do is to replace encoding and transmission parts to put an USRP Source block instead. You can remove the Random Source, Stream to tagged stream, OFDM Transmitter Channel Model and throttle blocks. The Throttle is not needed anymore because the USRP Source block will cadence our graph. Instead of these blocks, put and connect an USRP Source block. Also, it is highly recommended to add a filter in the Tag Debug block in order to avoid printing a huge amount of useless data. Open the tag debug block and add the key filter “packet_num”.

The last thing to do is to configure USRP parameters. Open the USRP Source block. We have nothing to change in the General tab. We don't have to specify a device address because we only have one USRP per node so it can be discovered automatically by the system. The Samp Rate should be binded with the samp_rate variable (We will change it later). Switch to the RF Options tab. Set the Center Freq at 2490000000 (2.49 GHz). We are going to use an absolute gain of 20 dB. The antenna to use is 'TX/RX' ('RX2' can't be used !) and the Bandwidth parameter should remain at 0. Finally, set the samp_rate variable to 5e6 (5 MHz) using the corresponding variable block located in top of the flow graph.

In the end your graph should look like this :

Generate the python files

The last thing we need to do within GRC is to generate the two python files corresponding to the two .grc files. For both tx_ofdm.grc and rx_ofdm.grc press the generate flow graph button and that's it ! You now have the two python files tx_ofdm.py and rx_ofdm.py in the same folder as the .grc files.

Hint : the button is located near the play button and looks like this →

Create the scenario

The experiment description file called scenario.yaml will be looked for and read by the experiment scheduler to get which nodes and what software will be used during the experiment. It also gives the necessary startup scripts and parameters that the user provides for his experiment.

Here is a simple example of a scenario.yaml file:

# Example scenario description file
#
#   All lines starting with "#" and empty lines are ignored


# Scenario textual description
#   simple string (a one liner)
description: OFDM tx-rx example scenario for CorteXlab

# Experiment maximum duration
#   Time after which the experiment is forced to stop
#   integer (seconds)
duration: 60

# Node list
#
#   format:
#
#   nodes:
#     (machine):
#       command: (entry point script relative to the task root)

nodes:
  node4:
    command: ./rx_ofdm.py
    passive: true
  node6:
    command: ./tx_ofdm.py

This file uses the yaml syntax and is self-documented. Adapt this example to suit your needs.

Launch the experiment in CorteXlab

The file tree should now look like this:

...
├── tuto_ofdm
│   ├── tx_ofdm.py
│   ├── rx_ofdm.py
│   ├── scenario.yaml
│   ├── tx_ofdm.grc
│   └── rx_ofdm.grc
...

The .grc files will not be used by CorteXlab but you can leave them in the same directory.

Upload the files on airlock

Upload the tuto_ofdm directory on Airlock. For example, on Linux, it will look like this :

you@your-pc:~$ scp -P 2269 -r path/to/tuto_ofdm username@gw.cortexlab.fr:~ 

Create the task

Connect to Airlock through ssh as described here. For example :

you@yourpc:~$ ssh -p 2269 username@gw.cortexlab.fr

You will find in your home directory the previously uploaded tuto_ofdm directory.

Now, use the Minus CLI to create the task file:

you@srvairlock:~$ minus task create tuto_ofdm

The success (or failure) of the creation will be printed on screen. The task file will be created at the same level and with the same name as the targeted experiment folder but with a .task suffix, in our case tuto_ofdm.task.

Note: You can get help on the Minus CLI at anytime with minus -h

Book the testbed with OAR

As explained here, we need to book the testbed with OAR in order to run our experiment. Once you have booked the platform, you will be the exclusive user of the testbed; this will prevent any experimentation interference.

A basic example to submit an OAR interactive job requesting all available nodes, for 30 minutes:

$ oarsub -I -l nodes=BEST,walltime=0:30:00

Submit the task

Now, we have booked the testbed and we have a .task file containing our experiment. In order to run it, we need to submit it to the testbed scheduler.

For now, the scheduler is a simple FIFO queue, but a more advanced scheduling mechanism will be implemented in upcoming versions of CorteXlab.

To submit a task to the scheduler, use the Minus CLI:

you@srvairlock:~$ minus task submit tuto_ofdm.task

On screen will be prompted the id of your task in the scheduler. Note it down so that you can easily retrieve your results or monitor the progress of the experiment.

Observe the result

You can check the status of your experiment through the testbed scheduler. To do so, use the Minus CLI:

you@srvairlock:~$ minus testbed status
num total tasks:   2540
num tasks waiting: 0
num tasks running: 0
tasks currently running:
  (none)

The information given by this command enables you to deduce your experiment status. It's quite self-explanatory.

Once it's finished (we have set the duration to 2 minutes), Minus will take care of copying the results and output messages back to your home folder in srvairlock, so that you can analyze it.

All results are stored by task number in the results folder, inside your home folder.

Go in this folder :

you@srvairlock:~/tuto_ofdm$ cd ~/results
you@srvairlock:~/results$ ls
task_15
you@srvairlock:~/results$ cd task_15
you@srvairlock:~/results/task_15$ ls
node4.tgz  node6.tgz

So we see that we have a folder for each task and inside each folder one compressed file per participant node. Let's extract one of those files and see what's inside:

you@srvairlock:~/results/task_15$ tar -zxf node4.tgz
you@srvairlock:~/results/task_15$ ls 
node4  node4.tgz  node6.tgz
you@srvairlock:~/results/task_15$ cd node4
you@srvairlock:~/results/task_15/node4$ ls
rx_ofdm.grc  scenario.yaml  stdout.txt   tx_ofdm.py
rx_ofdm.py   stderr.txt     tx_ofdm.grc

We see that all of the files we used to create the task are inside. The other two are:

Let's take a look inside stdout.txt:

you@srvairlock:~/results/task_15/node4$ less stdout.txt

You should get a long file that looks more or less like this:

linux; GNU C++ version 4.9.2; Boost_105500; UHD_003.010.git-33-g9401bdbd

-- Opening a USRP2/N-Series device...
-- Current recv frame size: 1472 bytes
-- Current send frame size: 1472 bytes
-- Detecting internal GPSDO.... Found an internal GPSDO
-- Setting references to the internal GPSDO
Using Volk machine: avx_64_mmx_orc
Press Enter to quit: 
----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 0  Source: n/a     Key: packet_num   Value: 114
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 96  Source: n/a     Key: packet_num   Value: 115
  Offset: 192  Source: n/a     Key: packet_num   Value: 116
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 288  Source: n/a     Key: packet_num   Value: 117
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 384  Source: n/a     Key: packet_num   Value: 118
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 480  Source: n/a     Key: packet_num   Value: 119
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 576  Source: n/a     Key: packet_num   Value: 120
----------------------------------------------------------------------

----------------------------------------------------------------------
Tag Debug: Rx Bytes
Input Stream: 00
  Offset: 672  Source: n/a     Key: packet_num   Value: 121
----------------------------------------------------------------------

Eventually, the output file can start with some decoding error looking like this :

INFO: Detected an invalid packet at item 432
INFO: Parser returned #f

What's next ?

We have seen through this tutorial how to run an experiment in CorteXlab starting from a local example on your computer for USRPs. Now you know all the basics in order to run your own experiment in CorteXlab between two USRP nodes.

Follow on to the next tutorial, where we will repeat this procedure for the PicoSDR nodes.