aboutsummaryrefslogtreecommitdiffstats
path: root/python/receiver/gsm_wideband_input.py
blob: 633ead22c2ef1fbbfe5b126087c0811965bf00b7 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# @file
# @author Piotr Krysik <ptrkrysik@gmail.com>
# @section LICENSE
#
# Gr-gsm is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# Gr-gsm is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with gr-gsm; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
##################################################
# Gnuradio Python Flow Graph
# Title: GSM wideband input adaptor
# Author: Piotr Krysik
# Co-author: Pieter Robyns
# 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.
##################################################

from gnuradio import filter
from gnuradio import gr
from gnuradio import eng_notation
from gnuradio.filter import firdes
import grgsm.arfcn as arfcn
import grgsm

class gsm_wideband_input(grgsm.hier_block):
    def __init__(self, ppm=0, osr=4, fc=925.2e6, samp_rate_in=20e6, ca=[], band='P-GSM'):
        self.num_streams = len(ca)
        grgsm.hier_block.__init__(
            self, "GSM wideband input adaptor",
            gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
            gr.io_signature(self.num_streams, self.num_streams, gr.sizeof_gr_complex*1),
        )

        ##################################################
        # Parameters
        ##################################################
        self.ppm = ppm
        self.osr = osr
        self.fc = fc
        self.samp_rate_in = samp_rate_in
        self.ca = ca
        self.blocks_fir_filters = {}
        self.blocks_resamplers = {}
        self.blocks_ocs = {}
        self.band = band

        ##################################################
        # Variables
        ##################################################
        self.samp_rate_out = samp_rate_out = 1625000.0/6.0*osr

        ##################################################
        # Blocks
        ##################################################
        self.ppm_in = None
        self.message_port_register_hier_in("ppm_in")
        #self.lpf = firdes.low_pass(1, samp_rate_out, 125e3, 5e3, firdes.WIN_HAMMING, 6.76)
        self.lpf = firdes.low_pass(1, samp_rate_in, 125e3, 75e3, firdes.WIN_HAMMING, 6.76)
        self.gsm_clock_offset_corrector_0 = grgsm.clock_offset_corrector(
            fc=fc,
            ppm=ppm,
            samp_rate_in=samp_rate_in,
        )

        center_arfcn = arfcn.downlink2arfcn(fc, band)
        fc_str = eng_notation.num_to_str(fc)
        print("Extracting channels %s, given center frequency at %sHz (ARFCN %d)" % (str(ca), fc_str, center_arfcn))

        self.connect((self, 0), (self.gsm_clock_offset_corrector_0, 0))

        output_port = 0
        for channel in ca:
            channel_freq = arfcn.arfcn2downlink(channel, band)
            if channel_freq is None:
                print("Warning: invalid ARFCN %d for band %s" % (channel, band))
                continue
            freq_diff = channel_freq - fc
            freq_diff_str = "+" if 0 <= freq_diff else ""
            freq_diff_str += eng_notation.num_to_str(freq_diff)
            print("ARFCN %d is at %sHz %sHz" % (channel, fc_str, freq_diff_str))

            self.blocks_resamplers[channel] = filter.fractional_resampler_cc(0, samp_rate_in/samp_rate_out)
            self.blocks_fir_filters[channel] = filter.freq_xlating_fir_filter_ccc(1, self.lpf, freq_diff, samp_rate_in)
            self.connect((self.gsm_clock_offset_corrector_0, 0), (self.blocks_fir_filters[channel], 0))
            self.connect((self.blocks_fir_filters[channel], 0), (self.blocks_resamplers[channel], 0))
            self.connect((self.blocks_resamplers[channel], 0), (self, output_port))
            output_port += 1

        ##################################################
        # Asynch Message Connections
        ##################################################
        self.msg_connect(self, "ppm_in", self.gsm_clock_offset_corrector_0, "ppm_in")

    def get_ppm(self):
        return self.ppm

    def set_ppm(self, ppm):
        self.ppm = ppm
        self.gsm_clock_offset_corrector_0.set_ppm(self.ppm)

    def get_fc(self):
        return self.fc

    def set_fc(self, fc):
        self.fc = fc
        self.gsm_clock_offset_corrector_0.set_fc(self.fc)

    def get_osr(self):
        return self.osr

    def set_osr(self, osr):
        self.osr = osr
        self.set_samp_rate_out(1625000.0/6.0*self.osr)

    def get_samp_rate_in(self):
        return self.samp_rate_in

    def set_samp_rate_in(self, samp_rate_in):
        self.samp_rate_in = samp_rate_in
        for channel in self.blocks_resamplers:
            self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)
        self.gsm_clock_offset_corrector_0.set_samp_rate_in(self.samp_rate_in)

    def get_samp_rate_out(self):
        return self.samp_rate_out

    def set_samp_rate_out(self, samp_rate_out):
        self.samp_rate_out = samp_rate_out
        for channel in self.blocks_resamplers:
            self.blocks_resamplers[channel].set_resamp_ratio(self.samp_rate_in / self.samp_rate_out)