blob: 633ead22c2ef1fbbfe5b126087c0811965bf00b7 [file] [log] [blame]
Piotr Krysikea34c012016-10-02 18:53:43 +02001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
3# @file
4# @author Piotr Krysik <ptrkrysik@gmail.com>
5# @section LICENSE
6#
7# Gr-gsm 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# Gr-gsm 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 gr-gsm; see the file COPYING. If not, write to
19# the Free Software Foundation, Inc., 51 Franklin Street,
20# Boston, MA 02110-1301, USA.
21#
rppa49a4d22015-10-01 10:44:34 +020022##################################################
23# Gnuradio Python Flow Graph
24# Title: GSM wideband input adaptor
25# Author: Piotr Krysik
26# Co-author: Pieter Robyns
27# 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.
28##################################################
29
30from gnuradio import filter
31from gnuradio import gr
32from gnuradio import eng_notation
33from gnuradio.filter import firdes
34import grgsm.arfcn as arfcn
35import grgsm
36
Piotr Krysik8715da02016-01-06 22:21:09 +010037class gsm_wideband_input(grgsm.hier_block):
Steve Glass5707c2b2016-02-28 10:28:14 +100038 def __init__(self, ppm=0, osr=4, fc=925.2e6, samp_rate_in=20e6, ca=[], band='P-GSM'):
rppa49a4d22015-10-01 10:44:34 +020039 self.num_streams = len(ca)
Piotr Krysik8715da02016-01-06 22:21:09 +010040 grgsm.hier_block.__init__(
rppa49a4d22015-10-01 10:44:34 +020041 self, "GSM wideband input adaptor",
42 gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
43 gr.io_signature(self.num_streams, self.num_streams, gr.sizeof_gr_complex*1),
44 )
45
46 ##################################################
47 # Parameters
48 ##################################################
49 self.ppm = ppm
50 self.osr = osr
51 self.fc = fc
52 self.samp_rate_in = samp_rate_in
53 self.ca = ca
54 self.blocks_fir_filters = {}
55 self.blocks_resamplers = {}
56 self.blocks_ocs = {}
Steve Glass5707c2b2016-02-28 10:28:14 +100057 self.band = band
rppa49a4d22015-10-01 10:44:34 +020058
59 ##################################################
60 # Variables
61 ##################################################
62 self.samp_rate_out = samp_rate_out = 1625000.0/6.0*osr
rppa49a4d22015-10-01 10:44:34 +020063
64 ##################################################
65 # Blocks
66 ##################################################
67 self.ppm_in = None
nightcoffee5edaff02016-02-23 05:51:34 +080068 self.message_port_register_hier_in("ppm_in")
rppa49a4d22015-10-01 10:44:34 +020069 #self.lpf = firdes.low_pass(1, samp_rate_out, 125e3, 5e3, firdes.WIN_HAMMING, 6.76)
70 self.lpf = firdes.low_pass(1, samp_rate_in, 125e3, 75e3, firdes.WIN_HAMMING, 6.76)
71 self.gsm_clock_offset_corrector_0 = grgsm.clock_offset_corrector(
72 fc=fc,
73 ppm=ppm,
74 samp_rate_in=samp_rate_in,
75 )
76
Steve Glassd3b40492016-03-03 07:39:57 +100077 center_arfcn = arfcn.downlink2arfcn(fc, band)
78 fc_str = eng_notation.num_to_str(fc)
79 print("Extracting channels %s, given center frequency at %sHz (ARFCN %d)" % (str(ca), fc_str, center_arfcn))
rppa49a4d22015-10-01 10:44:34 +020080
81 self.connect((self, 0), (self.gsm_clock_offset_corrector_0, 0))
82
rppa49a4d22015-10-01 10:44:34 +020083 output_port = 0
84 for channel in ca:
85 channel_freq = arfcn.arfcn2downlink(channel, band)
86 if channel_freq is None:
87 print("Warning: invalid ARFCN %d for band %s" % (channel, band))
88 continue
89 freq_diff = channel_freq - fc
Steve Glassd3b40492016-03-03 07:39:57 +100090 freq_diff_str = "+" if 0 <= freq_diff else ""
91 freq_diff_str += eng_notation.num_to_str(freq_diff)
92 print("ARFCN %d is at %sHz %sHz" % (channel, fc_str, freq_diff_str))
rppa49a4d22015-10-01 10:44:34 +020093
rppa49a4d22015-10-01 10:44:34 +020094 self.blocks_resamplers[channel] = filter.fractional_resampler_cc(0, samp_rate_in/samp_rate_out)
rppd7e8bae2015-10-05 10:48:18 +020095 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 +020096 self.connect((self.gsm_clock_offset_corrector_0, 0), (self.blocks_fir_filters[channel], 0))
97 self.connect((self.blocks_fir_filters[channel], 0), (self.blocks_resamplers[channel], 0))
98 self.connect((self.blocks_resamplers[channel], 0), (self, output_port))
99 output_port += 1
100
rppa49a4d22015-10-01 10:44:34 +0200101 ##################################################
102 # Asynch Message Connections
103 ##################################################
104 self.msg_connect(self, "ppm_in", self.gsm_clock_offset_corrector_0, "ppm_in")
105
106 def get_ppm(self):
107 return self.ppm
108
109 def set_ppm(self, ppm):
110 self.ppm = ppm
111 self.gsm_clock_offset_corrector_0.set_ppm(self.ppm)
112
113 def get_fc(self):
114 return self.fc
115
116 def set_fc(self, fc):
117 self.fc = fc
118 self.gsm_clock_offset_corrector_0.set_fc(self.fc)
rppd7e8bae2015-10-05 10:48:18 +0200119
120 def get_osr(self):
121 return self.osr
122
123 def set_osr(self, osr):
124 self.osr = osr
125 self.set_samp_rate_out(1625000.0/6.0*self.osr)
126
127 def get_samp_rate_in(self):
128 return self.samp_rate_in
129
130 def set_samp_rate_in(self, samp_rate_in):
131 self.samp_rate_in = samp_rate_in
132 for channel in self.blocks_resamplers:
133 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)
134 self.gsm_clock_offset_corrector_0.set_samp_rate_in(self.samp_rate_in)
135
136 def get_samp_rate_out(self):
137 return self.samp_rate_out
138
139 def set_samp_rate_out(self, samp_rate_out):
140 self.samp_rate_out = samp_rate_out
141 for channel in self.blocks_resamplers:
142 self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)