Lab Objectives
  • Successfully connect to the RemoteRF platform and make a reservation for a Pluto SDR.
  • Write a Python script which configures a Pluto SDR and sets its key system parameters.
  • Generate a complex exponential transmit signal at a desired frequency.
  • Transmit the generated complex exponential from the Pluto SDR.
  • Fetch receive samples from the Pluto SDR in Python (a near-perfect copy of your transmit signal).
  • Plot the FFT of the received samples and observe carrier frequency offset (CFO).
  • Estimate the frequency of the received complex exponential signal.


Part I: Getting Things Set Up

RemoteRF is a platform that allows you to remotely interface with software-defined radios (SDRs) through the UCLA network. Put simply, a server is running in my lab that has physically connected to it multiple SDRs, each of which you may remotely access via Python through a simple API. To begin using one of these SDRs connected to RemoteRF, you must download a package via pip and then create an account through a terminal interface. After making an account, you can make a reservation for a particular SDR, allowing you (and only you) to access that SDR during your reservation period. Upon making a reservation, a token will be issued to you, which can then be inserted into your Python code, allowing you to remotely access the SDR as if it were physically connected to your local machine. Behind the scenes, all commands and data will be transferred between the you and the SDR over the UCLA network via the RemoteRF platform. Let’s get things set up so that you may begin using the RemoteRF platform. Begin by following through the tutorial on this page.

Part II: Frequency and Gain Estimation

Following Part I, you should have a script that transmits and receives a complex exponential from one SDR to itself. When crafting this complex exponential in complex baseband (in Python), we can specify its exact frequency of 100 kHz, in this case. Recall, this complex baseband signal undergoes upconversion at the transmitter and then downconversion at the receiver. In setting the Pluto SDR transmitter to a desired carrier frequency via sdr.tx_lo = int(tx_carrier_freq_Hz), the Pluto cannot perfectly realize exactly the desired carrier frequency. Rather, there exists some carrier frequency offset (CFO) in the carrier generated by the Pluto’s transmitter. This CFO is usually small enough such that the upconverted transmit signal is near the desired carrier frequency. However, since the receiver of the Pluto similarly exhibits some CFO itself, the downconverted received signal exhibits some lingering frequency offset. When an engineer refers to CFO in the context of communications, they almost always are referring to the frequence difference between the carrier generated by the transmitter and that by the receiver, since it is this difference that can be observed at complex baseband.

In the context of this lab, CFO leads to a received complex exponential that is not at exactly the desired frequency of 100 kHz. If you zoom in on the plot of the FFT from Part I, you will see the peak is not centered at exactly 100 kHz. Use zero-padding when taking the FFT to interpolate and identify the location of the peak. You may need to oversample by a factor of 4 or more. Where is it centered? Write some code to automatically find the location of the peak and let that be your estimate of the frequency of the received complex exponential, which we can refer to as .

Now, repeat this when transmitting from one SDR and receiving with another SDR. (Note that, to do this, you will need two separate reservations—one for each SDR.) In this case, the CFO will be more pronounced, since the carriers used for upconversion and downconversion are generated on two different devices. Virtually all modern wireless communication systems must estimate and correct for CFO, since even a small degree of CFO can lead to poor performance. This is explored in more detail in courses such as ECE 230B Digital Communication Systems.