On matched filtering in the presence of carrier frequency offset

If \(\{x_k\}_{k=0}^{N-1}\) is a complex waveform and this waveform is received in AWGN, that is, the sequence \(y_k = A x_k + n_k\) is received, where \(A\) is an unknown complex amplitude and \(n_k\) are independent circularly symmetric normal random variables with standard deviation one, it is well known that the linear filter \(\{a_k\}_{k=0}^{N-1}\) that maximizes the detection SNR of \(T = \sum_{k=0}^{N-1} a_k y_k\), which is defined as \(|\mathbb{E}[T]|^2/V(T)\), is given by the matched filter \(a_k = \overline{x_k}\).

A natural question is what happens if the waveform is received with an unknown carrier frequency offset \(f\). That is, if \(y_k = A e^{2\pi i f k} x_k + n_k\). The typical solution is to use a bank of matched filters which are spaced by \(\Delta\) in the frequency domain and cover the expected carrier frequency offset range. This means that we use filters \(a_{k,m} = e^{-2\pi i \Delta m k} \overline{x_k}\), where the integers \(m\) are such that the grid of frequencies \(\Delta m\) covers the required frequency range. Here the hope is that if \(\Delta\) is small enough, then choosing the integer \(m\) such that \(\Delta m\) is closest to \(f\), we have that\[T = \sum_{k=0}^{N-1} e^{-2\pi i \Delta m k} \overline{x_k}y_k = A \sum_{k=0}^{N-1} e^{2 \pi i (f-\Delta m) k} |x_k|^2 + \sum_{k=0}^{N-1} e^{-2 \pi i \Delta m k} \overline{x_k} n_k.\]If \(\Delta m-f\) is small, this expression will have an SNR similar to the SNR for \(f = 0\).

However it is possible to do better. We can modify the matched filter to improve the SNR when there is frequency error. Since we choose the filter \(m\) from the bank such that \(\Delta m\) is closest to \(f\), we can assume that \(|f| \leq \Delta / 2\) and that we choose bank \(m = 0\). Now we can pose an optimization problem that involves the frequency error \(f\). Different kinds of optimization problems will lead to different solutions. A natural quantity to maximize is the average SNR with respect to \(f\), assuming that \(f\) is uniformly distributed in \([-\frac{\Delta}{2},\frac{\Delta}{2}]\). This is\[\frac{1}{\Delta}\int_{-\frac{\Delta}{2}}^{\frac{\Delta}{2}} \frac{|\mathbb{E}[T]|^2}{V(T)}\, df.\]Let us solve the optimization problem.

Similarly to the case of the matched filter with no frequency error, we have\[\mathbb{E}[T] = A \sum_{k=0}^{N-1} e^{2 \pi i f k} a_k x_k,\]so\[V(T) = \mathbb{E}[|T-\mathbb{E}[T]|^2] = \mathbb{E}\left[\left|\sum_{k=0}^{N-1} a_k n_k\right|^2\right] = \sum_{k = 0}^{N-1} |a_k|^2.\]Therefore, the optimization problem is equivalent to finding a vector \(\{a_k\}_{k=0}^{N-1}\) with unit norm (\(\sum_{k=0}^{N-1} |a_k|^2 = 1\)) that maximizes the expression\[\frac{1}{\Delta}\int_{-\frac{\Delta}{2}}^{\frac{\Delta}{2}}\left|\sum_{k=0}^{N-1} e^{2\pi i f k} a_k x_k\right|^2\, df.\]This expression can be rewritten as\[\frac{1}{\Delta}\sum_{k=0}^{N-1}\sum_{l=0}^{N-1}\overline{a_l x_l}a_k x_k \int_{-\frac{\Delta}{2}}^{\frac{\Delta}{2}} e^{2\pi i f (k-l)}\, df = \sum_{k=0}^{N-1}\sum_{l=0}^{N-1}\overline{a_l x_l}a_k x_k \operatorname{sinc} (\Delta (k-l)),\]where \(\operatorname{sinc}(x) = \sin(\pi x)/(\pi x)\).

