A modern implementation of the Parks-McClellan FIR design algorithm

The Parks-McClellan FIR filter design algorithm is used to design optimal FIR filters according to a minimax criterion: it tries to find the FIR filter with a given number of coefficients whose frequency response minimizes the maximum weighted error with respect to a desired response over a finite set of closed sub-intervals of the frequency domain. It is based on the Remez exchange algorithm, which is an algorithm to find uniform approximations by polynomials using the equioscillation theorem. In signal processing, the Parks-McClellan algorithm is often call Remez. This algorithm is a very popular FIR design algorithm. Compared to the windowing method, which is another commonly used algorithm, it is able to obtain better filters (for instance, meeting design constraints with less coefficients), in part because it allows the designer to control the passband ripple and stopband attenuation independently by means of the weight function.

I have been laying some groundwork for Maia SDR, and for this I will need to run the Parks-McClellan algorithm in maia-httpd, the piece of software that runs in the Pluto ARM CPU. To evaluate what implementation of this algorithm to use, I have first gone to the implementations that I normally use: the SciPy remez function, and GNU Radio’s pm_remez function. I read these implementations, but I didn’t like them much.

The SciPy implementation is a direct C translation of the original Fortran implementation by McClellan, Parks and Rabiner from 1973. This C translation was probably written decades ago and never updated. The code is very hard to read. The GNU Radio implementation looks somewhat better. It is a C implementation that was extracted from Octave and dates from the 90s. The code is much easier to follow, but there are some comments saying “There appear to be some problems with the routine search. See comments therein [search for PAK:]. I haven’t looked closely at the rest of the code—it may also have some problems.” that have seemingly been left unattended.

Because of this and since I want to keep all the Maia SDR software under permissive open source licenses (the GNU Radio / Octave implementation is GPL), I decided to write from scratch an implementation of the Parks-McClellan algorithm in Rust. The result of this has been the pm-remez crate, which I have released recently. It uses modern coding style and is inspired by recent papers about how to improve the numerical robustness of the Parks-McClellan algorithm. Since I figured that this implementation would also be useful outside of Maia SDR, I have written Python bindings and published a pm-remez Python package. This has a few neat features that SciPy’s remez function doesn’t have. The Python documentation gives a walkthrough of these by showing how to design several types of filters that are commonly used. This documentation is the best place to see what pm-remez is capable of.

The rest of this post has some comments about the implementation and the things I’ve learned while working on this.

LTE Transmission Mode 4 (closed-loop spatial multiplexing)

This is a long overdue post. In 2022, I wrote a series of posts about LTE as I studied its physical layer to understand it better. In the last post, I decoded the PDCCH (physical downlink control channel), which contains control information about each PDSCH (physical downlink shared channel) transmission. I found that, in the recording that I was using, some PDSCH transmissions used Transmission Mode 4 (TM4), which stands for closed-loop spatial multiplexing. For an eNB with two antenna ports (which is what I recorded), this transmission mode sends either one or two codewords simultaneously over the two ports by using a precoding matrix that is chosen from a list that contains a few options. The choice is done by means of channel-state information from the UE (hence the “closed-loop” in the name).

In the post I found a transmission where only one codeword was transmitted. It used the precoding matrix \([1, i]^T/\sqrt{2}\). This basically means that a 90º phase offset is applied to the two antenna ports as they simultaneously transmit the same data. I mentioned that this was the reason why I obtained bad results when I tried to equalize this PDSCH transmission using transmit diversity in another previous post, and that in a future post I would show how to equalize this transmission correctly. I have realized that I never wrote this post, so now it is as good a time as any.

5G NR downlink reference signals

Last summer I looked at the demodulation of the 5G NR downlink, using a short recording of an idle srsRAN gNB made by Benjamin Menkuec. In that post I looked at the phase compensation, which is new in NR compared to LTE, the SS/PBCH block, and performed OFDM demodulation of all the signals in the recording. One of these signals was the PDSCH transmitting the SIB1 (which is done periodically even on an idle cell), and its corresponding PDCCH transmission. However, there were some reference signals that I wasn’t able to identify at the time. In this post I will look at these reference signals in detail, and also to the DM-RS (demodulation reference signal) in the PDCCH and PDSCH.

Published
Categorised as Software Tagged

Decoding MOVE-II

MOVE-II is a cubesat from Technical University of Munich that was launched in December 2018. It transmits telemetry in the 145 MHz amateur satellite band using a protocol that uses CCSDS LDPC codewords. Back in the day, there was a GNU Radio out-of-tree module developed by the satellite team to decode this satellite. Given the additional effort required to support LDPC decoding for just this satellite and since there was already a GNU Radio decoder available, I never added a decoder for MOVE-II to gr-satellites.

Fast forward 5 years, and MOVE-II is still active, but apparently its GNU Radio out-of-tree module has bit rotten. The Gitlab repository where this was hosted (I believe it was a self-hosted Gitlab) has disappeared, and while it was originally developed for GNU Radio 3.7, it was never ported to newer GNU Radio versions. Some days ago, some amateurs including Scott Chapman K4KDR and Bob Mattaliano N6RFM started doing some experiments to try to get a decoder for MOVE-II working.

Seeing this, I decided to revisit the situation and try to add a decoder for MOVE-II to gr-satellites. Since this satellite was launched, I have been dealing with CCSDS LDPC for the Artemis Orion, made my own LDPC decoder, and participated in fixing the GNU Radio in-tree LDPC decoder. Therefore, most of the heavy lifting seemed to be already done.

I have now added an example decoder flowgraph for MOVE-II to gr-satellites. Here I describe the details of this example, and why it is only an example instead of a fully supported decoder as the ones that exist for other satellites.

Receiving HADES-D

HADES-D is the 9th PocketQube developed by AMSAT-EA. It is the first one that hasn’t failed early in the mission. Among the previous AMSAT-EA satellites, GENESIS-L and -N suffered the launch failure of the Firefly-Alpha maiden flight, EASAT-2 and HADES presumably failed to deploy their antennas, GENESIS-G and -J flew on the second Firefly-Alpha flight, which only achieved a short-lived orbit, with all the satellites reentering in about a week, URESAT-1 had the same kind of antenna deployment problem, and GENESIS-A is a short duration payload scheduled to fly in the Ariane-6 maiden flight, which hasn’t happened yet.

HADES-D launched with the SpaceX Transporter 9 rideshare on November 11. This PocketQube was carried in the ION SCV-013 vehicle, and was released on November 28. The antennas have been deployed correctly, unlike in its predecessors, the satellite is in good health, and several amateur stations have been able to receive it successfully, so congratulations to AMSAT-EA.

Since HADES-D is the first PocketQube from AMSAT-EA that is working well, I was curious to measure the signal strength of this satellite. Back around 2016 I was quite involved in the early steps of AMSAT-EA towards their current line of satellites. We did some trade-offs between PocketQube and cubesat sizes and calculated power budgets and link budgets. Félix Páez EA4GQS and I wanted to build an FM repeater amateur satellite, because that suited best the kind of portable satellite operations with a handheld yagi that we used to do back then. Using a PocketQube for this always seemed a bit of a stretch, since the power available wasn’t ample. In fact, around the time that PocketQubes were starting to appear, some people were asking if this platform could ever be useful for any practical application.

Fast forward to the end of 2023 and we have HADES-D in orbit, with a functioning FM repeater. My main interest in this satellite is to gather more information about these questions. I should say that I was only really active in AMSAT-EA’s projects during 2016. Since then, I have lost most of my involvement, only receiving some occasional informal updates about their work.

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.