blob: bff7cb7a7c051667338c50c8048b13a4c67db66a [file] [log] [blame]
rppa49a4d22015-10-01 10:44:34 +02001#!/usr/bin/env python
2##################################################
3# Gnuradio Python Flow Graph
4# Title: GSM wideband input adaptor
5# Author: Piotr Krysik
6# Co-author: Pieter Robyns
7# Description: Adaptor of input stream for the GSM receiver. Contains frequency ofset corrector doing also resampling to integer multiplies of GSM sample rate and LP filter filtering GSM channel.
8##################################################
9
10from gnuradio import filter
11from gnuradio import gr
12from gnuradio import eng_notation
13from gnuradio.filter import firdes
14import grgsm.arfcn as arfcn
15import grgsm
16
Piotr Krysik8715da02016-01-06 22:21:09 +010017class gsm_wideband_input(grgsm.hier_block):
Steve Glass5707c2b2016-02-28 10:28:14 +100018 def __init__(self, ppm=0, osr=4, fc=925.2e6, samp_rate_in=20e6, ca=[], band='P-GSM'):
rppa49a4d22015-10-01 10:44:34 +020019 self.num_streams = len(ca)
Piotr Krysik8715da02016-01-06 22:21:09 +010020 grgsm.hier_block.__init__(
rppa49a4d22015-10-01 10:44:34 +020021 self, "GSM wideband input adaptor",
22 gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
23 gr.io_signature(self.num_streams, self.num_streams, gr.sizeof_gr_complex*1),
24 )
25
26 ##################################################
27 # Parameters
28 ##################################################
29 self.ppm = ppm
30 self.osr = osr
31 self.fc = fc
32 self.samp_rate_in = samp_rate_in
33 self.ca = ca
34 self.blocks_fir_filters = {}
35 self.blocks_resamplers = {}
36 self.blocks_ocs = {}
Steve Glass5707c2b2016-02-28 10:28:14 +100037 self.band = band
rppa49a4d22015-10-01 10:44:34 +020038
39 ##################################################
40 # Variables
41 ##################################################
42 self.samp_rate_out = samp_rate_out = 1625000.0/6.0*osr
rppa49a4d22015-10-01 10:44:34 +020043
44 ##################################################
45 # Blocks
46 ##################################################
47 self.ppm_in = None
nightcoffee5edaff02016-02-23 05:51:34 +080048 self.message_port_register_hier_in("ppm_in")
rppa49a4d22015-10-01 10:44:34 +020049 #self.lpf = firdes.low_pass(1, samp_rate_out, 125e3, 5e3, firdes.WIN_HAMMING, 6.76)
50 self.lpf = firdes.low_pass(1, samp_rate_in, 125e3, 75e3, firdes.WIN_HAMMING, 6.76)
51 self.gsm_clock_offset_corrector_0 = grgsm.clock_offset_corrector(
52 fc=fc,
53 ppm=ppm,
54 samp_rate_in=samp_rate_in,
55 )
56
57 c0_arfcn = arfcn.downlink2arfcn(fc, band)
58 print("Extracting channels %s, given that the center frequency is at ARFCN %d (%s)" % (str(ca), c0_arfcn, eng_notation.num_to_str(fc)))
59
60 self.connect((self, 0), (self.gsm_clock_offset_corrector_0, 0))
61
rppa49a4d22015-10-01 10:44:34 +020062 output_port = 0
63 for channel in ca:
64 channel_freq = arfcn.arfcn2downlink(channel, band)
65 if channel_freq is None:
66 print("Warning: invalid ARFCN %d for band %s" % (channel, band))
67 continue
68 freq_diff = channel_freq - fc
69 print("ARFCN %d is at C0 %+d KHz" % (channel, int(freq_diff / 1000.0)))
70
rppa49a4d22015-10-01 10:44:34 +020071 self.blocks_resamplers[channel] = filter.fractional_resampler_cc(0, samp_rate_in/samp_rate_out)
rppd7e8bae2015-10-05 10:48:18 +020072 self.blocks_fir_filters[channel] = filter.freq_xlating_fir_filter_ccc(1, self.lpf, freq_diff, samp_rate_in)
rppa49a4d22015-10-01 10:44:34 +020073 self.connect((self.gsm_clock_offset_corrector_0, 0), (self.blocks_fir_filters[channel], 0))
74 self.connect((self.blocks_fir_filters[channel], 0), (self.blocks_resamplers[channel], 0))
75 self.connect((self.blocks_resamplers[channel], 0), (self, output_port))
76 output_port += 1
77
rppa49a4d22015-10-01 10:44:34 +020078 ##################################################
79 # Asynch Message Connections
80 ##################################################
81 self.msg_connect(self, "ppm_in", self.gsm_clock_offset_corrector_0, "ppm_in")
82
83 def get_ppm(self):
84 return self.ppm
85
86 def set_ppm(self, ppm):
87 self.ppm = ppm
88 self.gsm_clock_offset_corrector_0.set_ppm(self.ppm)
89
90 def get_fc(self):
91 return self.fc
92
93 def set_fc(self, fc):
94 self.fc = fc
95 self.gsm_clock_offset_corrector_0.set_fc(self.fc)
rppd7e8bae2015-10-05 10:48:18 +020096
97 def get_osr(self):
98 return self.osr
99
100 def set_osr(self, osr):
101 self.osr = osr
102 self.set_samp_rate_out(1625000.0/6.0*self.osr)
103
104 def get_samp_rate_in(self):
105 return self.samp_rate_in
106
107 def set_samp_rate_in(self, samp_rate_in):
108 self.samp_rate_in = samp_rate_in
109 for channel in self.blocks_resamplers:
110 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)
111 self.gsm_clock_offset_corrector_0.set_samp_rate_in(self.samp_rate_in)
112
113 def get_samp_rate_out(self):
114 return self.samp_rate_out
115
116 def set_samp_rate_out(self, samp_rate_out):
117 self.samp_rate_out = samp_rate_out
118 for channel in self.blocks_resamplers:
119 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)