blob: 962d7b08f54ef2bbd9da075a3ca5db3bdd1fa8c8 [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
Steve Glassd3b40492016-03-03 07:39:57 +100057 center_arfcn = arfcn.downlink2arfcn(fc, band)
58 fc_str = eng_notation.num_to_str(fc)
59 print("Extracting channels %s, given center frequency at %sHz (ARFCN %d)" % (str(ca), fc_str, center_arfcn))
rppa49a4d22015-10-01 10:44:34 +020060
61 self.connect((self, 0), (self.gsm_clock_offset_corrector_0, 0))
62
rppa49a4d22015-10-01 10:44:34 +020063 output_port = 0
64 for channel in ca:
65 channel_freq = arfcn.arfcn2downlink(channel, band)
66 if channel_freq is None:
67 print("Warning: invalid ARFCN %d for band %s" % (channel, band))
68 continue
69 freq_diff = channel_freq - fc
Steve Glassd3b40492016-03-03 07:39:57 +100070 freq_diff_str = "+" if 0 <= freq_diff else ""
71 freq_diff_str += eng_notation.num_to_str(freq_diff)
72 print("ARFCN %d is at %sHz %sHz" % (channel, fc_str, freq_diff_str))
rppa49a4d22015-10-01 10:44:34 +020073
rppa49a4d22015-10-01 10:44:34 +020074 self.blocks_resamplers[channel] = filter.fractional_resampler_cc(0, samp_rate_in/samp_rate_out)
rppd7e8bae2015-10-05 10:48:18 +020075 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 +020076 self.connect((self.gsm_clock_offset_corrector_0, 0), (self.blocks_fir_filters[channel], 0))
77 self.connect((self.blocks_fir_filters[channel], 0), (self.blocks_resamplers[channel], 0))
78 self.connect((self.blocks_resamplers[channel], 0), (self, output_port))
79 output_port += 1
80
rppa49a4d22015-10-01 10:44:34 +020081 ##################################################
82 # Asynch Message Connections
83 ##################################################
84 self.msg_connect(self, "ppm_in", self.gsm_clock_offset_corrector_0, "ppm_in")
85
86 def get_ppm(self):
87 return self.ppm
88
89 def set_ppm(self, ppm):
90 self.ppm = ppm
91 self.gsm_clock_offset_corrector_0.set_ppm(self.ppm)
92
93 def get_fc(self):
94 return self.fc
95
96 def set_fc(self, fc):
97 self.fc = fc
98 self.gsm_clock_offset_corrector_0.set_fc(self.fc)
rppd7e8bae2015-10-05 10:48:18 +020099
100 def get_osr(self):
101 return self.osr
102
103 def set_osr(self, osr):
104 self.osr = osr
105 self.set_samp_rate_out(1625000.0/6.0*self.osr)
106
107 def get_samp_rate_in(self):
108 return self.samp_rate_in
109
110 def set_samp_rate_in(self, samp_rate_in):
111 self.samp_rate_in = samp_rate_in
112 for channel in self.blocks_resamplers:
113 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)
114 self.gsm_clock_offset_corrector_0.set_samp_rate_in(self.samp_rate_in)
115
116 def get_samp_rate_out(self):
117 return self.samp_rate_out
118
119 def set_samp_rate_out(self, samp_rate_out):
120 self.samp_rate_out = samp_rate_out
121 for channel in self.blocks_resamplers:
122 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)