summaryrefslogtreecommitdiff
path: root/gr-digital/examples/example_fll.py
blob: 3b75b5a75896342892cc843abd2b07578de99531 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python

from gnuradio import gr, digital
from gnuradio import eng_notation
from gnuradio.eng_option import eng_option
from optparse import OptionParser

try:
    import scipy
except ImportError:
    print "Error: could not import scipy (http://www.scipy.org/)"
    sys.exit(1)

try:
    import pylab
except ImportError:
    print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
    sys.exit(1)

class example_fll(gr.top_block):
    def __init__(self, N, sps, rolloff, ntaps, bw, noise, foffset, toffset, poffset):
        gr.top_block.__init__(self)

        rrc_taps = gr.firdes.root_raised_cosine(
            sps, sps, 1.0, rolloff, ntaps)

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

        self.src = gr.vector_source_c(data.tolist(), False)
        self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps)
        self.chn = gr.channel_model(noise, foffset, toffset)
        self.fll = digital.fll_band_edge_cc(sps, rolloff, ntaps, bw)

        self.vsnk_src = gr.vector_sink_c()
        self.vsnk_fll = gr.vector_sink_c()
        self.vsnk_frq = gr.vector_sink_f()
        self.vsnk_phs = gr.vector_sink_f()
        self.vsnk_err = gr.vector_sink_f()

        self.connect(self.src, self.rrc, self.chn, self.fll, self.vsnk_fll)
        self.connect(self.rrc, self.vsnk_src)
        self.connect((self.fll,1), self.vsnk_frq)
        self.connect((self.fll,2), self.vsnk_phs)
        self.connect((self.fll,3), self.vsnk_err)

def main():
    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
    parser.add_option("-N", "--nsamples", type="int", default=2000,
                      help="Set the number of samples to process [default=%default]")
    parser.add_option("-S", "--sps", type="int", default=4,
                      help="Set the samples per symbol [default=%default]")
    parser.add_option("-r", "--rolloff", type="eng_float", default=0.35,
                      help="Set the rolloff factor [default=%default]")
    parser.add_option("-W", "--bandwidth", type="eng_float", default=2*scipy.pi/100.0,
                      help="Set the loop bandwidth [default=%default]")
    parser.add_option("-n", "--ntaps", type="int", default=45,
                      help="Set the number of taps in the filters [default=%default]")
    parser.add_option("", "--noise", type="eng_float", default=0.0,
                      help="Set the simulation noise voltage [default=%default]")
    parser.add_option("-f", "--foffset", type="eng_float", default=0.2,
                      help="Set the simulation's normalized frequency offset (in Hz) [default=%default]")
    parser.add_option("-t", "--toffset", type="eng_float", default=1.0,
                      help="Set the simulation's timing offset [default=%default]")
    parser.add_option("-p", "--poffset", type="eng_float", default=0.0,
                      help="Set the simulation's phase offset [default=%default]")
    (options, args) = parser.parse_args ()

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

    # Set up the program-under-test
    put = example_fll(options.nsamples, options.sps, options.rolloff,
                      options.ntaps, options.bandwidth, options.noise,
                      options.foffset, options.toffset, options.poffset)
    put.run()

    data_src = scipy.array(put.vsnk_src.data())
    data_err = scipy.array(put.vsnk_err.data())

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

    # adjust this to align with the data. There are 2 filters of
    # ntaps long and the channel introduces another 4 sample delay.
    data_fll = scipy.array(put.vsnk_fll.data()[2*options.ntaps-4:])
    
    # Plot the FLL's LO frequency
    f1 = pylab.figure(1, figsize=(12,10))
    s1 = f1.add_subplot(2,2,1)
    s1.plot(data_frq)
    s1.set_title("FLL LO")
    s1.set_xlabel("Samples")
    s1.set_ylabel("Frequency (normalized Hz)")

    # Plot the FLL's error
    s2 = f1.add_subplot(2,2,2)
    s2.plot(data_err)
    s2.set_title("FLL Error")
    s2.set_xlabel("Samples")
    s2.set_ylabel("FLL Loop error")

    # Plot the IQ symbols
    s3 = f1.add_subplot(2,2,3)
    s3.plot(data_src.real, data_src.imag, "o")
    s3.plot(data_fll.real, data_fll.imag, "rx")
    s3.set_title("IQ")
    s3.set_xlabel("Real part")
    s3.set_ylabel("Imag part")

    # Plot the symbols in time
    s4 = f1.add_subplot(2,2,4)
    s4.plot(data_src.real, "o-")
    s4.plot(data_fll.real, "rx-")
    s4.set_title("Symbols")
    s4.set_xlabel("Samples")
    s4.set_ylabel("Real Part of Signals")

    pylab.show()
    
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass