Report for today’s DSLWP-B SSDV session

Today an SSDV transmission session from DSLWP-B was programmed between 7:00 and 9:00 UTC. The main receiving groundstation was the Dwingeloo radiotelescope. Cees Bassa retransmitted the reception progress live on Twitter. Since the start of the recording, it seemed that some of the SSDV packets were being lost. As Dwingeloo gets a very high SNR and essentially no bit errors, any lost packets indicate a problem either with the transmitter at DSLWP-B or with the receiving software at Dwingeloo.

My analysis of last week’s SSDV transmissions spotted some problems in the transmitter. Namely, some packets were being cut short. Therefore, I have been closely watching out the live reports from Cees Bassa and Wei Mingchuan BG2BHC and then spent most of the day analysing in detail the recordings done at Dwingeloo, which have been already published here. This is my report.

Since Cees begun receiving the SSDV data, he was getting lost packets, as his first tweet shows:

After transmission, the picture Cees obtained looked like this:

Seeing some lost packets, I quickly turned to the analysis of the IQ recording made at Dwingeloo in search of corrupted packets or anything else that could prevent all packets from decoding correctly. The corresponding recording is 2018-08-12T06:58:02_436.4MHz.

The Jupyter notebook where the analysis of the recording is done is here. As I did for last week’s transmissions, I have analysed the location of the ASMs (attached sync markers) to identify Turbo codewords, and payed attention to the distance between these in case any Turbo codeword got cut short.

The SSDV transmission is done in a single GMSK burst and there are a few bursts of telemetry before the SSDV starts. A total of 130 Turbo codewords where found. Of these, 117 mark SSDV packets, 5 correspond to telemetry packets transmitted before the SSDV transmission, and the remaining 8 are telemetry packets interleaved with the SSDV transmission.

Decoding the recording with the GNU Radio flowgraph replay_ssdv.grc using a frequency offset of 1500Hz shows no problems whatsoever. The SSDV decoder runs correctly and there are no missing packets.

$ ssdv -d -D dslwp_ssdv.bin mare_nubium.jpg
Callsign: DSLWP
Image ID: 1E
Resolution: 640x480
MCU blocks: 2400
Sampling factor: 2x1
Quality level: 5
Read 117 packets

The SSDV decoder produces a complete image, as shown below.

Mare Nubium SSDV image downlinked by DSLWP-B

I do not know why Cees got missing packets when decoding the image in real time.

While I was analyzing the first recording, Cees already had decoded the next image and published two new recordings. The image he decoded is shown in the tweet below. Again, there are several missing packets.

The two recordings Cees shared are 2018-08-12T07:41:24_436.4MHz and 2018-08-12T08:32:25_436.4MHz. A quick analysis of these with the GNU Radio decoder shows problems.

The first of these two recordings contains a retransmission of the Mare Nubium image shown above. The SSDV decoder shows that the decoding starts at packet 61, so we’ve missed the beginning of the image. Then there is a gap between packets 89 and 107. After the image has ended, we see out-of-order packets, which the SSDV doesn’t like. Besides packets 5, 7 and 24, which are odd, what happens is that the image starts again and we get most of the packets from 0 to 80. Some preprocessing could be done to order the packets before sending them into the SSDV decoder, but still there are some missing packets.