Write \(x_k = e^{i\theta_k}|x_k|\) and denote by \(G\) the matrix with entries \(G_{kl} = |x_k||x_l|\operatorname{sinc} (\Delta (k-l))\). This matrix is the Gram matrix of the vectors \(\varphi_k(f) = e^{2 \pi i f k}|x_k|\) in \(L^2[-\frac{\Delta}{2}, \frac{\Delta}{2}]\) (with the Lebesgue measure multiplied by the normalization factor \(\frac{1}{\Delta}\)), so it is positive semidefinite (and it is positive definite if \(\Delta > 0\) and \(x_k \neq 0\) for all \(k = 0, \ldots, N-1\)). Let \(u = \{u_k\}_{k=0}^{N-1}\) be any unit norm eigenvector corresponding to the largest eigenvalue of \(G\). The solution to the optimization problem is then given by \(a_k = e^{-i\theta_k} u_k\).

The case in which \(|x_k| = 1\) for all \(k = 0, \ldots, N-1\) is particularly important, because it corresponds to constant-envelope modulations, and it is also easier to treat than the general case. This case includes the case of detecting a CW carrier, which corresponds to \(x_k = 1\) for all \(k\). In this case, the Gram matrix \(G\) is simply a matrix of sinc functions \(G_{kl} = \operatorname{sinc} (\Delta (k-l))\). This matrix has been studied by Slepian in 1978, because it appears in the spectral concentration problem, which is equivalent to the optimization problem I’m presenting here. In the spectral concentration problem we consider a unit norm sequence \(\{a_k\}_{k=0}^{N-1}\) and its Fourier transform\[U(f) = \sum_{k=0}^{N-1} e^{-2\pi i f k}a_k.\]The energy that \(\{a_k\}\) has in the frequency band \([-\frac{\Delta}{2}, \frac{\Delta}{2}]\) is\[\int_{-\frac{\Delta}{2}}^{\frac{\Delta}{2}} |U(f)|^2\,df.\]The problem asks which unit norm sequences \(\{a_k\}\) maximize the energy in this frequency band. It is clear that this is equivalent to a particular case of the optimization problem that we are considering (the case \(x_k = 1\) for all \(k\)).

The eigenvectors of the matrix \(G\) given by \(G_{kl} = \operatorname{sinc} (\Delta (k-l))\) can be computed numerically, but the problem is ill-conditioned for large \(N\), because many eigenvalues cluster around the largest eigenvalue. There is a trick to compute the eigenvectors without running into issues. In our case, we can use that trick to compute the eigenvector corresponding to the largest eigenvalue. The trick starts by noticing that the tridiagonal symmetric matrix \(R\) defined by\[\begin{split}R_{k,k} &= \cos(\pi\Delta) \left(k-\frac{N-1}{2}\right)^2,\ k = 0,\ldots, N-1\\R_{k,k+1} = R_{k+1,k} &= \frac{1}{2}(k+1)(N-1-k),\qquad k = 0,\ldots,N-2\end{split}\]commutes with \(G\) (this is shown by some straightforward calculations). This implies that the eigenspaces of \(G\) and \(R\) are the same. All the eigenvalues of a tridiagonal matrix with non-zero entries in its upper diagonal are simple. This is because the first component of an eigenvector for a given eigenvalue determines the remaining components (this is a very simple calculation). Moreover, it is also possible to prove that if \(v_0, v_1, \ldots, v_{N-1}\) are the eigenvectors of \(R\) with corresponding eigenvalues \(\lambda_0 > \lambda_1 > \cdots > \lambda_{N-1}\), then \(v_0, v_1, \ldots, v_{N-1}\) (which must be eigenvectors of \(G\)) have eigenvalues \(\mu_0 > \mu_1 > \cdots > \mu_{N-1}\) as eigenvectors of \(G\). However I haven’t been able to find a reference that proves this in a straightforward way, though presumably this follows from all the calculations in Slepian’s paper. This means that the eigenvector \(u\) that we need can be computed as \(v_0\), the eigenvector corresponding to the largest eigenvalue \(\lambda_0\) of \(R\).

