Decoding Mars 2020

Mars 2020, NASA’s latest mission to Mars, was launched a couple weeks ago. However, with all the Tianwen-1 work down the pipeline, until now I haven’t had time to dedicate an appropriate post to this mission (though I showed some sneak peek on Twitter). This mission consists of a rover and helicopter (a real novelty in space exploration). Both were launched with the cruise stage and the entry, descent and landing system on July 30 from Cape Canaveral, an are currently on their transfer orbit to Mars, as Tianwen-1 and Emirates Mars Mission.

In this post I will be working with some recordings made by AMSAT-DL using the 20m radio telescope at Bochum’s observatory. These feature the low rate safe mode telemetry, which was very strong and caused some anecdotes as it saturated some NASA DSN receivers, and the nominal 10kbps telemetry signal that was switched on later. Here I will describe the modulation and coding, giving GNU Radio decoders, and also take a look at the data. has also written a post where he shows similar information.

Safe mode modulation and coding

Mars 2020’s X-band downlink is at approximately 8414.9 MHz. When in safe mode, a baudrate of only 80 baud is transmitted using PCM/PSK/PM (see this document for the terminology). This means that the telemetry is a PSK signal modulated onto a subcarrier which is then phase modulated onto a residual carrier. The subcarrier in this case is a 25kHz square wave.

The figure below shows the spectrum of the signal, as recorded in Bochum on 2020-07-30 20:25 UTC. We see the central residual carrier at a slight offset from 0Hz, and then the data sidebands and their odd harmonics. We have only odd harmonics because of the square wave subcarrier. A sine wave subcarrier produces both even and odd harmonics when phase modulated.

If we zoom in to the centre of the modulation, we see that the data sidebands are very narrow, owing to the low baudrate.

The coding is CCSDS Turbo frames as described in the TM Synchronization and Channel Coding blue book. A rate of 1/2 and frame size of 223 bytes is used. Note that each frame takes 45.5 seconds to transmit, due to the low baudrate.

The GNU Radio decoder flowgraph is shown in the figure below (click on it to view in full size). Its structure is very similar to other PCM/PSK/PM demodulators I’ve shown in previous posts, such as the one for Tianwen-1. The residual carrier is locked with a PLL (here using a bandwidth of 200Hz), the imaginary part of the signal is taken to extract the data sideband, the subcarrier is moved down to baseband, and then clock recovery and subcarrier recovery using a Costas loop are done. Finally, Turbo decoding is done with the blocks from gr-dslwp. The flowgraph can be found here.

Mars 2020 safe mode GNU Radio decoder flowgraph

The figure below shows the decoder running. The signal is very strong, so the constellation is quite clean. We can see in the spectrum of the BPSK subcarrier that the data symbols are not filtered, since some sidelobes are visible.

Mars 2020 safe mode decoder running

10kbps modulation and coding

The nominal 10kbps signal replaces the safe mode modulation during normal spacecraft operations. The modulation is 60kbaud PCM/PM/NRZ. This means that the data is directly phase-modulated onto the residual carrier.

The figure below shows the spectrum of the signal as recorded by Bochum on 2020-07-31 20:04 UTC. We can see the residual carrier and the data modulation, which can be approximated by a BPSK modulation in quadrature with the carrier.

The coding is CCSDS Turbo frames as in the safe mode signal, but here a rate of 1/6 and frame size of 1115 bytes are used to improve the low Eb/N0 performance. As such, frames take around 0.9 seconds to transmit.

The figure below shows the GNU Radio decoder flowgraph for the 10kbps signal. A slightly different approach from the Emirates Mars Mission decoder (which is also PCM/PM/NRZ) is used here. The residual carrier is locked with a PLL (with 50Hz bandwidth) and then the imaginary part of the signal is taken to obtain the BPSK modulation. Clock recovery is made with an ML TED and polyphase root-raised cosine filter. Turbo decoding is done with the gr-dslwp blocks, as for the safe mode signal. The decoder can be found here.

Mars 2020 10kbps mode GNU Radio decoder flowgraph

The decoder is shown below running. The signal is not very strong, and there are many bit errors, but the Turbo decoder is still able to correct most of them, so the frame error rate is low.

Mars 2020 safe mode GNU Radio decoder flowgraph


The framing is the same for the safe mode and 10kbps signals, so it is described here for both. The frames are AOS Space Data Link frames as described in the CCSDS AOS Space Data Link Protocol blue book. The frames contain a CRC-16 used to discard frames with uncorrected errors.

In the recordings I have examined, only spacecraft ID 168 and virtual channel 0 are used in the AOS frames. The payload of the frames contains Space Packets (see the CCSDS Space Packet protocol blue book) using the M_PDU protocol.

