An annotated 5G SigMF recording

For quite some time I’ve been thinking about generating SigMF annotations in some of the Jupyter notebooks I have about signal analysis, such as those for LTE and 5G NR. The idea is that the information about the frequencies and timestamps of the packets, as well as their type and other metadata, is already obtained in the notebook, so it is not too difficult to generate SigMF annotations with this information. The main intention is educational: the annotated SigMF file provides a visual guide that helps to understand the signal structure, and it also serves as a summary of what kind of signal detection and analysis is done in the Jupyter notebook. The code also serves as an example of how to generate annotations.

Another benefit of this idea is that it serves as a good test case for applications that display SigMF annotations. It shows what kinds of limitations the current tools have, and can also motivate new features. I’ve been toying with this idea since a while ago, but never wrote a blog post about it before. A year ago I sent a pull request to Inspectrum to be able to display annotation comments as tooltips when the mouse hovers above the annotation. While doing some tests with one LTE recording I realized that a feature like this was necessary to display any kind of detailed information about a packet. Back then, Inspectrum was the only application that was reasonably good at displaying SigMF annotations in a waterfall. Later, IQEngine has appeared as another good tool to display SigMF annotations (and also add them manually).

I have now updated the Jupyter notebook that I used to process a 5G NR downlink recording made by Benjamin Menkuec. This is much better to show an example of what I have in mind compared to the LTE recordings I was playing with before. The recording is quite short (so it is small), and I already have code to detect all the “packets”, although I have not been able to identify what kind of signals some of them are.

ssdv-fec: an erasure FEC for SSDV implemented in Rust

Back in May I proposed an erasure FEC scheme for SSDV. The SSDV protocol is used in amateur radio to transmit JPEG files split in packets, in such a way that losing some packets only cases the loss of pieces of the image, instead of a completely corrupted file. My erasure FEC augments the usual SSDV packets with additional FEC packets. Any set of \(k\) received packets is sufficient to recover the full image, where \(k\) is the number of packets in the original image. An almost limitless amount of distinct FEC packets can be generated on the fly as required.

I have now written a Rust implementation of this erasure FEC scheme, which I have called ssdv-fec. This implementation has small microcontrollers in mind. It is no_std (it doesn’t use the Rust standard library nor libc), does not perform any dynamic memory allocations, and works in-place as much as possible to reduce the memory footprint. As an example use case of this implementation, it is bundled as a static library with a C-like API for ARM Cortex-M4 microcontrollers. This might be used in the AMSAT-DL ERMINAZ PocketQube mission, and it is suitable for other small satellites. There is also a simple CLI application to perform encoding and decoding on a PC.

BSRC REU GNU Radio tutorial recordings

Since 2021 I have been collaborating with the Berkeley SETI Research Center Breakthrough Listen Summer Undergraduate Research Experience program by giving some GNU Radio tutorials. This year, the tutorials have been recorded and they are now available in the BSRC Tech YouTube channel (actually they have been there since the end of August, but I only realized just now).

These tutorials are intended as an introduction to GNU Radio and SDR in general, focusing on topics and techniques that are related or applicable to SETI and radio astronomy. They don’t assume much previous background, so they can also be useful for GNU Radio beginners outside of SETI. Although each tutorial builds up on concepts introduced in previous tutorials, their topics are reasonably independent, so if you have some background in SDR you can watch them in any order.

All the GNU Radio flowgraphs and other materials that I used are available in the daniestevez/reu-2023 Github repository. Below is a short summary of each of the tutorials.

Demodulation of the 5G NR downlink

At the end of July, Benjamin Menkuec was commenting in Twitter about some issues he had while demodulating a 5G NR downlink recording. There was a lively discussion in which other people and I participated. I had never touched 5G, but had done some work with LTE, so I decided to take the chance to learn more about the 5G physical layer. Compared to LTE, the changes are more evolutionary than revolutionary, but understanding what has changed, and how and why, is part of the puzzle.

I had to take an 11.5 hour flight in a few days, so I thought it would be a nice challenge to give this a shot, take with me the recordings that Benjamin was using and all the 3GPP documents, and write a demodulator in a Jupyter notebook from scratch during the flight, as I had done in the past with my LTE recordings. This turned out to be an enjoyable and interesting experience, quite different from working at home in shorter intervals scattered over multiple days or weeks, and with internet access. At the end of the flight I had a mostly working demodulation, but it had a few weird problems that turned out to be caused by some mistakes and misconceptions. I worked on cleaning this up and solving the problems over the next few days, and also now preparing this post.

