Article, Projects

A Deeper Look into the Ettus USRP B200

After writing a few posts using the Ettus USRP B200, I wanted to continue to go over some of the features and utility of this amazing SDR (Software Defined Radio). In this post, I’ll go over some of the hardware that is employed, the FPGA used, and some basic captures for quick spectrum views. Having a SDR and discovering the open source world/community is pretty amazing.

As of 2010, Ettus Research is apart of National Instruments, and is one of the largest players in the SDR world. The USRP (Universal Software Radio Peripheral) product line has been heavily embraced by the open source community. GNU Radio is one of the largest communities and has spawned tons of projects. Other projects, such as SrsLTE and OpenAirInterface, leverage USRP products that transform a SDR into a working LTE base station!

In addition to amazing hardware, Ettus products also offers the UHD (USRP hardware driver) which has a robust C++/Python library for flashing FPGA images, RX/TX control, and so much more. This driver platform, in combination with the opensource community, has made the deployment of USRP products/hardware very easy for newcomers. I also recommend taking a look at the RX and TX output performance measurements. We can see that the Ettus USRP B200 has a maximum output power of about +15dBm across the whole 6Ghz spectrum! (Not bad at all for this little fella.)

Ettus USRP B200
USRP B200 Board

The Ettus USRP B200 is from the BUS series of devices. The BUS in this family comes from the fact that these are connected to software via USB (Universal Serial BUS). The Ettus USRP B200 uses a USB Type B for B200 input and a USB Type A for the computer connection and requires USB 3.0 on the PC for high speed transfers. Other types of USRP devices connect via Gigabit Ethernet or PCI-E connectors. These devices, while more expensive, have much higher sampling rates and therefore much wider bandwidths and capabilities.

Ettus USRP B200
List of USRP Devices, Interfaces, and Sampling Rates
From: https://kb.ettus.com/About_USRP_Bandwidths_and_Sampling_Rates

The hardware used on the Ettus USRP B200 is quite impressive. We can see from the block outline below that there are two main chips deployed for this board. The main chip and the programming heart of the system is the Spartan6 XC6SLX75. The FPGA (field programmable gate array) does a large amount of processing from the RF transceiver.

On the other side, we have our RFIC (radio frequency interface controller) AD 9364. This is the chip on our board that allows for sampling and frequency ranges from 70MHz to 6GHz! You can see from the picture below how the FPGA influences the clock and CTRL (Controls) on the AD 9364. We can also see on the chart at the end there’s an RF Front-end Switch network which allows the board to have a TRX (TX1 & RX1) and a second RX2.

Ettus USRP B200
Ettus USRP B200
FPGA Specs for the XC6SLX75 (Bottom Row) deployed in the USRP B200.
From Xilinx: https://www.xilinx.com/support/documentation/data_sheets/ds160.pdf
Ettus USRP B200
Data Sheet with features of the AD9364 RF Transceiver
From: https://www.analog.com/media/en/technical-documentation/data-sheets/AD9364.pdf

And…we can see it all working together in another diagram from the Ettus site. (This time it’s going from right to left, so don’t be confused.)

Ettus USRP B200
High Level RF Block Diagram for the USRP 2920 https://kb.ettus.com/About_USRP_Bandwidths_and_Sampling_Rates

I do want to make a comment about the above diagram. It is NOT from, the B200, but does show the common RF blocked used inside Ettus products. There are also has some schematics posted online. Many of the designs are very similar to that of the B210. For the curious, follow the links!

A Little Coding

Now that we’ve gone through the nitty-gritty of what this device offers, let’s go through an easy sample of programming with the UHD library. In the next few lines, I’ll walk through a simple spectrum analyzer. We’ll pick a center frequency, a sampling rate (BW) and plot it out using matplotlib and Python. We’ll initially use the RxSampling code and tweak it a bit to get our desired outputs. Ready?

Below is the standard code that comes with the UHD driver build. We can see from the code that there’s a standard argparse where we pick out gain, rate, frequency, duration, and file destination.


