Decoding AO-40 uncoded telemetry

AO-40 is an Amateur satellite that was active between 2000 and 2004. It had several transponders and beacons covering many bands from HF to microwave and its position on a HEO orbit provided several consecutive hours of coverage each day and allowed long distance contacts. Since then, many interesting things have happened with Amateur satellites, particularly the high increase of the number of cubesats that is happening over the last few years, but even so, we haven’t seen again any other satellite with the characteristics of AO-40 nor it is to be expected in the near future.

I was quite young when AO-40 was operational, so for me this is all history. However, Pieter N4IP has posted recently on Twitter some IQ recordings of AO-40 that he made back in 2003. I have been playing with these recordings to see how AO-40 was like. One of the things I’ve dong is to write my own telemetry decoder using GNU Radio.

AO-40 transmitted telemetry using 400bps BPSK. There were two modes: an uncoded mode which used no forward error correction and an experimental FEC mode proposed by Phil Karn KA9Q. The FEC mode was used later in the FUNcube satellites, and I’ve already talked about it in a previous post. The beacon in Pieter’s recordings is in uncoded mode. Here I describe this mode in detail and how my decoder works. The decoder and a small sample taken from Pieter’s recordings have already been included in gr-satellites.

The specifications for the uncoded telemetry are in this document. The data is transmitted using Manchester-encoded differential BPSK. One has to be careful when understanding this. It is important to note at which point in the processing chain the differential encoding is done. In this case, the data bitstream is first differentially encoded, which means that a ‘0’ is represented as no change and a ‘1’ as a change from ‘0’ to ‘1’ or vice versa, and then the differentially-encoded bitstream is Manchester-encoded. This amounts to XORing the 400bps bitstream with a 400Hz clock.

There are several ways to process this encoding upon reception. What I have done is to use an 800baud non-coherent BPSK receiver which outputs one sample per symbol. Then I use a decimating filter with taps [1,-1] and decimation by 2. This takes care of XORing the 400Hz clock again and recovering the differentially-encoded bitstream. However, this will only work if the decimating filter is properly aligned with the 400Hz clock. As it might be one sample out of phase, processing is done both on the output from the BPSK receiver and on the output delayed one sample. After decimation, differential decoding is done on the BPSK symbols. Since this is a non-coherent receiver, carrier recovery (using a Costas loop or similar) is not done. The differential decoder takes care of any small mistuning. The relevant part of the GNU Radio flowgraph can be seen below.

AO-40 GNU Radio decoder

Framing is done using a 32bit syncword and 514 byte frames. These can be extracted using the “Sync and create packed PDU” hierarchical block from gr-satellites. Each frame takes 10.36 seconds to transmit at 400bps. The last 2 bytes of each frame are a CRC16. The CRC variant used is what is called CRC16_CCITT_FALSE in this online CRC calculator. This CRC uses the same polynomial as the CRC16 used in AX.25, but there are some differences. CRC checking is done in a custom block that I have implemented in Python.

After checking the CRC, no further processing is done with the telemetry frames. However, they contain lots of ASCII data. For instance, this is the hex dump of the two frames that decode from the small wav sample I’ve extracted frome Pieter’s recordings. It contains an A block, which carried 128 analogue and 128 digital telemetry channels; and an L block, which was used for the mailbox or broadcast messages. You can scroll the textbox to the right to see the ASCII dump.

It is interesting to note the particular shape of AO-40’s beacon on the waterfall, which can be seen on the top of this post. It is the product of Manchester encoding and the fact that the data is unscrambled and there are many consecutive identical bytes inside each frame.