Rather than trying to give an account of all my mistakes and dead ends (I spoke a little about these in Twitter), in this post I will show the final clean solution. There are some tricky new aspects in 5G NR (phase compensation, as we will see below) which can be quite confusing, so hopefully this post will do a good job at explaining them in a simple way.

The Jupyter notebook used in this post is here, and the recording in SigMF format can be found in this folder. Here I will only be using the first of Benjamin’s two recordings, since they are quite similar. It was done with an ADALM Pluto at 7.86 Msps and has a duration of 143 ms. The transmitter is an srsRAN 5 MHz cell. The recording was done off-the-air, or maybe with a cabled set up, but there are some other signals leaking in. The SNR is very good, so this is not a problem.

The first signal we find is at 9 ms. There is a transmission like this every 10 ms. As we will see, this is an SS/PBCH block. Something that stands out to those familiar with the LTE downlink spectrum is that the 5G NR spectrum is almost empty. In LTE, the cell-specific reference signals are transmitted all the time. In 5G this is not the case. Downlink signals are transmitted only when there is traffic. There is always a burst of one or several SS/PBCH blocks transmitted periodically (usually every 20 ms, but in this recording every 10 ms), as well as other signals that are always sent periodically (such as the SIB1 in the PDSCH), but this may be all if there is no traffic in the cell.

SS/PBCH block waterfall

ldpc-toolbox gets LDPC decoding

Recently I have implemented an FPGA LDPC decoder for a commercial project. The belief propagation LDPC decoder algorithm admits many different approximations in the arithmetic, and other tricks that can be used to trade off between decoding sensitivity (BER versus Eb/N0 performance) and computational complexity. To help me benchmark the different belief propagation algorithms, I have extended my ldpc-toolbox project to implement many different LDPC decoding algorithms and perform BER simulations.

ldpc-toolbox is a Rust library and command line tool for the design of LDPC codes. I initially created this project when I was trying to design a suitable LDPC code for a narrowband 32APSK modem to be used over the QO-100 amateur GEO transponder. The tool so far supported some classical pseudorandom constructions of LDPC codes, computed Tanner graph girths, and could construct the alists for all the DVB-S2 and CCSDS LDPC codes. Extending this tool to support LDPC encoding, decoding and BER simulation is a natural step.

An erasure FEC for SSDV

SSDV is an amateur radio protocol that is used to transmit images in packets, in a way that is tolerant to packet loss. It is based on JPEG, but unlike a regular JPEG file, where losing even a small part of the file has catastrophic results, in SSDV different blocks of the image are compressed independently. This means that packet loss affects only the corresponding blocks, and the image can still be decoded and displayed, albeit with some missing blocks.

SSDV was originally designed for transmission from high-altitude balloons (see this reference for more information), but it has also been used for some satellite missions, including Longjiang-2, a Chinese lunar orbiting satellite.

Even though SSDV is tolerant to packet loss, to obtain the full image it is necessary to receive all the packets that form the image. If some packets are lost, then it is necessary to retransmit them. Here I present an erasure FEC scheme that is backwards-compatible with SSDV, in the sense that the first packets transmitted by this scheme are identical to the usual \(k\) packets of standard SSDV, and augments the transmission with FEC packets in such a way that the complete image can be recovered from any set of \(k\) packets (so there is no encoding overhead). The FEC packets work as a fountain code, since it is possible to generate up to \(2^{16}\) packets, which is a limit unlikely to be reached in practice.

Monitoring the QO-100 WB transponder usage with Maia SDR

I am interested in monitoring the usage of the QO-100 WB transponder over several weeks or months, to obtain statistics about how full the transponder is, what bandwidths are used, which channels are occupied more often, etc., as well as statistics about the power of the signals and the DVB-S2 beacon. For this, we need to compute and record to disk waterfall data for later analysis. Maia SDR is ideal for this task, because it is easy to write a Python script that configures the spectrometer to a low rate, connects to the WebSocket to fetch spectrometer data, performs some integrations to lower the rate even more, and records data to disk.

For this project I’ve settled on using a sample rate of 20 Msps, which covers the whole transponder plus a few MHz of receiver noise floor on each side (this will be used to calibrate the receiver gain) and gives a frequency resolution of 4.9 kHz with Maia SDR’s 4096-point FFT. At this sample rate, I can set the Maia SDR spectrometer to 5 Hz and then perform 50 integrations in the Python script to obtain one spectrum average every 10 seconds.

