KS-1Q decoded

In a previous post, I talked about my attempts to decode KS-1Q. Lately, WarMonkey, who is part of the satellite team, has been giving me some extra information and finally I have been able to decode the packets from the satellite. The decoder is in gr-ks1q, together with a sample recording contributed by Scott K4KDR. I’ve also added support for KS-1Q in gr-satellites. Here I look at the coding of the packets in more detail.

As we already know, KS-1Q transmits 20kbps FSK telemetry in the 70cm band. In my previous post, I managed to get Viterbi decoding for the CCSDS r=1/2, k=7 convolutional code and Reed-Solomon decoding working, but I couldn’t identify correctly the packet boundaries, since I wasn’t able to find a syncword. Several people insisted that I try the standard CCSDS syncword 0x1acffc1d. However, I wasn’t able to find this syncword in the bitstream from KS-1Q.

It turns out that this syncword should not be searched in the raw bitstream, but in the bitstream obtained after doing Viterbi decoding. In hindsight, it is pretty obvious that this could be a possibility, since this is what LilacSat-2 and the rest of the satellites from HIT do. However, I had in mind all the time the kind of coding that AAUSAT4 uses, where the Viterbi decoder runs synchronously, so the syncword is found in the raw bitstream. For KS-1Q, LilacSat-2, etc., the Viterbi decoder runs asynchronously and descrambling and Reed-Solomon decoding are done synchronously by finding the syncword in the Viterbi-decoded bitstream.

Another thing that I failed to note during my previous analysis is that KS-1Q is using a CCSDS scrambler. In fact, I got good Reed-Solomon decodes without descrambling. This may be surprising at first, and I would have to think what is the mathematical reason behind this, but Reed-Solomon codes have many interesting properties that make this sort of things possible.

To sum up, the decoding process for KS-1Q is as follows:

  1. Viterbi decoding. As it is usual with asynchronous Viterbi decoding, two decoders should run in parallel using the bitstream and the bitstream delayed one sample. See the note below about the convention.
  2. Find the syncword 0x1acffc1d and take the packet of 255 bytes following the syncword.
  3. Descramble the 255 byte packet with the CCSDS pseudorandom sequence.
  4. Use Reed-Solomon decoding with the CCSDS convention on the 255 byte packet to obtain a 223 byte packet.

The packets obtained after Reed-Solomon decoding have a 3 byte header. It is always 01 00 50. The first two bytes are the spacecraft ID, and the third byte indicates the type of packet: 5 corresponds to CSP downlink and 0 stands for protocol version 0. The rest of the packet is formed by several CSP packets using KISS framing. The packet is padded to its full 223 byte size by inserting 0xc0 bytes at the end. This is one of the packets from the recording by Scott.

0000: 01 00 50 c0 00 84 92 08 00 00 00 00 00 6b 03 ff 
0010: 00 00 05 1a a7 0e 00 00 3d 00 00 00 35 00 00 00 
0020: 00 00 0c 09 00 00 00 00 0e 00 00 00 00 00 00 00 
0030: 00 00 00 00 00 00 00 00 00 6e 17 00 00 ff ff ff 
0040: ff f0 91 f5 a6 c0 c0 00 82 92 08 00 09 00 00 00 
0050: 00 00 00 00 0d 0c 8f 00 02 00 00 63 10 27 00 bd 
0060: 50 22 bb c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
0070: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
0080: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
0090: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
00a0: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
00b0: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
00c0: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 
00d0: c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 

After removing the 3 byte header and performing KISS deframing, we get the two CSP packets that were framed inside the packet above.

0000: 84 92 08 00 00 00 00 00 6b 03 ff 00 00 05 1a a7 
0010: 0e 00 00 3d 00 00 00 35 00 00 00 00 00 0c 09 00 
0020: 00 00 00 0e 00 00 00 00 00 00 00 00 00 00 00 00 
0030: 00 00 00 00 6e 17 00 00 ff ff ff ff f0 91 f5 a6 

0000: 82 92 08 00 09 00 00 00 00 00 00 00 0d 0c 8f 00 
0010: 02 00 00 63 10 27 00 bd 50 22 bb 

The CSP header starts with the priority bits instead of the reserved bits. I won’t say whether this is the right or the wrong endianness, because even GomSpace seem to get this wrong. The CSP header of AAUSAT4 is the opposite endianness to what one would expect by reading the datasheet of the AX100 transceiver, and in GOMX-3 they use the opposite endianness to AAUSAT4 on the air but then they swap the header during Reed-Solomon decoding. In any case, keep in mind that the CSP header endianness used by KS-1Q is the opposite of what gr-csp expects. The same happens with the satellites from HIT. Thus, I swap the CSP header to obtain the endianness expected by gr-csp. We get the following data in the CSP header.