There are efficient algorithms to compute eigenvalues and eigenvectors for tridiagonal symmetric matrices. For instance, SciPy has an eigh_tridiagonal function. Additionally it is possible to use these algorithms to compute only a selection of some of the eigenvalues and eigenvectors. This is precisely what we need, because in our case we only want the eigenvector \(v_0\) corresponding to the largest eigenvalue \(\lambda_0\) of \(R\).

The eigenvectors \(v_0, v_1, \ldots, v_{N-1}\) are called discrete prolate spheroidal sequences (DPSS) and they also play a role in other similar spectral concentration problems and in multitaper spectral analysis. They can be calculated with the dpss window function in SciPy. The first DPSS, also known as Slepian window, and \(v_0\) in our eigenvector notation, is the vector that solves our optimization problem in the constant-envelope case. That is, when \(|x_k| = 1\) for all \(k = 0, \ldots, N-1\). The takeaway of this post is:

For a constant-envelope waveform, average SNR performance in the presence of carrier frequency offset improves if the matched filter is multiplied by a DPSS window.

In the general case in which the waveform is not constant-envelope, the trick of using a tridiagonal matrix does not work, and we can also have ill-conditioning when trying to compute the eigenvectors numerically (for instance by using the eigh SciPy function).

It is convenient to put the above theoretical results in perspective and show what they really imply for the usual practical applications. In most applications \(\Delta \lesssim 1/N\). For instance, when an FFT is used to detect a CW carrier, we have \(\Delta = 1/N\), because in this case \(\Delta\) is equal to the FFT bin spacing. Other matched filter applications that use an FFT similarly set \(\Delta\) in relation to the FFT bin spacing.

The following plot shows, for a constant-envelope waveform of \(N\) samples, what is the average SNR loss when there is a carrier frequency offset \(f\) uniformly distributed on \([-\frac{\Delta}{2},\frac{\Delta}{2}]\), for both the matched filter (solid lines) and for a matched filter weighted with the DPSS window (dashed lines). The values of \(\Delta = 1/(4N)\), \(1/(2N)\), \(1/N\), \(2/N\), \(4/N\) are shown. We see that there is almost no dependence on \(N\), which is to be expected because this problem can be approximated well by an analogous continuous-time problem. We also see that for the smallest values of \(\Delta\) the loss of the matched filter is already quite small and the DPSS weighting gives almost no improvement.

Since the behaviour changes very little with \(N\), it is better to study what happens for a fixed \(N\) (here \(N = 8192\)), in terms of \(\Delta N\). This is what the plot below shows.

Another good takeaway from this plot is:

The average SNR loss of matched filtering with a frequency bin separation equal to the reciprocal of the filter length (for instance when using an FFT to detect a CW carrier) is around 1 dB, regardless of whether DPSS weighting is used.

The following figure shows the difference between the two traces in the figure above. This indicates how much improvement is obtained by applying DPSS weighting to the matched filter. For \(\Delta = 1/N\) the improvement is 0.05 dB, which explains why this is rarely done in practice. However for \(\Delta = 2/N\) the improvement is 0.36 dB, so DPSS weighting can be a useful technique if we need to implement a system that is in this situation for whatever reason. Note that interestingly the improvement decreases for \(\Delta > 2/N\).

Finally, the following plot shows the DPSS windows. As expected, when \(\Delta\) decreases they tend to a rectangular window, and as \(\Delta\) increases the window tapers off more.

These plots have been made in this Jupyter notebook.

Here I have treated the optimization of the average SNR assuming a uniform distribution of \(f \in [-\frac{\Delta}{2},\frac{\Delta}{2}]\). An equally interesting and useful optimization criterion is to maximize the worst-case SNR. That is, find the sequence \(\{a_k\}\) with unit norm that maximizes\[\min_{|f| \leq \frac{\Delta}{2}}\frac{|\mathbb{E}[T]|^2}{V(T)} = \min_{|f| \leq \frac{\Delta}{2}} \left|\sum_{k=0}^{N-1} e^{2\pi i f k} a_k x_k\right|^2.\]The techniques that are applicable in this problem are related to the Remez exchange used for optimal FIR design, but since the solution is quite involved, this might be a topic for another time.

