blob: 626e37d3f0308ca09273391fd29ea91cadbad662 [file] [log] [blame]
piotr6b78abc2014-07-08 23:29:13 +02001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
Piotr Krysika6268a52017-08-23 16:02:19 +02003# @file
4# @author (C) 2014 by Piotr Krysik <ptrkrysik@gmail.com>
5# @section LICENSE
piotr6b78abc2014-07-08 23:29:13 +02006#
7# This 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# This software 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 this software; see the file COPYING. If not, write to
19# the Free Software Foundation, Inc., 51 Franklin Street,
20# Boston, MA 02110-1301, USA.
21#
22
23from numpy import *
Piotr Krysik69851312014-12-06 20:57:32 +010024#from pylab import *
piotr6b78abc2014-07-08 23:29:13 +020025from gnuradio import gr
26import pmt
27from scipy.ndimage.filters import uniform_filter1d
28
29class sch_receiver():
30 """
31 docstring for class sch_reciever
32 """
33 def __init__(self, OSR):
34 self.sync_seq = array([1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0,
35 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
36 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
37 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1])
38 self.OSR = OSR
39 sync_seq_msk_tmp = self.msk_mod(self.sync_seq, -1j)
40 self.sync_seq_msk = sync_seq_msk_tmp[5:59]
ptrkrysik2e5b7fb2014-12-13 10:11:51 +010041 self.sync_seq_msk_interp = zeros(self.OSR*len(self.sync_seq_msk), dtype=complex64)
piotr6b78abc2014-07-08 23:29:13 +020042 self.sync_seq_msk_interp[::OSR] = self.sync_seq_msk
43 self.L = 5
44
45 def msk_mod(self, x, start_point):
46 x_nrz = 2*x-1
47 x_diffenc = x_nrz[1:]*x_nrz[0:-1]
48 mod_tmp = concatenate((array([start_point]),1j*x_diffenc))
49 return cumprod(mod_tmp)
50
51 def get_chan_imp_resp(self, sch_burst):
52 sch_burst_bl = resize(array(sch_burst), (int(len(sch_burst)/self.OSR),self.OSR))
ptrkrysik2e5b7fb2014-12-13 10:11:51 +010053 correlation_bl = zeros(shape(sch_burst_bl), dtype=complex64)
piotr6b78abc2014-07-08 23:29:13 +020054 for ii in xrange(0,self.OSR):
55 correlation_bl[:,ii]=correlate(sch_burst_bl[:,ii],self.sync_seq_msk,'same')
56
57 correlation_bl = correlation_bl/len(self.sync_seq_msk)
piotrd8506d62014-07-20 23:52:57 +020058 power_bl_mov_avg = uniform_filter1d(abs(correlation_bl)**2,self.L+1,mode='constant',axis=0)
piotr6b78abc2014-07-08 23:29:13 +020059
Vasil Velichkov1789ae22019-08-13 20:32:05 +000060 print("correlation_bl.argmax()",argmax(abs(correlation_bl)))
61 print("power_bl_mov_avg.argmax()",(power_bl_mov_avg).argmax())
62 print('unravel_index(correlation_bl.argmax(), correlation_bl.shape)',unravel_index(argmax(abs(correlation_bl)), correlation_bl.shape))
63 print('unravel_index(power_bl_mov_avg.argmax(), power_bl_mov_avg.shape)',unravel_index(power_bl_mov_avg.argmax(), power_bl_mov_avg.shape))
piotrd8506d62014-07-20 23:52:57 +020064 (r_corrmax, c_corrmax)=unravel_index(argmax(abs(correlation_bl)), correlation_bl.shape)
65 (r_powmax, c_powmax)=unravel_index(power_bl_mov_avg.argmax(), power_bl_mov_avg.shape)
66
piotr6b78abc2014-07-08 23:29:13 +020067# correlation = zeros(shape(sch_burst))
68# correlation = correlate(sch_burst, self.sync_seq_msk_interp,'same')/len(self.sync_seq_msk)
69# print "pozycja maksimum",argmax(abs(correlation))
piotrd8506d62014-07-20 23:52:57 +020070# plot(abs(hstack(correlation_bl))*1000)
71## hold(True)
72## plot(abs(sch_burst)*500)
73## print shape(range(0,len(sch_burst),self.OSR))
74## print shape(correlation_bl[:,0])
75# for ii in range(0,self.OSR):
76# if ii == c_powmax:
77# plot(range(ii,len(correlation_bl[:,0])*self.OSR,self.OSR),power_bl_mov_avg[:,ii]*5e6,'g.')
78# else:
79# plot(range(ii,len(correlation_bl[:,0])*self.OSR,self.OSR),power_bl_mov_avg[:,ii]*5e6,'r.')
80# show()
81# figure()
Vasil Velichkov1789ae22019-08-13 20:32:05 +000082 print('r_powmax: ',r_powmax)
piotrd8506d62014-07-20 23:52:57 +020083# plot(abs(correlation_bl[range(r_powmax-(self.L+1)/2+1,r_powmax+(self.L+1)/2+1), c_powmax]),'g')
piotr6b78abc2014-07-08 23:29:13 +020084# hold(True)
piotrd8506d62014-07-20 23:52:57 +020085# plot(abs(correlation_bl[range(r_corrmax-(self.L+1)/2+1,r_corrmax+(self.L+1)/2+1), c_corrmax]),'r')
86# show()
87
piotr6b78abc2014-07-08 23:29:13 +020088 def receive(self, input_corr, chan_imp_resp):
89 pass
90
91class sch_detector(gr.sync_block):
92 """
93 docstring for block sch_detector
94 """
95 def __init__(self, OSR):
96 gr.sync_block.__init__(self,
97 name="sch_detector",
98 in_sig=[complex64],
99 out_sig=[complex64])
100 self.OSR = OSR
101 self.states = {"waiting_for_fcch_tag":1, "reaching_sch_burst":2, "sch_at_input_buffer":3}
102 self.state = self.states["waiting_for_fcch_tag"]
103 self.sch_offset = -100 #-100 - just some invalid value of sch burst position in the stream
104 self.burst_size = int(round(156.25*self.OSR))
105 self.guard_period = int(round(8.25*self.OSR))
106 self.block_size = self.burst_size + self.guard_period
107 self.set_history(self.block_size)
108 self.set_output_multiple(self.guard_period)
109 self.sch_receiver = sch_receiver(OSR)
110
111 def work(self, input_items, output_items):
112 in0 = input_items[0]
113 out = output_items[0]
114 to_consume = len(in0)-self.history()
115
116 if self.state == self.states["waiting_for_fcch_tag"]:
117 fcch_tags = []
118
119 start = self.nitems_written(0)
120 stop = start + len(in0)
121 key = pmt.string_to_symbol("fcch")
122 fcch_tags = self.get_tags_in_range(0, start, stop, key)
123 if fcch_tags:
124 self.sch_offset = fcch_tags[0].offset + int(round(8*self.burst_size+0*self.guard_period)) #156.25 is number of GMSK symbols per timeslot,
125 #8.25 is arbitrary safety margin in order to avoid cutting boundary of SCH burst
126 self.state = self.states["reaching_sch_burst"]
127
128 elif self.state == self.states["reaching_sch_burst"]:
129 samples_left = self.sch_offset-self.nitems_written(0)
130 if samples_left <= len(in0)-self.history():
131 to_consume = samples_left
132 self.state = self.states["sch_at_input_buffer"]
133
134 elif self.state == self.states["sch_at_input_buffer"]:
135 offset = self.nitems_written(0)
136 key = pmt.string_to_symbol("sch")
137 value = pmt.from_double(0)
138 self.add_item_tag(0,offset, key, value)
139 self.state = self.states["waiting_for_fcch_tag"]
140 self.sch_receiver.get_chan_imp_resp(in0[0:self.block_size+self.guard_period])
141# plot(unwrap(angle(in0[0:2*self.block_size])))
142# show()
143
144 out[:] = in0[self.history()-1:]
145 return to_consume
piotrd8506d62014-07-20 23:52:57 +0200146
147 def get_OSR(self):
148 return self.OSR
149
150 def set_OSR(self, OSR):
151 self.OSR = OSR
152 self.burst_size = int(round(156.25*self.OSR))
153 self.guard_period = int(round(8.25*self.OSR))
154 self.block_size = self.burst_size + self.guard_period
155 self.set_history(self.block_size)
156 self.sch_receiver = sch_receiver(OSR)
piotr6b78abc2014-07-08 23:29:13 +0200157