CSP header:
        Priority:		2
        Source:			2
        Destination:		9
        Destination port:	8
        Source port:		8
        Reserved field:		0
        HMAC:			0
        XTEA:			0
        RDP:			0
        CRC:			0

CSP header:
        Priority:		2
        Source:			1
        Destination:		9
        Destination port:	8
        Source port:		8
        Reserved field:		0
        HMAC:			0
        XTEA:			0
        RDP:			0
        CRC:			0

Although the CRC flag in the CSP header is set to false, the CSP packets contain a CRC-32 at the end. It is the same CRC-32C that is used by CSP. The CSP header is not included in the calculation of the CRC (this is optional in the CSP standard). The CRC of the packets can be checked by using the “Force” option of the “Check CRC” block in gr-csp (otherwise “Check CRC” will pass all packets without checking, because their CRC flag is set to false).

I still don’t know the telemetry format of these packets, but as you can see in the hexdumps above, there are few non-zero fields. I don’t know if KS-1Q is still transmitting, because it was only intended as a short term experiment. WarMonkey says that antenna rotator of their groundstation failed on November 20th.

Update 2/1/2017: Looking more closely at the convolutional code used by KS-1Q, it turns out that it is not the usual CCSDS code with polynomials POLYA and POLYB. The code used by KS-1Q first applies POLYB and then applies POLYA and inverts the result. Therefore, to use the “Decode CCSDS 27” GNU Radio block, it is necessary to invert the second symbol in each pair of symbols and swap the order of the pair. The satellites from HIT (Lilacsat-2, BY70-1, etc.) use the same convention as KS-1Q, so the “Vitfilt 27 FB” block from gr-lilacsat already follows this convention.


    1. You are more or less right. Actually, it is a bit more complex than this. There are the two polynomials POLYA = 0x6d and POLYB = 0x4f. According to the comments in Phil Karn’s libfec, NASA-DSN convention is to use ~POLYA, POLYB. CCSDS/NASA-GSFC convention is to use POLYB, ~POLYA. GNU Radio uses POLYA, POLYB for some reason. I don’t know if this convention is used in some real over the air system. I’ve also encountered POLYB, POLYA in Outernet, which uses the Datum Systems M7 Inmarsat satellite modem. Therefore, one has to watch out for the possible different conventions.

  1. https://public.ccsds.org/Pubs/131x0b2ec1.pdf
    KS-1Q strictly obey ccsds telemetry and telecommand standard

    when data is all zero POLYA and B both output zero. because the two polynomial output is interleaved, to keep receiver syncing it’s necessary to inverse one of them. but, if POLYA and B is combined and transmitted at the same time (e.g. QPSK modulation), bit inverse is unnecessary.

  2. Telemetry decode result:
    =========EPS Telemetry==========
    Solar1i = 0mA,
    Solar2i = 0mA,
    Accel = 875mg,
    Heater = 255,
    PwrOBC = 0,
    PwrCam = 0,
    BatVH = 6661mV,
    BatVL = 3751mV,
    IBat = 0,
    IPsb = 61mA,
    IHeater = 0,
    ITTC = 53mA,
    ILED = 0mA,
    ICAM = 0mA
    BatTemp = 12`C,
    CamTemp = 9`C,
    Temp1 = 0`C,
    Temp2 = 0`C,
    Temp3 = 0`C,
    Temp4 = 0`C,
    RadRaw = 14,
    SunA = 0,
    SunB = 0,
    SunC = 0,
    SunD = 0,
    EBatVL = 0mV,
    Resets = 0,
    WDT = 5998s
    FirstRun = 0,
    OBCEn = 65535,
    HeaterEn = 65535

    ==========TTC Telemetry=========
    TxPkts = 9,
    RxPkts = 0,
    RxErrs = 0,
    CanErrs = 0,
    MCUTemp = 13`C,
    PATemp = 12`C,
    Current = 143mA,
    IPA = 2mA,
    Resets = 0,
    RSSI = 99,
    Beacon Interval = 10000ms,
    Beacon Timeout = 0s

    To decode more packets, use host/KS1GCS at

    1. Thanks for the info! I wasn’t aware that so much information about KS-1Q had been released. Is KS-1Q still active? I have the impression that it isn’t, but I might be wrong.

      1. Last successful telemetry reception at Chengdu, China shows battery level is critical. we stopped operation after ~1month. all recorded raw IQ samples will be decoded this month.

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.