$ ssdv -d -D dslwp_ssdv.bin mare_nubium_again.jpg
Callsign: DSLWP
Image ID: 1E
Resolution: 640x480
MCU blocks: 2400
Sampling factor: 2x1
Quality level: 5
Gap detected between packets -1 and 61
Gap detected between packets 89 and 107
Packets are not in order. 115 > 5
Packets are not in order. 115 > 7
Packets are not in order. 115 > 24
Packets are not in order. 115 > 0
Packets are not in order. 115 > 1
Packets are not in order. 115 > 2
Packets are not in order. 115 > 3
Packets are not in order. 115 > 4
Packets are not in order. 115 > 5
Packets are not in order. 115 > 6
Packets are not in order. 115 > 7
Packets are not in order. 115 > 8
Packets are not in order. 115 > 9
Packets are not in order. 115 > 10
Packets are not in order. 115 > 11
Packets are not in order. 115 > 12
Packets are not in order. 115 > 13
Packets are not in order. 115 > 14
Packets are not in order. 115 > 15
Packets are not in order. 115 > 16
Packets are not in order. 115 > 17
Packets are not in order. 115 > 22
Packets are not in order. 115 > 23
Packets are not in order. 115 > 24
Packets are not in order. 115 > 25
Packets are not in order. 115 > 26
Packets are not in order. 115 > 27
Packets are not in order. 115 > 28
Packets are not in order. 115 > 29
Packets are not in order. 115 > 30
Packets are not in order. 115 > 31
Packets are not in order. 115 > 32
Packets are not in order. 115 > 33
Packets are not in order. 115 > 34
Packets are not in order. 115 > 35
Packets are not in order. 115 > 36
Packets are not in order. 115 > 37
Packets are not in order. 115 > 38
Packets are not in order. 115 > 39
Packets are not in order. 115 > 40
Packets are not in order. 115 > 41
Packets are not in order. 115 > 42
Packets are not in order. 115 > 43
Packets are not in order. 115 > 44
Packets are not in order. 115 > 45
Packets are not in order. 115 > 46
Packets are not in order. 115 > 47
Packets are not in order. 115 > 48
Packets are not in order. 115 > 49
Packets are not in order. 115 > 50
Packets are not in order. 115 > 51
Packets are not in order. 115 > 52
Packets are not in order. 115 > 53
Packets are not in order. 115 > 54
Packets are not in order. 115 > 55
Packets are not in order. 115 > 56
Packets are not in order. 115 > 57
Packets are not in order. 115 > 58
Packets are not in order. 115 > 59
Packets are not in order. 115 > 60
Packets are not in order. 115 > 61
Packets are not in order. 115 > 62
Packets are not in order. 115 > 63
Packets are not in order. 115 > 64
Packets are not in order. 115 > 65
Packets are not in order. 115 > 66
Packets are not in order. 115 > 67
Packets are not in order. 115 > 68
Packets are not in order. 115 > 69
Packets are not in order. 115 > 70
Packets are not in order. 115 > 71
Packets are not in order. 115 > 72
Packets are not in order. 115 > 73
Packets are not in order. 115 > 74
Packets are not in order. 115 > 75
Packets are not in order. 115 > 76
Packets are not in order. 115 > 77
Packets are not in order. 115 > 78
Packets are not in order. 115 > 79
Packets are not in order. 115 > 80
Read 119 packets

Below we see the image produced by the SSDV decoder. Note it has ignored all the beginning of the image, since it is retransmitted out-of-order.

Incomplete image received during retransmission

The last recording corresponds to the purple Sun image. Decoding starts by packet 3, then packets 4 and 5 are missing, and there is a large gap between packets 41 and 70. Also, after the end of the image, packets 70 through 80 are transmitted again.

$ ssdv -d -D dslwp_ssdv.bin purple_thing.jpg
Callsign: DSLWP
Image ID: 2B
Resolution: 640x480
MCU blocks: 2400
Sampling factor: 2x1
Quality level: 5
Gap detected between packets -1 and 3
Gap detected between packets 3 and 6
Gap detected between packets 41 and 70
Packets are not in order. 79 > 70
Packets are not in order. 79 > 71
Packets are not in order. 79 > 72
Packets are not in order. 79 > 73
Packets are not in order. 79 > 74
Packets are not in order. 79 > 75
Packets are not in order. 79 > 76
Packets are not in order. 79 > 77
Packets are not in order. 79 > 78
Packets are not in order. 79 > 79
Unexpected MCU ID in packet 80.
Read 59 packets

The image produced by the SSDV decoder is show below. Note the large gap and packets 4 and 5, which are missing.

SSDV image of purple Sun with large gap

What I find very puzzling is that the gaps in Cees image are completely different from mine. He doesn’t have the large gap, but he has more smaller gaps. Thus I have spent the rest of the day investigating this recording, setting aside for the moment the recording of the retransmission of the Mare Nubium image.

The Jupyter notebook with the analysis of the recording is here.

After some investigation I have found that there is a frequency jump in the DSLWP-B transmitter, which is something that Wei already suspected (see here). Apparently, it has something to do with the DSLWP-B onboard TCXO. This frequency jump upsets the coherent OQPSK decoder and makes it lose a couple of packets. The effects in the GNU Radio decoder can be seen in the figure below.

DSLWP-B transmitter frequency jump

In detail, when the frequency jump happens, the PLL loses sync and the tail of one packet gets corrupted. The ASM frequency estimator for the next packet fails completely, so the next packet is garbage. After this, decoding resumes normally. This corresponds to SSDV packets 4 and 5 and explains why they where lost.

Even though the frequency jump prevents coherent decoding, non-coherent decoding is possible given the large SNR of the signal. I have done this by hand in the Jupyter notebook to spot any other problems. The idea is to demodulate the GMSK signal as an FSK signal in the manner I’ve being doing before. However, then the GMSK symbols must be transformed into QPSK symbols. This is a bit tricky. It involves integrating the GMSK symbols and considering phase ambiguities. See the Jupyter notebook for more details.

