Software Defined Radios (SDRs) are one of my favorite topics and application uses for FPGAs. I've found that they've become very popular in the industry space for their flexibility in their reconfiguration capabilities.
There are several FPGA-based SDR boards out there for development use, and one of my favorites is the USRP line of SDR boards from Ettus Research. For beginners specifically, I found the B205mini USRP on Diligent to be a great starting point for getting into SDR development. So I decided to write up the process for installing the Ettus UHD host drivers, GNU Radio, and how to control the B205mini using GNU Radio.
I'm doing this on a Linux machine running Ubuntu 18.04, covering everything from Ettus UHD driver installation, to GNU Radio installation, then creating a simple GNU Radio flowgraph to control the B205mini with.
B205mini RF Board Handling PracticesIf this your first experience with RF hardware, there are some practices for good/safe handling that you need to be aware of as compared to lower frequency electronics hardware.
RF Handling Rule 1: The first of which is to always have any transmit ports properly terminated with an antenna or equivalent 50Ω termination like I have:
RF Handling Rule 2: Never apply more than 0 dBm of power into any RF input.
RF Handling Rule 3: Always use at least 30dB of attenuation if operating in a loop-back configuration (with the TX port transmitting out to either an RX or Reference port).
RF Handling Rule 4: Never let any metal object contact the PCB while it's powered, and never let any form of moisture come in contact with it ever.
RF Handling Rule 5: Never allow the board to directly or indirectly come into contact with any voltage spikes, including any ESD events.
Install UHD DriversFirst things first, the host UHD drivers need to be installed on the host PC being used with the B205mini USRP.
Add the Ettus repository, update the local libraries, then install the initial UHD dependencies.
~$ sudo add-apt-repository ppa:ettusresearch/uhd
~$ sudo apt-get update
~$ sudo apt-get install libuhd-dev libuhd003 uhd-host
Change directories into the user library directory to where the UHD utilities have been installed. Copy the UHD driver rules file into the rules.d udev directory of the system then reload the system rules. This adds the UHD driver rules to be available to the userspace (/udev).
~$ cd /usr/lib/uhd/utils/
/usr/lib/uhd/utils$ sudo cp ./uhd-usrp.rules /etc/udev/rules.d/
/usr/lib/uhd/utils$ sudo udevadm control --reload-rules
/usr/lib/uhd/utils$ sudo udevadm trigger
From here you can either install the rest of the UHD drivers/tools with a Docker container of an Ubuntu image, or just install it natively. I just installed the rest natively as I felt that the Docker container installation didn't really save me that much effort. If you prefer to go that route however, you can find the Docker file from Ettus here.
Update local libraries and install remaining dependencies:
~$ sudo apt-get update
~$ sudo apt-get -y install -q libboost-all-dev libusb-1.0-0-dev libudev-dev python3-mako doxygen python3-docutils cmake python3-requests python3-numpy dpdk libdpdk-dev
~$ sudo rm -rf /var/lib/apt/lists/*
Clone UHD host repository from Ettus, change directories into it, and check out the desired version tag.
~$ sudo git clone https://github.com/EttusResearch/uhd.git /usr/local/src/uhd
~$ cd /usr/local/src/uhd/
/usr/local/src/uhd$ sudo git checkout v3.14.0.0
Create a build directory and change directories into it.
/usr/local/src/uhd$ sudo mkdir -p ./host/build
/usr/local/src/uhd$ cd ./host/build
Then build and install the UHD host driver.
/usr/local/src/uhd/host/build$ sudo cmake .. -DENABLE_PYTHON3=ON -DUHD_RELEASE_MODE=release -DCMAKE_INSTALL_PREFIX=/usr
/usr/local/src/uhd/host/build$ sudo make -j 2
/usr/local/src/uhd/host/build$ sudo make install
Finally, download the FPGA bitstream image files for the USRP boards.
/usr/local/src/uhd/host/build$ sudo uhd_images_downloader
Connect to B205mini SDR USRP BoardConnect to B205mini and test out UHD drivers by running the base UHD to find all devices connected to the host PC:
~$ uhd_find_devices
Then run the USRP Hardware Driver Peripheral Report Utility to get the full specifications of the B205mini that the host PC detects is connected.
~$ uhd_usrp_probe
I like always starting with these two commands to verify the connection between the host PC and USRP hardware.
Another fun little test for this first fire up of my B205mini is one of the example Python example functions. In particular, there is a fun little FFT program you can run that simply takes a specified center frequency and displays a small spectrum around that center frequency to see if any RF signal is present anywhere in that small spectrum.
I ran it passing 100MHz as the center frequency:
~$ cd /usr/lib/uhd/examples/python/
/usr/lib/uhd/examples/python$ python3 curses_fft.py -f 100e6
And as you can see from the screenshot above, there are no RF signals present in the spectrum aside from a little noise at or around the specified center frequency of 100MHz.
Install GNU RadioWith the UHD drivers installed and verified, and a successful connection to the B205mini it's finally time to install GNU Radio. Start by adding the GNU Radio repository and updating the local libraries. Then GNU Radio can be installed using apt.
~$ sudo add-apt-repository ppa:gnuradio/gnuradio-releases
~$ audo apt-get update
~$ sudo apt install gnuradio
See the installation instructions here on the GNU Radio wiki for installation instructions for different OS's and further help.
Create a FlowgraphLaunch GNU Radio from the Applications view:
or from the command line:
~$ gnuradio-companion &
Which will launch into a new blank flowgraph since this it the first time it is being launch (after that, it opens to whatever flowgraph was open when GNU Radio was closed).
GNU Radio works with a graphical syntax where the main premise is to plop in the function blocks you need, configure them as seen fit, then connect them together in the proper sequence such that the signal flows from the left side of the screen to the right side being manipulated per the target application.
Personally I think starting of the receive side is a bit better for beginners to understand the signal chain of how to manipulate an RF signal into digital data. So I’ll be recreating a simple little FM receiver that demodulates a 2FSK signal into digital bits and outputting the resulting signal via my PC’s speakers.
The RF signal is taken in at the UHF frequency of 405MHz (which is the operating frequency the antenna I’m using is tuned to) and down-converted to the audio range of 0Hz - 20kHz then ultimately sampled at a rate of 96kHz (because the type sampling rate of audio output devices is 48kHz and the Nyquist of that is 48kHz*2 = 96kHz).
The same way you’d typically start with any program you’re coding, you’ll declare the variables you’ll be using throughout the program. There are variable blocks that allow you to set names with assigned values. These are super handy for any variable that will be used by most every other block in the flowgraph and could potentially need to be changed. The best example of this is the center frequency that the SDR is operating at and sample rates.
There are two variable blocks we’ll be adding to this flowgraph for the center frequency and base sample rate before decimation (down conversion).
New blank flowgraphs are populated with one variable block already for the sample rate, so set the sample rate (named samp_rate) variable to 5MHz. Since this flowgraph is ultimately going to be converted to a Python script on the backend, the full number needs to be passed as the variable. In this case, the value needs to be 5000000 for 5MHz. If you set the value as 5M or 5MHz then it'll throw an error when you attempt to run the flowgraph.
Set the center frequency to the frequency the antenna you’re using is tuned to. The antenna I’m using is a UHF omnidirectional antenna tuned to 405MHz by adding another variable block with the ID center_freq set to 405000000.
Next, add the block that will actually be controlling the B205mini. Since the B205mini is being told to listen on its receive port and feed back the signal to the flowgraph, it is referred to as a source in the flowgraph. So add a USRP Source block from the UHD library, UHD > UHD: USRP Source.
Leave all of the default settings in the first two tabs of the USRP Source block, then in the third tab (RF Options) set the Ch0: Center Freq (Hz) variable to center_freq.
Add QT GUI Sink (Instrumentation > QT > QT GUI Sink) to display the raw input signal in graphical form to the flowgraph. Connect the output from the USRP source to the input of the GUI sink by clicking once on the two ports you want connected (don't click and hold/drag).
The raw signal from the B205mini needs to be low pass filtered to remove any frequencies outside of the audio range we are interested in listening to. Add a Low Pass Filter (LPF) block to the flowgraph. Set the cutoff frequency to 150kHz and a transition band of the filter from the passband to the stop band of 10kHz (Filters > Low Pass Filter).
These settings translate to the real world that I don't want any audio frequency being emitted at full strength from my PC's speakers above 150kHz, and the filter has 10kHz of range to go from not attenuating the signal at all to completely suppressing the signals above my 150kHz cutoff.
After filtering out the undesired signals from the input, we'll pass it through an block to demodulate broadcast FM signals, which is the WBFM Receive block (Modulators > WBFM Receive). The quadrature rate is the decimated sample rate of the input signal which is 5MHz/20 = 250kHz. We don't want to decimate the signal any further here, so set Audio Decimation to 1.
To achieve the Nyquist sampling rate of the audio signal to output to the PC speakers, the 250kHz signal needs to be converted to 96kHz. The best way to do a sample rate conversion is using a polyphase filter. In the GNU Radio library, the Rational Resampler block is a polyphase FIR filter (but you should note that it only works when the GNU Radio flowgraph is converted to Python on the backend).
Configure the Rational Resampler (Resamplers > Rational Resampler) block to be Float->Float for the Type. Set the Interpolation value to the desired output sample rate for the signal which is 96, and the Decimation value to the input sample rate of 250. Since both the input and output values are in the kHz range, I simply cancelled out the zeros because the settings of a polyphase filter is about the ratio between the input and output sample rates.
With the final sample rate set to the correct value, the signal can be fed into an audio sink block (Audio > Audio Sink) to route it to my PC‘s speakers. The audio sink also needs to be configured to the final sample rate of 96kHz, 96000.
Since we also want see the final processed output baseband signal compared to the raw input signal, add another QT GUI sink and configure it to have a 250MHz bandwidth so we can see everything in the baseband plus any stray signals that might appear (ie harmonics, spurs, etc.)
Connect the blocks in the flowgraph
Name the flowgraph in the Options block assigning it as ID and Title value.
Finally generate the backend Python script, which will prompt you to save the flowgraph. If the generate button is greyed out and you can’t click it, that means there is a syntax error somewhere in the flowgraph. You can click the red circle icon for a list of the detected syntax errors that need to be fixed.
Execute/run the flowgraph using the green play button.
This will bring up the QT GUI sinks to display the signal being received by the B205mini.
One of the tricky issues with using the UHD drivers with GNU Radio is making sure that the version of the FPGA bitstream images being uploaded to the USRP boards matches the version of UHD drivers in GNU Radio.
Since I installed GNU Radio the easy way using the apt package manager instead of installing from source, I’m at the mercy of whatever version of the UHD drivers are in the master branch of the repository of GNU Radio. Which happened to be a couple of versions behind the UHD host drivers I installed on my machine.
Luckily it’s pretty easy to swap the FPGA bitstream images with whichever version is needed from the Ettus UHD image files server. Simply download the version that you need, unzip the package, and swap out the images directory located in /usr/share/uhd
The drivers installed by default in GNU Radio on Ubuntu using the package manager apt is 003.010.003.000, while the version installed in the UHD host drivers is 3.15.0.0-1-1ubuntu1~bionic1. So after downloading the 003.010.003.000 version from Ettus, I just swap between each keeping the one not in use in the Downloads directory:
~$ sudo mv -R /usr/share/uhd/images ./Downloads
~$ sudo mv -R ./Downloads/uhd-images_003.010.003.000-release/share/uhd/images /usr/share/uhd
Don’t delete the version installed in the UHD host driver because the example scripts like the Python FFT we ran earlier won’t work with the image version for GNU Radio. Again, this could be avoided by installing GNU Radio from source to control the version better but swapping out the images directory is easy enough that I feel like it saves more time compared to the time to install GNU Radio from source (yes, I’m being lazy about this…).
Comments