#!/usr/bin/env python
#
# Copyright 2017-2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
RX samples to file using Python API
"""
import argparse
import numpy as np
import uhd
def parse_args():
    """Parse the command line arguments"""
    parser = argparse.ArgumentParser()
    parser.add_argument("-a", "--args", default="", type=str)
    parser.add_argument("-o", "--output-file", type=str, required=True)
    parser.add_argument("-f", "--freq", type=float, required=True)
    parser.add_argument("-r", "--rate", default=1e6, type=float)
    parser.add_argument("-d", "--duration", default=5.0, type=float)
    parser.add_argument("-c", "--channels", default=0, nargs="+", type=int)
    parser.add_argument("-g", "--gain", type=int, default=10)
    parser.add_argument("-n", "--numpy", default=False, action="store_true",
                        help="Save output file in NumPy format (default: No)")
    return parser.parse_args()
def main():
    """RX samples and write to file"""
    args = parse_args()
    usrp = uhd.usrp.MultiUSRP(args.args)
    num_samps = int(np.ceil(args.duration*args.rate))
    if not isinstance(args.channels, list):
        args.channels = [args.channels]
    samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)
    with open(args.output_file, 'wb') as out_file:
        if args.numpy:
            np.save(out_file, samps, allow_pickle=False, fix_imports=False)
        else:
            samps.tofile(out_file)
if __name__ == "__main__":
    main()

Lets run it!

$ ./rx_to_file.py -f 945000000 -r 1000000 -d 1 -o 945M1S.dat

And let’s open it up!

Ettus USRP B200
Binary Caputre from rx_to_file.py from UHD

I guess we got something…COOL! Let’s try to see if we can track down a real cell. I have a personal iPhone, and you can see your current serving cell by dialing a special code: *3001#12345. This will bring you the Field Test screen and from there you can go to serving cell info. You can see from the images below we have a serving cell that is 20MHz wide with a DownLink EARFCN of 2050 If we type that into Niviuk, we see that it’s centered at 2120MHz.

Let’s see if there’s truly a cell there. For this, I’ll run a GNU-Radio based program that’s a pretty nifty spectrum analyzer in a pinch. It’s UHD_FFT and it is some stock software that comes when you install GNU Radio.

$uhd_fft -f 2120000000 -s 30M

LTE FDD cell @ 2120Mhz w/ 20Mhz BW. Caputres from uhd_fft & GNU Radio.

Okay, great! We can see the same cell that our Phone/UE can see! Now, let’s edit that rx_to_file.py and this time, we’ll call it rx_to_fft.py. Our code is going to be VERY similar but instead of outputting to a file, we’re going to do the FFT conversion and plot it out. So, line 1-40 will remain the same and we’ll remove 39-43 and replace it with the following:


samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)
X = np.fft.fft(samps[0].tolist())
fft_freqs = np.fft.fftfreq(len(X),d = 1/args.rate)
plt.plot(fft_freqs, np.abs(X))
plt.show()

The first line we’ll keep the same. We need to pass this into the B200 to pull the sampling data from the device. It takes the number of samples, center frequency, rate/BW, and the channel if we want to specify RX1 or RX2 (and the gain if we need). The num_samps is the duration*rate.


samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)

Let’s put that samps variable into an array for processing. I noticed that running np.fft.fft(samps) would output an array of size =1. So, I found a work-around by taking the samps[0].tolist() as the pass instead. I’m not sure if this is the 100% correct way but hey, it worked for me.


X = np.fft.fft(samps[0].tolist())

Another helpful tool from numpy (np) is the fftfreq. This is going to be our X-Axis on our plot and it takes the length of our sample array and the time duration. We know that t = 1/f so we’ll pass in 1/(freq rate).


fft_freqs = np.fft.fftfreq(len(X),d = 1/args.rate)

The next step is to plot it! X-Axis is the first argument and we’ll graph the absolute value of our FFT samples.

    

plt.plot(fft_freqs, np.abs(X))
plt.show()
FFT transform of SDR capture with B200 at 2120Mhz w/ 30Mhz BW capture.

THERE SHE BLOWS! How cool is that?! I have no idea why there’s a spur at that exact location. I ran the script a few times and it seems to be always in that exact location. The code could probably use some normalizing and a few tweaks here and there. But for some quick dirty code this certainly gets the job done!

              |    |    |
             )_)  )_)  )_)
            )___))___))___)\
           )____)____)_____)\\
         _____|____|____|____\\\__
---------\                   /---------
  ^^^^^ ^^^^^^^^^^^^^^^^^^^^^
    ^^^^      ^^^^     ^^^    ^^
         ^^^^      ^^^

#!/usr/bin/env python
"""
RX samples to file using Python API
"""
import argparse
import numpy as np
import numpy.fft
import uhd
import matplotlib.pyplot as plt
from scipy import fftpack
def parse_args():
    """Parse the command line arguments"""
    parser = argparse.ArgumentParser()
    parser.add_argument("-a", "--args", default="", type=str)
    parser.add_argument("-o", "--output-file", type=str, required=False)
    parser.add_argument("-f", "--freq", default=1980e6, type=float, required=False)
    parser.add_argument("-r", "--rate", default=20e6, type=float)
    parser.add_argument("-d", "--duration", default=2.0, type=float)
    parser.add_argument("-c", "--channels", default=0, nargs="+", type=int)
    parser.add_argument("-g", "--gain", type=int, default=30)
    parser.add_argument("-n", "--numpy", default=False, action="store_true",
                        help="Save output file in NumPy format (default: No)")
    return parser.parse_args()
def main():
    """RX samples and write to matplotlib plot"""
    args = parse_args()
    usrp = uhd.usrp.MultiUSRP(args.args)
    num_samps = int(np.ceil(args.duration*args.rate))
    if not isinstance(args.channels, list):
        args.channels = [args.channels]
    samps = usrp.recv_num_samps(num_samps, args.freq, args.rate, args.channels, args.gain)
    X = np.fft.fft(samps[0].tolist())
    fft_freqs = np.fft.fftfreq(len(X),d = 1/args.rate)
    plt.plot(fft_freqs, np.abs(X))
    plt.show()
if __name__ == "__main__":
    main()

Conclusion

Python coding with the B200 and the UHD background seems really straightforward! I’m really impressed with how intuitive it is to push things out to the B200 and get your samples back for processing. I’ll do more projects like this in the future so stay tuned!

Thanks for reading,
Eric

Tagged , , , , , , ,

15 thoughts on “A Deeper Look into the Ettus USRP B200

  1. Is it possible to run an Ettus B200 on a Windows 10 machine using SDR#? Would I have to have two B200’s to listen in on public safety digital trunking? On the subject of public safety / digital modes. Does SDR# decode as many modes as the UNIDEN SDS 200?

    1. 1. Windows 10 is supported by SDR#, so that shouldn’t be an issue, and from what I can tell without installing sdrsharp and doing it myself there is Ettus UHD support. Therefore, I believe that the B200 would be able to run SDR#. The UHD driver is fairly common among SDR software, and it is almost universally supported. This was actually a big reason why I picked up an Ettus product over the bladeRF.

      2. I am unware if SDR# would be able to support 2 inputs. Theoretically it certainly can, but it is common with free software such as SDRsharp the libraries and features for SDR boards are never fully utilized. The B200 has a TX/RX1 path and RX2, but utilizing them together would be based on the SDR# platform leveraging the UHD library. (I would safely assume that only 1 SDR input would be decoded at one time.)

      3. As for digital modes, the B200 would certainly be able to decode everything but I can not answer as to the depth of support that SDR# has for specific protocols for public safety / digital modes. I think this question could be better asked on their website / boards.

      It sounds like you are in between Products, (ETTUS B200 or UNIDEN SDS 200). If you are a tinkerer then I would recommend the B200. If you are so inclined there are tons of ways to help with open source development if a specific feature you require is not supported. However, if you do not want to rely on opensource solutions to your problems, I could very easily recommend that you buy the UNIDEN SDS 200, because it will probably “Just work” as opposed to a more expensive product and a “maybe”…

      Hope it helps!
      -Eric

  2. Hi, Neat post. There is a problem along with your site in web explorer, could test this?
    IE nonetheless is the market chief and a large part of other people will pass over your wonderful writing due
    to this problem.

  3. Hello I am so delighted I found your blog, I really found
    you by error, while I was researching on Yahoo for something else, Regardless I am
    here now and would just like to say thank you for a fantastic post and a all round thrilling blog (I
    also love the theme/design), I don’t have time to browse it all at the moment but I have
    bookmarked it and also added in your RSS feeds, so when I have time I will be back to read a great deal more,
    Please do keep up the superb job.

  4. I’m now not sure where you’re getting your information, however good topic.

    I must spend a while studying much more or figuring
    out more. Thanks for great information I was looking for
    this info for my mission.

  5. Thank you for every other informative web site. Where else may
    just I get that type of information written in such an ideal method?

    I have a venture that I am simply now working on, and I’ve been at the glance out for such information.

  6. I’ve been surfing online more than 4 hours today, yet I never
    found any interesting article like yours. It’s pretty worth enough for me.
    In my opinion, if all site owners and bloggers made good content as you did, the
    net will be much more useful than ever before.

  7. It is appropriate time to make some plans for the long run and it’s time to be happy.
    I have read this post and if I could I desire to
    suggest you some interesting things or suggestions.
    Maybe you could write next articles regarding this article.
    I desire to read even more issues approximately it!

    1. Hey! Thank you so much for the feedback! You are totally right. I should have caught that from the 1Gb Eth interface link to the PC which is common for the “N” family of boards. The B200 uses a 3.0 USB link instead. I’ve updated the post, thank you for the feedback!

Comments are closed.