The launch last Saturday of Crew Dragon Demo-2 undoubtedly was an important event in the history of American space exploration and human spaceflight. This was the first crewed launch from the United States in 9 years and the first crewed launch ever by a commercial provider. Amateur radio operators always follow this kind of events with their hobby, and in the hours and days following the launch, several Amateur operators have posted reception reports of the Crew Dragon C206 “Endeavour” signals.
It seems that the signal received by most people has been the one at 2216 MHz. Among these reports, I can mention the tweets by Scott Tilley VE7TIL (and this one), USA Satcom, Paul Marsh M0EYT. Paul also managed to receive a signal on 2272.5 MHz, which is not in the FCC filing, so this may or may not be from the Crew Dragon.
Scott has also shared with me an IQ recording of one of the passes, and as I showed on Twitter yesterday, I have been able to demodulate the data. This post is my analysis of the signal.
The recording that Scott sent me is 115 seconds long and was made on 2020-05-31 03:19:39 UTC, at a frequency of 2216 MHz using a sample rate of 4Msps. The recording has a size of 3.5GB. Interested people should get in touch with Scott to obtain a copy of the file. For convenience, I’m also hosting a one second snippet of this recording (selected from the portion where the signal was strongest). This snippet is only 31MB large and can be downloaded here. It should be more than enough for people interested in analysing the modulation and coding.
The material used in this post is in this Github repository. The data files are handled using git annex (see the README for instructions). The GNU Radio flowgraph crewdragon.grc uses some blocks from gr-satellites v3.0.0-rc1.
A first look at the modulation shows that it is FSK (most likely GFSK) with a baudrate of 2.35Mbaud and a deviation of approximately 800 kHz. I have made the demodulator shown below, which works by moving each of the two FSK tones down to baseband and comparing power.
The figure below shows the decoder running on the one second snippet linked above. Although there is lots of fading in the recording, the signal in this snippet is quite strong and there are very few bit errors. It is noteworthy the large number of spectral lines that are visible in the spectrum, as well as in the waterfalls of the tweets mentioned earlier.
This Jupyter notebook is used to look at the symbols produced by the demodulator and reverse-engineer the synchronization and coding. Since this is a spacecraft signal, it is quite possible that some form of the CCSDS protocols is used, and indeed correlating against the
0x1ACFFC1D CCSDS 32-bit ASM shows that this ASM appears in a regular fashion in the symbol stream.
The correlation peaks are spaced 2000 symbols. Not taking into account the 32 bit ASM, this suggests that frames of 1968 symbols are used. According to the TM Synchronization & Channel Coding CCSDS Blue Book, there are a number of coding schemes that use this 32 bit ASM: uncoded, convolutional, Reed-Solomon, concatenated, and some LDPC frames. However, the frame size doesn’t seem right for LDPC, and if a convolutional encoder was used, the ASM would be sent encoded, so we wouldn’t see it directly. This leaves us with uncoded and Reed-Solomon as the only choices (or it could be something else not in the Blue Book).
Collecting each of the frames as an array of 246 bytes and plotting them by rows, we get the figure below. We see that many frames have exactly the same pattern.
By looking at one of the frames with this pattern, we see that the pattern repeats every 255 bits and matches almost exactly the CCSDS scrambler sequence. This suggests that these are idle frames which are full of zeros almost completely. The fact that many frames have a repeating pattern of 255 bits explains the abundance of spectral lines, which should be spaced in integer multiples of 9215.7 Hz (for a clever solution to this, see my post about the BepiColombo idle frames).
By descrambling the frames, we see that only the first byte (which is
0xff) and the last 32 bytes are non-zero. This suggests that Reed-Solomon is used, and indeed a simple test with the Reed-Solomon decoder from gr-satellites shows that the frames can be decoded successfully with the CCSDS Reed-Solomon decoder using the dual basis.
Therefore, we conclude that the frames are completely standard CCSDS Reed-Solomon frames with a frame size of 214 bytes. The gr-satellites CCSDS Reed-Solomon Deframer can be used to perform ASM detection, descrambling and Reed-Solomon decoding. The resulting frames are written to a file, which is analysed in the same Jupyter notebook.
The figure below shows the successfully decoded 214 byte frames corresponding to the whole 115 second recording. Note that many frames, especially near the beginning and end of the recording, were not decoded due to the fading. In fact, there are some 130k frames in 115 seconds, while we only have nearly 60k correct frames.
The idle frames can be seen as dark lines, since all their contents, except for the first byte are zeros. It turns out that the first byte identifies the type of frame:
0xff for an idle frame,
0x00 for a non-idle frame. It is interesting to study the rate of idle frames, which shows the link usage. This can be seen in the figure below, where we can see some event that temporarily increases the datarate pushed through the link. Still, the link is nowhere near its maximum capacity (which is 243KiB/s, after discarding the overhead due to FEC and headers).
The second byte of non-idle frames contains a 7bit sequence counter (interestingly the most significant bit is always zero). We can use this counter to detect frame loss by looking at unexpected jumps in the counter (of course this has aliasing when many frames are lost and will ignore an integer multiple of 128 lost frames). The figure below shows that most of the time we manage to decode all the frames, but there are occasions when many frames are lost due to fading (note that this doesn’t take into account the moments when we don’t decode any frames at all).
The figure below shows all the non-idle frames that were correctly decoded. Except for the first two bytes, their contents seem completely random. It might happen that the data is encrypted or compressed, so without any knowledge of what kind of data is transmitted, it is not obvious how to proceed now.
Thank you for looking into this so promptly! Fascinating to see analysis of such a recent signal.
I will continue reading in case you have already addressed this, but so far cannot figure out how to utilize the smaller sample file (crewdragon2_20200531_032019_2215MHz_4Msps.c64) with the ‘crewdragon.grc’ flowgraph which appears to use as input the standard .RAW file typical of collection tools such as GQRX.
May we please get some guidance on whether these input files are interchangeable? Or, if not, what adjustments to make?
I often use .c64 as an extension for complex64 raw files, but it is exactly the same format as in the .raw file produced by GQRX and can be used interchangeably.
Another hint: if using the shorter file, set the offset parameter in the file source to 0. I used that to skip the first 40 seconds in the long recording.
Thanks for the reply! You will be proud of me – before reading your reply I tried a zero offset on the input file and it the flowgraph runs perfectly.
Crazy hint: pass the data through a dvb-s2 decoder
What do you mean? The physical layer here (FSK + CCSDS Reed Solomon frames) is completely different from DVB-S2. Or do you mean that the payload of the non-idle frames (i.e., last figure in my post) are DVB-S2 BBFRAMEs? That would be surprising.
Good day, we are trying to make a gfsk decoder for the student and amateur cube satellite we are developing, but we could not solve it, can you help us. I would be glad if you give us advice.
Hi TA2RMU, I see that you’ve also sent me an email with this question, so I will be replying directly over email.