GOES Satellite Decoding, Part 2

There are a number of different Viterbi packages freely available. For the C++ implementation of the GOES decoder, I used the package available here, which was created by Phil Karn. For the initial Matlab decoder, I relied on the Viterbi decoder in the communications toolbox. I posted the raw bit data, and I plan to post the decoded data here so anyone testing out the C++ Viterbi decoder should have enough test data to debug and get things working.

The first step in using Matlab’s Viterbi decoder is to create a Viterbi Trellis. The GOES satellite uses the NASA standard k=7, rate 1/2 encoding. The trellis for this encoding can be created in Matlab with the poly2tellis command:

trel = poly2trellis(7,[171 133]);

Here the taps on the encoding shift register are represented in Octal notation. The first set of taps is 171 (decimal 121, and hex 79), and the second is 133 (decimal 91, and hex 5B).

With the trellis created, the bitstream can be decoded with the vitdec command. There are a number of user definable parameters available with the vitdec command. The first parameter is the trace-back length for the decoder. I stuck with the convention of 5 times the trace-back length. The next option is the mode of the decoder, this options determines what state the decoder starts with. I used the ‘trunc’ option which places the decoder in the all zeros state. The final option specifies how you quantize the input data, I used binary data so I chose the hard-decision option. The entire command is given as:

decoded1 = vitdec(bit1,trel,tblen,’trunc’,’hard’);

Here tblen represents the traceback length and bit1 represents the bit stream.

There is one further complication, since this is a rate 1/2 code, each bit is represented by 2 channel symbols. There is no way to tell which BPSK bit corresponds to the first channel symbol and which corresponds to the second, to overcome this I decode two bitstreams, each offset by 1 bit. I can then re-encode the decoded data to look at the bit errors. By seeing which one of the re-encoded data streams is most similar to the original bit stream, the alignment of the channel symbols can be determined.

One point I should mention, with the Costas loop, the carrier recovery has an ambiguity of pi radians. This means that what I currently refer to as a positive could be negative in a different receiver or even a different initialization of the current receiver. This viterbi filter is transparent, that is, if the incoming bitstream is inverted, the output will decode correctly but still be inverted.

Frame Synchronization

The output of the Viterbi filter is a stream of Channel Access Data Unit (CADU) packets. These packets contain the raw imaging data and a Reed-Solomon error correcting header, all xor’d with a pseudorandom bit mask to ensure there are no long runs of ones or zeros.  The start of each packet can be identified by a 32 bit synchronization header, 0x1ACFFC1D, and is 8192 bits long, including the header.

At 32 bits, it is unlikely that this particular string of bits will occur by random, but even still, I search for the header of each packet, and once found, take the next 8192 bits from the start of the header before searching again. This ensures that if a CADU packet were to contain the synchronization header bits at a location other than the start, I would only lose two packets instead of a long stream of packets.

The frame sync stage is where I check for the correct polarity of the incoming bit stream. I look for both the synchronization header described above, and its complement. I can determine the polarity by looking at if I am finding the specified header or its complement.


Once the CADU packet has been isolated, the next step is to remove the randomization. Each packet has its data payload (i.e. everything other than the synchronization header) xor’d with a pseudorandom bit mask. This randomization process is different than some other information bearing signals transmitted by GOES. The mask used on each packet is identical from transmission to transmission. Some signals (the EMWIN from GOES-11) xor their information with a free running PN bit stream. The generator polynomial for the bit stream is:

1 + x^3 + x^5 + x^7 +x^8

The first few bits of this output are:


I’ve included the entire random bit string in the mFiles and data zip file at the end of this post.

After Xor’ing this Pn bit stream with the CADU, we are left with the Coded Virtual Channel Data Unit (CVCDU). The CVCDU contains the data payload along with the Reed-Solomon error correction headers.

Next Steps

We’re slowly beginning to make our way up the protocol layers. The next steps will require us to create the individual protocol data units. These must be arranged by the type of data they are transmitted (i.e. visual light image, ultraviolet light image, textual information, etc..), and then the data must be decompressed row by row to yield the final image. I’ll post the next couple steps in the decoding process in a few days.

I’ve attached the mFiles and Data files created and used in this post here. There are three mFiles, viterbiDecode, packetDecode, frameDecode. viterbitDecode takes in the raw bitstream from the last post. packetDecode takes the output of the virterbiDecode function and breaks this up into the synchronized packets. frameDecode removes the randomization. The data contains the PN bit stream, as well as the output of the Viterbi Filter and the derandomized packets.



Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>