Part of the interest of setting up this project is that the Python script can serve as an example of how to interface Maia SDR with other applications and scripts. In this post I will show how the system works and an initial evaluation of the data that I have recorder over a week. More detailed analysis of the data will come in future posts.

Maia SDR

I’m happy to announce the release of Maia SDR, an open-source FPGA-based SDR project focusing on the ADALM Pluto. The first release provides a firmware image for the Pluto with the following functionality:

  • Web-based interface that can be accessed from a smartphone, PC or other device.
  • Real-time waterfall display supporting up to 61.44 Msps (limit given by the AD936x RFIC of the Pluto).
  • IQ recording in SigMF format, at up to 61.44 Msps and with a 400 MiB maximum data size (limit given by the Pluto RAM size). Recordings can be downloaded to a smartphone or other device.

Decoding the BlueWalker 3 S-band downlink

BlueWalker 3 is a satellite built by AST SpaceMobile that was launched in 2022-09-11. It is as a prototype mission that will try to communicate from low Earth orbit with unmodified cellphones on ground using a large 64 m² unfoldable phased array antenna. It has received some criticism because of concerns of the satellite being too bright due to the large antenna (impacting astronomy observations) and potentially causing RF interference to radioastronomy and other services, since the cellular bands it will use are normally used only in terrestrial applications.

It also received criticism when shortly after launch, amateur radio operators noticed that the satellite was transmitting packets on 437.500 MHz, in the UHF amateur satellite band. The mission of this satellite is not compatible with the amateur radio service and it hasn’t received IARU coordination. There were some arguments on Twitter about whether BlueWalker 3 actually had the proper experimental license from the FCC to do this or not, and people posted ITU SNL filings and FCC applications. I didn’t track all of this in detail, so I don’t have a well informed opinion about whether BlueWalker 3 is following the regulations correctly.

A month ago, I looked at the UHF packets and checked that BlueWalker 3 used exactly the same modulation and coding as Light-1, which is a 3U cubesat from United Arab Emirates (this was first discovered by Tetsurou Satou JA0CAW). The framing contains the typical elements of the built-in packet handler of low cost FSK chips such as the Texas Instruments CC11xx family. Scott Tilley noticed some details that seem to explain this connection: Light-1 was built by NanoAvionics, which apparently has collaborated with AST SpaceMobile in the BlueWalker 3 mission. Therefore, it seems that the satellite bus used by BlueWalker 3 is that of a typical cubesat.

BlueWalker 3 also transmits in S-band, at a frequency of 2245 MHz. Scott Tilley has been doing some observations of this signal and sharing some recordings. Aang254 has been analysing the signal and remarks that it’s mostly idle data. In this post I’ll do an analysis of the BlueWalker 3 S-band signal using two recordings made by Scott.

Blockstream Satellite: decoding Bitcoin transactions

In my previous post I wrote about the protocols used by Blockstream Satellite. This was motivated by a challenge in GRCon22’s CTF. In that challenge, muad’dib sent the flag as a Blockstream API message and recorded the Blockstream Satellite DVB-S2 downlink as the message was broadcast. The recording was used as the IQ file for the challenge.

In my post, I gave a look at how all the protocol stack for the Blockstream API works: DVB-S2, MPE, IPv4, UDP, plus a custom protocol that supports fragmentation and application-level FEC. However, I didn’t give any details about how the protocols used to broadcast the Bitcoin blockchain work. This runs on another UDP port, independently of the Blockstream API. At that time I didn’t understand much about it, even though during the CTF I was trying to search for the flag in a Bitcoin transaction and looking at the source code of bitcoinsatellite to try to figure out how it worked.

After my previous post, Igor Freire commented some details of the FEC used in bitcoinsatellite. This is quite interesting by itself. Two FEC libraries by Chris Taylor are used: the Wirehair O(N) fountain code for larger blocks, and the CM256 MDS code based on Cauchy matrices over GF(256) (this is very similar to Reed-Solomon used as erasure coding). This motivated me to continue studying how all this works.

Now I have been able decode the Bitcoin transactions in the CTF recording. These don’t use any FEC, since transactions are small. I believe that there aren’t any blocks fully contained in the 35 second recording, so to see how the FEC codes work (which could be quite interesting) I would need a longer recording.

In this post I’ll show how to decode the Bitcoin transaction in Blockstream Satellite. The materials can be found in this repository.