%matplotlib inline
from math import sin, pi
import random
import chart
from matplotlib import rcParams
rcParams.update({'font.size': 12})
The L1 GPS carrier is a plain sine wave at 1575.42 MHz. Not much to look at, but here it is
f = 154 * 10.23e6
carrier = lambda x: sin(2*pi*f*x)
chart.Plot('GPS L1 Carrier Wave', tend=8/f, sr=1.0e-12).signal(carrier, color=chart.blue).show()
Modulated to this carrier is a psudo-random sequnce known as a PRN. There isn't any information in this data in the usual way that we think of. That is to say that the bits themselves aren't interesting, it's just a random-looking number. But instead they work as a way to figure out where in the signal you are looking. It's part of a kind of radio technique called CDMA.
To have something to look at that is simpler than the actual GPS PRN we're going to make a psudorandom sequence using python's random module (a mersenne twister) starting with an arbitrary seed, in this case the string "GPS PRN". For later convineience we'll look at this sequence as a square wave from -1 to 1.
random.seed("GPS PRN")
prn_seq = [random.choice([1,-1]) for i in xrange(16)]
print "Our PRN chip:", str(prn_seq).replace('-1','0')
Our PRN chip: [0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1]
# The chipping frequency
f_prn = 10.23e6 / 10
prn = lambda x: prn_seq[int(x*f_prn)%16]
chart.Plot('GPS PRN', tend=16/f_prn, sr=1.0e-8).signal(prn).show()
The transmited GPS signal uses binary phase shift keying, which can be done by multiplying the carefully constructed PRN above with the carrier!
This works because a $sin(x)\times-1 = sin(x-180^o)$, in other words it's exactly a 180 degree phase shift. We should see this as blips in sine wave every time our data changes from 1 to 0 or visa-versa:
signal = lambda x: carrier(x) * prn(x)
chart.Plot('GPS BPSK', tend=8/f_prn, sr=1.0e-10).signal(signal, color=chart.blue).show()
Oops! This is completely indecipherable! The problem is that the carrier is running three orders of magnintude faster than the PRN!!! Unless we zoom into one spot where the phase shift happens we can see anything at this scale.
For the sake of argument lets make the prn modulation much faster.
f_prn = 77 * 10.23e6 #so we can see
chart.Plot('GPS BPSK', tend=16/f_prn, sr=1.0e-11).signal(signal, color=chart.blue).show()
Now we see the phase shifts! To make what's going on even clearer, lets overlay the PRN back on the chart to see how the phase shifts coincide with the edges of our PRN:
f_prn = 77 * 10.23e6 # for now, so we can see
p = chart.Plot('GPS BPSK', tend=16/f_prn, sr=1.0e-11)
p.signal(signal, color=chart.blue)
p.signal(prn, color=chart.red, lw=1, alpha=0.5).show()
This is the basic encoding of a PRN in GPS. But the PRN is made wrong! This was just an example. Read the next post in the series to learn about how to compute the actual GPS PRN's.