PLL coefficients for rate-only feedback

A couple years ago I wrote a post about the paper Controlled-Root Formulation for Digital Phase-Locked Loops, by Stephens and Thomas. In this paper, the authors study digital PLLs by studying the transfer function in discrete time, rather than doing any continuous-time approximations or equivalences. They give values for the loop coefficients that are needed to achieve a certain noise bandwidth for some standard loop root placements (the supercritical damped response and the standard underdamped response). In general, the loop coefficients are obtained numerically. In my post, I show that in the case of a loop of order 2 with supercritical response the loop coefficients can be calculated explicitly in terms of the loop bandwidth by using the solution of a cubic equation. However, in that post, I treated only the phase/phase-rate feedback case. In this post I cover the rate-only feedback case.

Non-coherent m-FSK BER

Yesterday I posted about how to compute the well known formula for the bit error rate of FSK with non-coherent demodulation. Later I realized that the same kind of argument can be extended to cover the case of \(m\)-FSK in which the \(m\) tones are orthogonal. The formula for this is not so well known, and I don’t recall having seen it before, although surely it is somewhere in the literature. Here I show the calculations and the closed-form expression that is obtained.

Published
Categorised as Maths Tagged ,

About FLLs with band-edge filters

Using band-edge filters for carrier frequency recovery with an FLL is an interesting technique that has been studied by fred harris and others. Usually this technique is presented for root-raised cosine waveforms, and in this post I will limit myself to this case. The intuitive idea of a band-edge FLL is to use two filters to measure the power in the band edges of the signal (the portion of the spectrum where the RRC frequency response rolls off). If there is zero frequency error, the powers will be equal. If there is some frequency error, the signal will have more “mass” in one of the two filters, so the power difference can be used as an error discriminant to drive an FLL.

The band-edge FLL is presented briefly in Section 13.4.2 of fred harris’ Multirate Signal Processing for Communication Systems book. Additionally, fred also gave a talk at GRCon 2017 that was mainly focused on how band-edge filters can also be used for symbol timing recovery, but the talk also goes through the basics of using them for carrier frequency recovery. Some papers that are referenced in this talk are fred harris, Elettra Venosa, Xiaofei Chen, Chris Dick, Band Edge Filters Perform Non Data-Aided Carrier and Timing Synchronization of Software Defined Radio QAM Receivers and fred harris, Band Edge Filters: Characteristics and Performance in Carrier and Symbol Synchronization.

Recently I was looking into band-edge FLLs and noticed some problems with the implementation of the FLL Band-Edge block in GNU Radio. In this post I go through a self-contained analysis of some of the relevant math. The post is in part intended as background information for a pull request to get these problems fixed, but it can also be useful as a guideline for implementing a band-edge FLL outside of GNU Radio.

Computing PLL coefficients

Whenever I implement a PLL or a similar control loop, I invariably consult the formulas in the paper Controlled-Root Formulation for Digital Phase-Locked Loops, by Stephens and Thomas. Other sources that give formulas for the loop coefficients in terms of the loop bandwidth perform a continuous time analysis and then use a bilinear transform or a similar kind of transform to translate results between continuous time and discrete time. The appeal of the paper by Stephens and Thomas is that they work directly in discrete time, using a beautiful complex contour integral argument to calculate the loop bandwidth in terms of the loop coefficients for a loop of any order. Unfortunately, their method doesn’t give a closed-form formula for the loop coefficients in terms of the loop bandwidth. The loop coefficients can be obtained numerically, and the paper gives tables for common loop bandwidths and orders.

In most of my designs I use a second order loop with supercritical damping, which means that the two loop roots in the z-plane are equal (and hence real). As I was doing a design the other day, I wondered whether in this specific situation, which is much simpler than the general case, a closed-form solution could be obtained. It turns out that this is the case, so I’ll be using this formula from now on. In this short post I explain how this is done and give the formula.

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.

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.

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.