D-SAT image downlink

In a previous post, I spoke about the cubesat D-SAT. The thing that first caught my attention about this satellite is its image downlink and the quality of some of the images that Mike DK3WN has managed to receive. Yesterday, Mike sent me an IQ recording of D-SAT downlinking a couple of images. After using the Groundstation software by the D-SAT team to verify that the images in the recording can be decoded, I have reverse engineered the protocol used to transmit images and added an image decoder to the D-SAT decoder in gr-satellites.

The image decoder can be tested with the dsat-image.wav recording in satellite-recordings. This WAV file contains the image below, which shows the Southwestern part of Spain and Portugal. The image was taken by D-SAT on 2017-08-17 10:09:54 UTC and received by Mike during the 19:10 UTC pass that evening.

Image of Spain and Portugal taken by D-SAT

According to the TLEs, at the time this image was taken, D-SAT was just above Rincón de la Victoria, in Málaga, passing on a North to South orbit. This means that D-SAT’s camera was pointing more or less in a direction normal to the orbit.

This image is a 352×288 pixels JPEG image with a size of 13057 bytes. It took 43 seconds to transfer using D-SAT’s 4k8 AF GMSK downlink (yes, the overhead is around 100%, more on that later). In the rest of this post, I detail the protocol used to transmit the images.

There are two types of packets involved in the image downlink protocol: image announcements and JPEG chunks. The first packet sent to downlink an image is an image announcement which contains the UTC timestamp, the image number, the GPS position (although this is set to 0 in the packets I’ve seen) and the image size. After that, the JPEG file is transmitted in consecutive chunks.

The following packet is the image announcement for the image shown above.

0000: 00 34 a3 82 72 6b 95 59 01 00 00 00 00 00 00 00 
0010: 00 00 00 00 00 01 33 00 00

Bytes 0x00 to 0x03 are the CSP header, bytes 0x04 to 0x07 are the UTC UNIX timestamp as a little endian int32_t, bytes 0x08 to 0x11 are the image number or ID, as a little endian uint32_t, the next 12 bytes are the GPS position (I’m not sure about the format), and bytes 0x15 to 0x18 are the size of the JPEG image in bytes as a little endian uint32_t.

The following packet is the first JPEG chunk for the image shown above.

0000: 10 b5 a7 82 ff d8 ff e0 00 11 4a 46 49 46 00 01 
0010: 01 01 00 00 00 00 00 00 0a ff db 00 43 00 08 06 
0020: 06 07 06 05 08 07 07 07 09 09 08 0a 0c 14 0d 0c 
0030: 0b 0b 0c 19 12 13 0f 14 1d 1a 1f 1e 1d 1a 1c 1c 
0040: 20 24 2e 27 20 22 2c 23 1c 1c 28 37 29 2c 30 31 
0050: 34 34 34 1f 27 39 3d 38 32 3c 2e 33 34 32 ff db 
0060: 00 43 01 09 09 09 0c 0b 0c 18 0d 0d 18 32 21 1c 
0070: 21 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 
0080: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 
0090: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 
00a0: 32 32 32 ff c4 00 1f 00 00 01 05 01 01 01 01 01 
00b0: 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 
00c0: 08 09 0a 0b ff c4 00 b5 10 00 02 01 03 03 02 04 
00d0: 03 05 05 00 00 00 00 00 00 04 b0

The first 4 bytes are the CSP header. After the CSP header, the chunk from the JPEG file starts. Here you can recognize JPEG’s magic number ff d8 ff at the start of the file. The chunk continues until the last 8 bytes of the packet. In this case, the chunk has 207 bytes, but this may vary. These last 8 bytes are interpreted as follows: the first 4 are the offset in bytes of this chunk within the current segment, encoded as a big endian uint32_t, and the last 4 bytes are the size in bytes of the current segment, also encoded as a big endian uint32_t.

The concept of segments works as follows, the first segment of this file has a size of 0x04b0 = 1200 bytes. This means that chunks for a total size of 1200 bytes will be transferred. This transfer is done as 5 chunks of 207 bytes and a last chunk of 165 bytes, although in principle this need not be the case. The first chunk has an offset of 0, the second chunk has an offset of 207 = 0x00cf and so on. After the first 1200 bytes of the file are transferred, the offset is reset to 0 and the file transfer continues with the second segment. This second segment may have a size different from 1200 bytes.

I am not sure why this concept of segments is implement. There doesn’t seem to be any FEC per segment. Perhaps they are used for some ARQ protocol.

This protocol used by D-SAT is similar to the protocol used by the BY70-1 image downlink, so it was easy to modify the BY70-1 image decoder in gr-satellites to implement an image decoder for D-SAT. The main difference between D-SAT and BY70-1 is that BY70-1’s chunks are in some sense self-sufficient, as all of them indicate the image ID and absolute offset within the file. D-SAT’s protocol is much less robust. If you lose the image announcement you don’t have much to do. Also, if you lose some packets, you probably lose track of which is the current segment, because segments are not numbered. As a curiosity, I find it amusing that D-SAT’s protocol involves both big endian and little endian integers.

Regarding the overhead in image transmission, if we study it per packet it is not much. Typically, chunks of 207 bytes are used. These have 4 bytes of CSP headers and a footer with 8 bytes. In front of the message we have a 4 byte syncword and a 12 bit field indicating the length and FEC of the packet. Also, a 32 byte Reed-Solomon checksum is appended to the packet. This means that the total size of the packet is 256.5 bytes, so the overhead is 24%. However, it seems that the downlink is not active continuously, stopping between packets. This is apparent in the following screenshot, which shows the sample recording in Audacity.

Gaps between D-SAT image packets

The signal of lower amplitude is the signal from D-SAT’s packets, while the signal of larger amplitude is just noise when the downlink is not transmitting. The transmitter goes on for about 3 seconds and then it remains off for about 1.2 seconds. It seems that a complete image segment is transferred every time that the transmitter goes on (3 seconds is the time it takes to transmit 7 packets of 256.5 bytes at 4k8). This makes plausible my idea that the segments are used for ARQ. Probably, after transmitting the segment, D-SAT listens for 1.2 seconds to see if it hears a retransmission request from its groundstation.

Many thanks to Mike DK3WN for contributing the IQ recording used in this post.


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.