Statistics
| Branch: | Tag: | Revision:

gnuradio / gr-digital / examples / example_costas.py @ master

History | View | Annotate | Download (5.19 KB)

1
#!/usr/bin/env python
2
#
3
# Copyright 2011-2013 Free Software Foundation, Inc.
4
#
5
# This file is part of GNU Radio
6
#
7
# GNU Radio is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3, or (at your option)
10
# any later version.
11
#
12
# GNU Radio is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with GNU Radio; see the file COPYING.  If not, write to
19
# the Free Software Foundation, Inc., 51 Franklin Street,
20
# Boston, MA 02110-1301, USA.
21
#
22

23
from gnuradio import gr, digital, filter
24
from gnuradio import blocks
25
from gnuradio import channels
26
from gnuradio import eng_notation
27
from gnuradio.eng_option import eng_option
28
from optparse import OptionParser
29
import sys
30

31
try:
32
    import scipy
33
except ImportError:
34
    print "Error: could not import scipy (http://www.scipy.org/)"
35
    sys.exit(1)
36

37
try:
38
    import pylab
39
except ImportError:
40
    print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
41
    sys.exit(1)
42

43
class example_costas(gr.top_block):
44
    def __init__(self, N, sps, rolloff, ntaps, bw, noise, foffset, toffset, poffset):
45
        gr.top_block.__init__(self)
46

47
        rrc_taps = filter.firdes.root_raised_cosine(
48
            sps, sps, 1.0, rolloff, ntaps)
49

50
        data = 2.0*scipy.random.randint(0, 2, N) - 1.0
51
        data = scipy.exp(1j*poffset) * data
52

53
        self.src = blocks.vector_source_c(data.tolist(), False)
54
        self.rrc = filter.interp_fir_filter_ccf(sps, rrc_taps)
55
        self.chn = channels.channel_model(noise, foffset, toffset)
56
        self.cst = digital.costas_loop_cc(bw, 2)
57

58
        self.vsnk_src = blocks.vector_sink_c()
59
        self.vsnk_cst = blocks.vector_sink_c()
60
        self.vsnk_frq = blocks.vector_sink_f()
61

62
        self.connect(self.src, self.rrc, self.chn, self.cst, self.vsnk_cst)
63
        self.connect(self.rrc, self.vsnk_src)
64
        self.connect((self.cst,1), self.vsnk_frq)
65

66
def main():
67
    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
68
    parser.add_option("-N", "--nsamples", type="int", default=2000,
69
                      help="Set the number of samples to process [default=%default]")
70
    parser.add_option("-S", "--sps", type="int", default=4,
71
                      help="Set the samples per symbol [default=%default]")
72
    parser.add_option("-r", "--rolloff", type="eng_float", default=0.35,
73
                      help="Set the rolloff factor [default=%default]")
74
    parser.add_option("-W", "--bandwidth", type="eng_float", default=2*scipy.pi/100.0,
75
                      help="Set the loop bandwidth [default=%default]")
76
    parser.add_option("-n", "--ntaps", type="int", default=45,
77
                      help="Set the number of taps in the filters [default=%default]")
78
    parser.add_option("", "--noise", type="eng_float", default=0.0,
79
                      help="Set the simulation noise voltage [default=%default]")
80
    parser.add_option("-f", "--foffset", type="eng_float", default=0.0,
81
                      help="Set the simulation's normalized frequency offset (in Hz) [default=%default]")
82
    parser.add_option("-t", "--toffset", type="eng_float", default=1.0,
83
                      help="Set the simulation's timing offset [default=%default]")
84
    parser.add_option("-p", "--poffset", type="eng_float", default=0.707,
85
                      help="Set the simulation's phase offset [default=%default]")
86
    (options, args) = parser.parse_args ()
87

88
    # Adjust N for the interpolation by sps
89
    options.nsamples = options.nsamples // options.sps
90

91
    # Set up the program-under-test
92
    put = example_costas(options.nsamples, options.sps, options.rolloff,
93
                         options.ntaps, options.bandwidth, options.noise,
94
                         options.foffset, options.toffset, options.poffset)
95
    put.run()
96

97
    data_src = scipy.array(put.vsnk_src.data())
98

99
    # Convert the FLL's LO frequency from rads/sec to Hz
100
    data_frq = scipy.array(put.vsnk_frq.data()) / (2.0*scipy.pi)
101

102
    # adjust this to align with the data.
103
    data_cst = scipy.array(3*[0,]+list(put.vsnk_cst.data()))
104

105
    # Plot the Costas loop's LO frequency
106
    f1 = pylab.figure(1, figsize=(12,10), facecolor='w')
107
    s1 = f1.add_subplot(2,2,1)
108
    s1.plot(data_frq)
109
    s1.set_title("Costas LO")
110
    s1.set_xlabel("Samples")
111
    s1.set_ylabel("Frequency (normalized Hz)")
112

113
    # Plot the IQ symbols
114
    s3 = f1.add_subplot(2,2,2)
115
    s3.plot(data_src.real, data_src.imag, "o")
116
    s3.plot(data_cst.real, data_cst.imag, "rx")
117
    s3.set_title("IQ")
118
    s3.set_xlabel("Real part")
119
    s3.set_ylabel("Imag part")
120
    s3.set_xlim([-2, 2])
121
    s3.set_ylim([-2, 2])
122

123
    # Plot the symbols in time
124
    s4 = f1.add_subplot(2,2,3)
125
    s4.set_position([0.125, 0.05, 0.775, 0.4])
126
    s4.plot(data_src.real, "o-")
127
    s4.plot(data_cst.real, "rx-")
128
    s4.set_title("Symbols")
129
    s4.set_xlabel("Samples")
130
    s4.set_ylabel("Real Part of Signals")
131

132
    pylab.show()
133

134
if __name__ == "__main__":
135
    try:
136
        main()
137
    except KeyboardInterrupt:
138
        pass
139