blob: c14f7fb3dd7151a596a3c33baee67fd7c1b44b86 [file] [log] [blame]
piotr6b78abc2014-07-08 23:29:13 +02001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2014 Piotr Krysik pkrysik@elka.pw.edu.pl
5#
6# This is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3, or (at your option)
9# any later version.
10#
11# This software is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this software; see the file COPYING. If not, write to
18# the Free Software Foundation, Inc., 51 Franklin Street,
19# Boston, MA 02110-1301, USA.
20#
21
22from numpy import *
23from pylab import *
24from gnuradio import gr
25import pmt
piotr299ff0e2014-07-20 23:49:48 +020026from gsm.chirpz import ZoomFFT
piotr6b78abc2014-07-08 23:29:13 +020027
28class fcch_burst_tagger(gr.sync_block):
29 """
30 docstring for block fcch_burst_tagger
31 """
32 def __init__(self, OSR):
33 gr.sync_block.__init__(self,
34 name="fcch_burst_tagger",
35 in_sig=[complex64, float32],
36 out_sig=[complex64])
37
38 self.state=False
39 self.symbol_rate = 1625000/6
40 self.OSR=OSR
41 self.samp_rate = self.symbol_rate*OSR
42 self.burst_size = int(156.25*self.OSR)
43 self.guard_period = int(round(8.25*self.OSR))
44 self.block_size = self.burst_size+self.guard_period
45 self.processed_block_size = int(142*self.OSR)
46 self.set_history(self.burst_size)
47 self.set_output_multiple(self.guard_period)
48 self.prev_offset=0
49
50 #parameters of zoomfft frequency estimator
51 f1 = self.symbol_rate/4*0.9
52 f2 = self.symbol_rate/4*1.1
53 m=5000*self.OSR
54 self.zoomfft = ZoomFFT(self.processed_block_size, f1, f2, m, Fs=self.samp_rate)
55 self.f_axis = linspace(f1,f2,m)
56
57 def work(self, input_items, output_items):
58 in0=input_items[0]
59 output_items[0][:] = in0[self.history()-1:]
60
61 threshold = input_items[1][self.history()-1:]
62 threshold_diff = diff(concatenate([[0],threshold]))
63 up_to_high_indexes = nonzero(threshold_diff>0)[0]
64
65 up_to_high_idx=[]
66
67 for up_to_high_idx in up_to_high_indexes: #look for "high" value at the trigger
68 if up_to_high_idx==0 and self.state==True: #if it's not transition from "low" to "high"
69 continue #then continue
70 self.state=True #if found - change state
71
72 if self.state==True and up_to_high_idx and any(threshold_diff<0): #and look for transition from high to low
73 last_up_to_high_idx = up_to_high_idx
74 last_high_to_low_idx = nonzero(threshold_diff<0)[0][-1]
75
76 if last_high_to_low_idx-last_up_to_high_idx>0:
77 coarse_idx = int(last_high_to_low_idx+self.history()-self.guard_period-self.burst_size)
78 inst_freq = angle(in0[coarse_idx:coarse_idx+self.block_size]*in0[coarse_idx-self.OSR:coarse_idx+self.block_size-self.OSR].conj())/(2*pi)*self.symbol_rate #instantaneus frequency estimate
79 precise_idx = self.find_best_position(inst_freq)
80# measured_freq = mean(inst_freq[precise_idx:precise_idx+self.processed_block_size])
81 expected_freq = self.symbol_rate/4
82 zoomed_spectrum = abs(self.zoomfft(in0[coarse_idx+precise_idx:coarse_idx+precise_idx+self.processed_block_size]))
83 measured_freq = self.f_axis[argmax(zoomed_spectrum)]
84 freq_offset = measured_freq - expected_freq
85 offset = self.nitems_written(0) + coarse_idx + precise_idx - self.guard_period
86 key = pmt.string_to_symbol("fcch")
87 value = pmt.from_double(freq_offset)
88 self.add_item_tag(0,offset, key, value)
89 self.state=False
90
91# Some additional plots and prints for debugging
92# print "coarse_idx+precise_idx",coarse_idx+precise_idx
93# print "offset-self.nitems_written(0):",offset-self.nitems_written(0)
94 print offset-self.prev_offset
95 self.prev_offset=offset
96 print "freq offset", freq_offset
97# freq_offset = measured_freq - expected_freq
98# plot(self.f_axis, zoomed_spectrum)
99# show()
100# plot(inst_freq[precise_idx:precise_idx+self.burst_size])
101# show()
102# plot(unwrap(angle(in0[coarse_idx+precise_idx:coarse_idx+precise_idx+self.burst_size])))
103# show()
104#
105 return len(output_items[0])
106
107 def find_best_position(self, inst_freq):
108 lowest_max_min_diff = 1e6 #1e6 - just some large value
109 start_pos = 0
110
111 for ii in xrange(0,int(30*self.OSR)):
112 min_inst_freq = min(inst_freq[ii:self.processed_block_size+ii-1]);
113 max_inst_freq = max(inst_freq[ii:self.processed_block_size+ii-1]);
114
115 if (lowest_max_min_diff > max_inst_freq - min_inst_freq):
116 lowest_max_min_diff = max_inst_freq - min_inst_freq;
117 start_pos = ii
118# print 'start_pos',start_pos
119
120# plot(xrange(start_pos,start_pos+self.processed_block_size),inst_freq[start_pos:start_pos+self.processed_block_size],'r.')
121# hold(True)
122# plot(inst_freq)
123# show()
124
125 return start_pos