The Jupyter notebook saves all Turbo codewords to a file. This file is then loaded into the GNU Radio flowgraph replay_ssdv_postproc.grc, which performs descrambling, Turbo decoding, and extraction of the SSDV frames.

A total of 67 ASMs where found in the Jupyter notebook and the GNU Radio flowgraph decodes correctly 67 TM master frames. These have sequence numbers 9 through 75, which indicates that there are no lost packets. Of these frames, 61 are SSDV packets, which belong to virtual channel 1 and have virtual sequence numbers 240 through 255 and 0 through 44. The remaining 6 frames are transmitted through virtual channel 0.

As one can see in the Jupyter notebook, the SSDV packets are transmitted in three different GMSK bursts.

The SSDV decoder produces the following output. Note that packets 70 through 80 have been transmitted twice.

 $ ssdv -d -D dslwp_ssdv.bin purple_sun.jpg
Callsign: DSLWP
Image ID: 2B
Resolution: 640x480
MCU blocks: 2400
Sampling factor: 2x1
Quality level: 5
Gap detected between packets -1 and 3
Gap detected between packets 41 and 70
Packets are not in order. 79 > 70
Packets are not in order. 79 > 71
Packets are not in order. 79 > 72
Packets are not in order. 79 > 73
Packets are not in order. 79 > 74
Packets are not in order. 79 > 75
Packets are not in order. 79 > 76
Packets are not in order. 79 > 77
Packets are not in order. 79 > 78
Packets are not in order. 79 > 79
Unexpected MCU ID in packet 80.
Read 61 packets

The JPEG image produced by the decoder is shown below. It is the same as the image shown before, except for the fact that packets 4 and 5 are no longer missing. The large gap is still present.

SSDV image of purple Sun with large gap (small gap fixed)

Therefore the conclusion is that a frequency jump in the DSLWP-B transmitter causes the coherent OQPSK demodulation to fail and corrupts SSDV packets 4 and 5. This can be fixed by using a non-coherent demodulator. However, there is a large gap: packets 42 through 69 where not transmitted. The master and virtual channel sequence numbers are consistent and indicate that all the transmitted packets where received correctly. The problem is with the transmitter software, which has skipped several SSDV packets from transmission.

Note that there is no evidence that samples were lost in the recording by Dwingeloo. The phase of the GMSK signal is continuous, all the ASMs identified carry a valid packet, and there are no gaps in the TM sequence numbers.

At this point I am quite puzzled. Remember that the image shown by Cees Bassa of the purple Sun didn’t have a large gap as mine does. I have no clue of where the packets to fill this large gap have come from, since they were not transmitted during the recording made at Dwingeloo.

Update 2018-08-12: Shortly after publishing this post and talking with Cees Bassa about the different recordings, I have noted that I missidentified all the SSDV packets in the second recording (the one containing a partial picture of Mare Nubium) as belonging to the same image. This is an oversight on my part. The image IDs in the SSDV packets clearly show two different images. The fist one is the picture of Mare Nubium. The second one, comprised by the packets 0 through 80 that I though were a repetition is the first transmission of the picture of the purple Sun.

The SSDV decoder assumes that all the SSDV packets form part of the same image. After separating the packets of each image, I get the following JPEG image.

SSDV image of the purple Sun transmitted in the second recording

Thus, we see that the purple Sun image was transmitted completely during the second recording and retransmitted leaving a large gap during the third recording. There are a few missing packets in the image above, but this is probably caused by a frequency jump in the transmitter. The missing packets can be completed with the retransmission of the image in the third recording.

To aid in recovering SSDV files, I have made the script ssdv_sort.py, which gets a file containing several SSDV packets, separates them according to the image ID, sorts them, and calls the SSDV decoder for each image. This script can be called as

$ ./ssdv_sort.py /tmp/ssdv /tmp/ssdv_out

Here /tmp/ssdv is a file containing all the SSDV packets extracted from the second and third recording (it has been obtained by concatenating the outputs of the GNU Radio decoder on each file using cat). This produces the files /tmp/ssdv_out_30.jpg and /tmp/ssdv_out_43.jpg, shown below.

ssdv_out_30.jpg Retransmission of Mare Nubium image during second recording
ssdv_out_43.jpg Image of the purple Sun assembled from second and third recordings

Thus, finally the image of the purple Sun is complete and the mistery of where the pieces in Cees’ tweet came from is solved.

6 comments

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.