The Space Packets contain a secondary header which is a 6 byte timestamp using the CUC format (see the Time Code Formats blue book). This means that the timestamp is a 48 bit counter, which in this case uses units of \(2^{-16}\) seconds. The epoch for the counter is the J2000 epoch, which is 2000-01-01 12:00:00. I am not sure about the timescale used (UTC, TAI, etc.), since the timestamps are somewhat off with respect to the timestamp in the recording filename.

Safe mode frames

Since safe mode frames take so long to transmit, I have only 4 frames extracted from the short recording. The last of them is partly corrupted, due to the signal fading out, so it has incorrect CRC. The frames are shown below, with one frame per row. As we will see later, the blue bands correspond to ASCII text.

Mars 2020 safe mode frames

There are 7 space packets in these frames. The first four belong to APID 8, and the remaining three to the idle APID 2047. The packet timestamps, shown below, are quite interesting. We see that the first four packets (which are those in APID 8 having useful data) were generated almost simultaneously and are sent when possible, due to the low data rate. According to the filename, the recording starts on 20:25:19 UTC. The last three packets are idle and presumable have real-time timestamps. The timestamp spacing for these is 45.5 seconds, which is precisely the duration of the frames.


The APID 2047 idle packets are filled in with an ASCII text as an Easter egg. However, the safe mode frames are too short to contain the full text, so it will be shown later in the 10kbps frames.

The packets in APID 8 contain the following ASCII strings, as well as some binary data


10kbps mode frames

A total of 950 frames were extracted from the recording. From these, only 4 have incorrect CRC. The frames can be seen in the figure below. Most of the frames have an idle packet with the Easter egg ASCII text, as shown by the blue bars (the deep blue blocks are ASCII spaces). The more irregular block near the top is a transmission of old telemetry data.

Below we show the number of frames lost according to the virtual channel frame count.

There are three APIDs active in this recording: APID 2047, which contains idle packets and has 741 packets, APID 9, which contains some real time telemetry and has 58 packets, and APID 247, which contains old telemetry and has 14 packets. The distribution of the packets can be seen well in the figure below, which shows the timestamps classified by APID. We see that most of the time an idle packet is transmitted, with occasional real-time telemetry in APID 9. For some time, old data is transmitted in APID 247, while the real-time APID 9 data continues.

The packets in APID 9 contain data in a format which is difficult to parse. It is a tag-value format in which there is a 2 byte tag describing the type of field and then the field itself. The problem is that the field length is implicit. This can be seen in the block below, which shows the first 64 bytes of the payload of some APID 9 packets in hex. Most of them start by the tag 0x027a, then there is a float64 value, then the tag 0x027d followed by a 32 bit field, the the tag 0x027e, etc.


The problem with parsing this kind of data is guessing the length of each field. However, I have made a heuristic algorithm that doesn’t do such a bad job. It is based on the fact that often one tag and the next one are related: the second tag will be equal to the first one plus a small number. I call “chunk” to the collection of all the fields having the same tag, which indicates that the same type of data (format and semantics) is present.

I have tried to plot some of the chunks that use float64 format and show below the most interesting chunks I’ve found. These clearly have some kind of sinusoidal behaviour. However, as usual, I have not a clear idea of what these are.

Each of the APID 2047 packets contains the following ASCII text. Interestingly, CRLF is used for the line jumps, and lines are filled in to a width of 48 characters with spaces (even the two blank lines), except for the last line (which wouldn’t fit completely in the frame).

N.Abcouwer P.Basa M.Belete E.Benowitz S.Brooks  
J.Biesiadecki L.Burke D.Byrne S.Chen S.Scandore 
J.Carsten K.Edelberg D.Gaines D.Leang R.Joshi   
R.Haleski A.Harris L.Galdamez S.Lewis T.Litwin  
D.Lam Q.Ho M.Maimone M.McHenry D.Morgan S.Myint 
B.Martin P.Partikian G.Rabideau P.Romano R.Tsao 
M.Schoppers A.Shearer R.Srisamang C.Williams    
L.Stewart O.Toupet I.Trettel I.Uchenik V.Verma  
P.Vieira E.Wang B.Wright G.Yang B.Cichy C.Pong  
G.Reeves M.Tuszynski J.Casoliva P.Brugarolas    
Z.Rahman G.Griffin T.Fouser M.Wang P.Kwan       
A.Baez Harry *** The MSL FSW development team.  
 There is beauty in space, it is orderly. There 
 is no weather, and there is regularity. It is  
 predictable. Just look at our little Explorer; 
 you can set your clock by it. Everything in    
 space obeys the laws of physics. If you know   
 these laws, and obey them, space will treat    
 you kindly.     -- Wernher von Braun           
 Deep Purple '72 - Let's go Space Truckin'


The analysis of the frames shown above has been made in this Jupyter notebook. The spectrums of the signals have been computed and plotted in this Jupyter notebook. Thee data files for the frames can be found in the Github repository.

Leave a comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.