Plotting RF spectrum with the LinHT

RF spectrum is always a mesmerizing thing to stare at. Since the LinHT’s RF front-end is a full-blown SDR, and the display is so colorful, why not sprinkle it with a bit of DSP maths, generating a nice plot for us to enjoy?

Let’s start with the baseband. The source, SX1255, offers a baseband stream over I2S at selectable rate. Each I2S sample carries two 16-bit values (real and imaginary parts – we deal with complex numbers, disguised as left and right audio channels). At 500k samples per second, the RF span is 500k (this does not violate Nyquist rule – again, we are dealing with complex numbers). Pretty impressive for a simple handheld.

The baseband samples are collected by the System on Module’s (SoM) I2S receiver and handled by Alsa & friends. From there, they can be easily accessed (read) using the Audio Source GNU Radio block.

Samples are converted from 16-bit signed integers to floats internally. That’s one less thing to worry about. Using a Float to Complex block is very handy here. At this point, we need to normalize the frequency response of the signal (equalize the sinc characteristic of the RF front end’s ADC). To do that, it is enough to design a simple, inverse-sinc FIR filter with to get a maximally flat response as a result. This can be done using Matlab (generating the taps) or a simple GNU Radio python block using scipy’s window method (firwin2: reference).

When the frequency response is flat, it’s time to remove the DC residual with the Remove DC Spike block. I believe that these blocks (FIR and DC removal) can be swapped, so the order doesn’t really matter.

ZMQ PUB Sink is used for debug purposes – it allows us to peek at the baseband using a PC connected to LinHT.

Log Power FFT block is doing the DSP heavy lifting. Since the display’s width is 160 pixels, we set the FFT size to 256. Calculated FFT values are saved to a file (/tmp/fft) in a cyclic manner – overwriting the same 1024-byte chunk each time a new set of data is available. Unfortunately, the standard File Sink block can not be used for this purpose, and a custom-made python block is required.

Contents of the resulting file have to be read and displayed repeatedly. This sample C code does exactly that. 256 FFT values have to be mapped onto 160 pixels. Let’s use a simple rounding method without interpolation, as the device is not a lab-grade measurement instrument:

map_val[0] = val[0];
map_val[159] = val[255];
for(uint8_t i=1; i<RES_X-1; i++)
{
	map_val[i] = val[(uint8_t)roundf((i/159.0f)/(1.0f/255.0f))];
}

The SX1255 chip can be configured using sx1255-spi tool provided in the LinHT-utils repository. A sample command is as follows:

sx1255-spi -E -s 500 -r 433475000 -l 18 -p 18 -R 1 -P

Let’s analyze this command:
-E resets the device
-s sets the sample rate to 500kSa/s
-r sets the receiver’s frequency (units: Hz)
-l sets the LNA gain (dB)
-p sets the PGA gain (dB)
-R enables the receiver chain
-P displays PLL lock statuses

Now, the flowgraph can be “compiled” using built-in grcc tool and ran. Needless to say, the GUI C code has to be compiled and ran as well. Here’s a short video demonstrating LinHT’s RF plot capabilities, summarizing all the work described above:

The RF signal was an M17 text message sent with a modified Nokia 3310, close to the receiver. The peak decay is caused by the GR’s DC spike removal IIR filter block.

Happy hacking 🙂

Comments

One response to “Plotting RF spectrum with the LinHT”

  1. […] Plotting RF spectrum with the LinHT The display is so colorful, why not sprinkle it with a bit of DSP maths, generating a nice plot for us to enjoy? M17 Project […]

Leave a Reply

Your email address will not be published. Required fields are marked *