Tag Archives: BPSK

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.



GOES Satellite Decoding

Back in February of this year I found a fantastic site, SetiQuest. Like a lot of people, I’ve been fascinated by the idea of SETI for a long time and to have the opportunity to play around with their data was great. The actual process of searching these signals for signs of intelligent life doesn’t interest me too much, though the matched filtering methods proposed by Professor David Messerschmitt seems very interesting. What does interest me is the calibration data collected from satellites. This data often contains information bearing signals that can be demodulated and decoded to give a wide variety of information. The data set that most interested me was a recording made while targeting a geostationary operational environmental satellite (GOES) satellite. These satellites provide constant monitoring of weather related events on earth and beam down a variety of images and text information.

With the data sets provided I was able to decode a number of high quality images from both GOES-East (aka GOES-13) and GOES-West (aka GOES-11). GOES-East is stationed above the northern part of South America and is able to see both the North and South American continents as well as the eastern coast of Africa. The satellites cycle through a series of imaging sectors targeting different parts of the globe with capturing various segments of the RF spectrum. The image below is of the continental United States taken in the visible light spectrum from GOES-East.

GOES East 13 North AmericanGOES-West is stationed over the Pacific Ocean and can view the continental US as well as Alaska and Hawaii. The image shown below targeted the south hemisphere in the visible light spectrum.

GOES West 11 South Pacific

When I originally did this decoding, I used Matlab for the entire process. I’ve since rewritten everything for C++ to speed things along, but I thought I would detail my original demodulation and decoding process in case anyone is interested.

SetiQuest Data Formatting

The first step in the decoding process is understanding how the data is saved by SetiQuest. The SETI website gives a nice description of how they collect and save their data so I’ll just give a brief overview. The data is saved in a series of .dat files which contain 8 bit complex numbers corresponding to the IQ demodulated data. Each data set on the SETI website comes with a header file which outlines the center frequency the data was collected at, along with the bandwidth of the data.

For the GOES data sets, the center frequency was 1692 MHz with a bandwidth of ~8.74 MHz. You can see an amplitude plot of the spectrum below.

Geostationary Operational Environmental Satellites GOES SpectrumI’ve labelled the locations of some of the signals transmitted down by the GOES satellite. At 1691 MHz is the Low Rate Information Transmission (LRIT) signal. This is the signal which contains the information for the above images. At 1692.7 MHz is the EMWIN-N signal. At 1694 MHz there is a low data rate telemetry signal. Between 1694 MHz and 1695 is a Data Collection Platform Report (DCPR) signal. I’ve been primarily concerned with the LRIT signal since this is the most well documented signal, however I have briefly looked at the other signals. The telemetry signal appears to be a 4000 bps, manchester encoded signal. I couldn’t find any sources that provide the details of this signal so I didn’t explore it too far. I hope to spend some time looking at the EMWIN-N signal, I believe this signal is modulated with an offset quadrature phase-shift keying approach.

LRIT Demodulation

The demodulation and decoding of the LRIT is fairly straightforward. The only real complexity comes in the number of signal processing steps that lie between the raw data and the final image. My plan is to break the entire demodulation process into a series of posts. I’ll post as much processed data from each step as possible. To get the original raw data, you need to sign up at the setiQuest website and then you can download the data from here.

For this post, I’ll focus on bringing the passband signal down to baseband and sampling the bits. There is a nice report from the Aerospace Corporation which details the transmission parameters of LRIT as well as some of the other signals transmitted by the GOES satellites. Below you can see a table from that report which summarizes the transmission specifications very nicely.

The first step in the demodulation process is filtering the signal to isolate the LRIT signal. Since this is a complex signal, we can not simply use a real-valued bandpass filter. A real bandpass filter is designed to pass both positive and negative frequencies, but in the case of this data, the negative frequencies are not just a complex conjugated copy of the positive frequencies. The bandpass filter was created by starting with a lowpass filter with a bandwidth equal to a half my desired bandpass bandwidth (~350 KHz lowpass bandwidth). I then multiplied the real-valued lowpass filter with a complex sinusoid whose discrete frequency was equal to the discrete frequency of the LRIT signal, this frequency is 2*pi*(1691e6 – 1692e6)/sF, where sF is the sampling frequency. The graphic below shows the filter superimposed on the LRIT signal.

 Geostationary Operational Environmental Satellites GOES LRIT

The next step is the carrier recovery to bring the BPSK signal to baseband. Because no two systems have exactly synchronous clocks, you can’t simply shift the passband signal to baseband with a complex sine multiplication. Instead, I use a Costas loop to track the carrier, and use this recovered carrier to bring the system to baseband. The Costas loop is essentially a PI controller for the frequency of the synthesized carrier. The error fed into this controller is generated by multiplying the real part of the baseband signal by the imaginary part. This creates a signal which is proportional to the difference in frequency between the received carrier and the synthesized carrier. Often times you will see this error term passed through a low pass filter, but since we are dealing with a complex passband signal this isn’t strictly necessary. If the passband signal is a real signal, there will be harmonics at 2 and 4 times the carrier frequency which need to be filtered out. The proportional term of the Costas loop will cancel any frequency offset, while the integral term will bring the phase offset to zero. Below you can see the baseband signal in blue and the sampling times for each bit marked with the black star.

 LRIT BPSK Baseband Signal and Timing

The timing recovery was performed using a Mueller-Muller timing scheme. This bit timing recovery uses the current sample along with the previous sample to determine if the sampling instance is early or late. If the sampling is early, the symbol timing period is increased, if the timing is late, the symbol period is decreased. You can see the constellation diagram for the BPSK signal below.

LRIT BPSK Constellation Diagram

I’ve collected all the mFiles I used to get the above data along with a text file containing the first 2 million bits from the GOES-13 second data set. If you’d like to run the files yourself, you should only need to change the file location of the GOES data set. You can download the scripts and data here. In the next few days I plan to discuss the Viterbi decoding, packet synchronization and de-randomization.