Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-examples / python / digital-bert / receive_path.py
1 #
2 # Copyright 2008 Free Software Foundation, Inc.
3 #
4 # This file is part of GNU Radio
5 #
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10 #
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20 #
21
22 from gnuradio import gr, eng_notation
23 import math
24
25 n2s = eng_notation.num_to_str
26
27 class receive_path(gr.hier_block2):
28     def __init__(self,
29                  if_rate,        # Incoming sample rate
30                  symbol_rate,    # Original symbol rate
31                  excess_bw,      # RRC excess bandwidth, typically 0.35-0.5
32                  costas_alpha,   # Costas loop 1st order gain, typically 0.01-0.2
33                  costas_beta,    # Costas loop 2nd order gain, typically alpha^2/4.0
34                  costas_max,     # Costas loop max frequency offset in radians/sample
35                  mm_gain_mu,     # M&M loop 1st order gain, typically 0.001-0.2
36                  mm_gain_omega,  # M&M loop 2nd order gain, typically alpha^2/4.0
37                  mm_omega_limit, # M&M loop max timing error
38                  ):
39         
40         gr.hier_block2.__init__(self, "receive_path",
41                                 gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
42                                 gr.io_signature(0, 0, 0))                    # Output signature
43
44         self._if_rate = if_rate
45         self._sps = int(self._if_rate/symbol_rate)
46         print "IF sample rate:", n2s(self._if_rate)
47         print "Symbol rate:", n2s(symbol_rate)
48         print "Samples/symbol:", self._sps
49         print "RRC bandwidth:", excess_bw
50         
51         # Create AGC to scale input to unity
52         self._agc = gr.agc_cc(1e-5, 1.0, 1.0, 1.0)
53
54         # Create RRC with specified excess bandwidth
55         taps = gr.firdes.root_raised_cosine(1.0,          # Gain
56                                             self._sps,    # Sampling rate
57                                             1.0,          # Symbol rate
58                                             excess_bw,    # Roll-off factor
59                                             11*self._sps) # Number of taps
60
61         self._rrc = gr.fir_filter_ccf(1, taps)
62         
63         # Create a Costas loop frequency/phase recovery block
64
65         print "Costas alpha:", costas_alpha
66         print "Costas beta:", costas_beta
67         print "Costas max:", costas_max
68         
69         self._costas = gr.costas_loop_cc(costas_alpha,  # PLL first order gain
70                                          costas_beta,   # PLL second order gain
71                                          costas_max,    # Max frequency offset rad/sample
72                                          -costas_max,   # Min frequency offset rad/sample
73                                          2)             # BPSK
74
75         # Create a M&M bit synchronization retiming block
76         mm_mu = 0.5
77         mm_omega = self._sps
78
79         print "MM gain mu:", mm_gain_mu
80         print "MM gain omega:", mm_gain_omega
81         print "MM omega limit:", mm_omega_limit
82         
83         self._mm = gr.clock_recovery_mm_cc(mm_omega,       # Initial samples/symbol
84                                            mm_gain_omega,  # Second order gain
85                                            mm_mu,          # Initial symbol phase
86                                            mm_gain_mu,     # First order gain
87                                            mm_omega_limit) # Maximum timing offset
88
89         # Add an SNR probe on the demodulated constellation
90         self._snr_probe = gr.probe_mpsk_snr_c(10.0/symbol_rate)
91         self.connect(self._mm, self._snr_probe)
92         
93         # Slice the resulting constellation into bits.
94         # Get inphase channel and make decision about 0
95         self._c2r = gr.complex_to_real()
96         self._slicer = gr.binary_slicer_fb() 
97         
98         # Descramble BERT sequence.  A channel error will create 3 incorrect bits
99         self._descrambler = gr.descrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit descrambler
100
101         # Measure BER by the density of 0s in the stream
102         self._ber = gr.probe_density_b(1.0/symbol_rate)
103
104         self.connect(self, self._agc, self._rrc, self._costas, self._mm, 
105                      self._c2r, self._slicer, self._descrambler, self._ber)
106
107     def frequency_offset(self):
108         return self._costas.freq()*self._if_rate/(2*math.pi)
109
110     def timing_offset(self):
111         return self._mm.omega()/self._sps-1.0
112
113     def snr(self):
114         return self._snr_probe.snr()
115
116     def ber(self):
117         return (1.0-self._ber.density())/3.0
118