AGC for gr-satellites

In a previous post I discussed my BER simulations with the LilacSat-1 receiver in gr-satellites. I found out that the "Feed Forward AGC" block was not performing well and causing a considerable loss in performance. David Rowe remarked that an AGC should not be necessary in a PSK modem, since PSK is not sensitive to amplitude. While this is true, several of the GNU Radio blocks that I'm using in my BPSK receiver are indeed sensitive to amplitude, so an AGC must be used with them. Here I look at these blocks and I explain the new AGC that I'm now using in gr-satellites.

The basic BPSK receiver that I'm using in GNU Radio is show below. An FLL Band-Edge block is used first for coarse frequency correction, a low pass filter takes out some of the noise off the sides of the signal, the Polyphase Clock Sync performs clock recovery and RRC filtering, and the Costas loop acts as a PLL to lock to the phase of the carrier.

Coherent BPSK receiver

It turns out that all the three blocks in this chain (besides the low pass filter) have feedback loops with discriminators that assume a signal of amplitude 1. Let us analyse this in detail, starting by the Costas loop, which is probably the best known and simplest algorithm amongst the three used here.

Recall that a Costas loop works by using a phase detector to measure the phase of the signal and then using this measure as an error input in a feedback loop to try to drive the phase to zero. The phase detector of a BPSK Costas loop should be insensitive to phase changes of 180º, meaning that it should output zero both for a phase of 0º and a phase of 180º. Otherwise we just get a regular PLL, which is sensitive to phase changes. Mathematically, the optimal phase detector for a BPSK Costas loop is \arctan(Q/I). Note that this is just the phase of the point z = I + iQ when z is in the first or fourth quadrant and the phase of -z when z is in the second or third quadrant. This is just what we wanted.

Often, to simplify computations a different phase detector is used. This phase detector should approximate well \arctan(I/Q) at least when the phase of z is near 0º and near 180º. The detector used in the Costas loop GNU Radio block is just IQ. This works as follows. If I^2 + Q^2 = 1, then IQ = \frac{1}{2}\sin(2\theta), where \theta is the phase of I + iQ. Now, for \theta near 0 we have \frac{1}{2}\sin(2\theta) \approx \theta just as we wanted, and also similarly for \theta near \pi. However, this only works if I^2 + Q^2 = 1, which means that the amplitude of the signal is 1. To make this detector insensitive to amplitude we would have to use IQ/(I^2 + Q^2) instead.

The algorithm used in the Polyphase clock sync is best read in the documentation. We see that there are two polyphase filterbanks: one contains matched filters at different phases and the other one contains their derivatives. The error is computed as

E = \frac{1}{2}(\operatorname{Re} x_j \operatorname{Re} d_j + \operatorname{Im} x_j \operatorname{Im} d_j),

where x_j is the output of the j-th matched filter and d_j is the output of its corresponding derivative filter. We see that this is sensitive to the amplitude of the input signal. If the input signal is multiplied by \lambda, then E gets multiplied by \lambda^2.

Similarly, the FLL Band Edge block also includes an algorithm whose error discriminator depends on the amplitude of the input signal.

It would be interesting to modify the discriminators in these 3 blocks to make a BPSK receiver which is insensitive to amplitude. For now, I have just tried to include a better AGC in gr-satellites. Besides the Feed Foward AGC, GNU Radio includes 3 AGC blocks. The simplest is the AGC block. It has a reference value R, and at each step it transforms the input x_n into the output y_n = g_n x_n, and updates the gain as g_{n+1} = g_n + \alpha (R - |y_n|). The problem with this algorithm is that if the input level is very low, then g_n grows almost linearly as g_n \approx \alpha R n + g_0, and so it takes a lot to ramp up to the appropriate level if the rate \alpha is set to a value that provides good performance in the steady state.

The AGC2 algorithm is similar but it uses different rates \alpha for attack and decay. There is also an AGC3 algorithm which presumably solves this problem by doing a linear average of the signal amplitude the first time and then using an IIR filter to update the gain. However, I haven't managed to make it work properly.

In the end, I haven't used any of the AGC, AGC2 or AGC3 blocks for gr-satellites. The AGC that I'm using is rather simple. It computes the average RMS level of the signal using the GNU Radio RMS block and then divides the signal by this RMS. This is inspired by Blockstream satellite, which uses the same kind of AGC. I'm calling this block the "RMS AGC".

RMS AGC block (set to a reference of 0.5)

The RMS block computes and averages the RMS power using a single-pole IIR filter as

p_{n+1} = (1-\alpha)p_n + \alpha|x_n|^2,\quad r_n = \sqrt{p_n},

where x_n is the input signal, p_n is the averaged power and r_n is the RMS. I have found that a value of \alpha = 0.01 works well for gr-satellites, since it gives a time constant of \tau = -1/\log(1-\alpha) \approx 99.5 samples. Since gr-satellites uses a sampling rate of 48kHz, this is 2ms. For 9k6 and 1k2 modems it provides an averaging over several symbols, while still being short enough to ramp up to a stable value during the preamble of the packet.

I have run the BER simulations again, now using an RMS AGC block and an input signal amplitude of 0.1, to force the AGC do some work. It seems that the BPSK receiver works best at a signal amplitude of 0.5, which is weird, because all the blocks are designed for an amplitude of 1, as we have seen above. For this reason, I'm using a reference level of 0.5 in the RMS AGC. For comparison, I also include the BER simulation obtained in the previous post with no AGC and a signal amplitude of 0.5. It seems that the performance of the Viterbi decoder is slightly better with the RMS AGC.

LilacSat-1 BER simulation with new RMS AGC
LilacSat-1 BER simulation without AGC (previous post)

Thanks to David Rowe VK5DGR for all his advice regarding modems.

5 Replies to “AGC for gr-satellites”

  1. I have observed that any filtering block (including AGC, FLL) in GNU Radio uses a lot of CPU. The osmocom source /sink blocks for LIMESDR has the option of setting the AGC in the LIME HW.
    I am using the Automatic gain option there but not sure if it helps.
    Do you have an example for a PSK Receiver for LIMESDR?

    1. The kind of AGC discussed here doesn't play the same role as the AGC in a hardware SDR. I tend not to use AGC in the hardware, as I find it's much better to set the gain manually.

      I don't have a PSK receiver especifically for the LimeSDR, but any in gr-satellites could easily be adapted.

  2. Nice work Daniel, looks like your new AGC algorithm has some performance gains.

    I have been working on PSK modems for HF fading channels. I wonder how the GNU radio sync algorithms would perform, as the AGC would need to track the amplitude as it rapidly shifts up and down. This may lead to some implementation loss compared to ideal modem performance on that channel. Worth noting (and perhaps testing) if anyone uses GNU Radio for fading channels.

    As you've noted it's quite possible to develop amplitude insensitive PSK modem syncronisation routines, would be a useful addition to GNU radio.

  3. I presume that GNURadio uses versions of these algorithms that *are* sensitive to amplitude because the math happens to simpler and thus the speed of the algorithm is better? i.e. IQ is cheaper than arctan(I/Q)

    1. Yes. That is correct. However David make a good point that amplitude insensitive modems are needed in some situations. Also, the modems in gr-satellites run at 48ksps, so it is not that important to use very efficient computations. Moreover, IQ/(I^2+Q^2) is more expensive that IQ, but much cheaper than arctan(Q/I) , and it is also insensitive to amplitude.

Leave a Reply

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