aboutsummaryrefslogtreecommitdiffstats
path: root/python/receiver/fcch_burst_tagger.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/receiver/fcch_burst_tagger.py')
-rw-r--r--python/receiver/fcch_burst_tagger.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/python/receiver/fcch_burst_tagger.py b/python/receiver/fcch_burst_tagger.py
new file mode 100644
index 0000000..56fead9
--- /dev/null
+++ b/python/receiver/fcch_burst_tagger.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2014 Piotr Krysik pkrysik@elka.pw.edu.pl
+#
+# This 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.
+#
+# This software 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 this software; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from numpy import *
+from pylab import *
+from gnuradio import gr
+import pmt
+from gsm.chirpz import ZoomFFT
+
+class fcch_burst_tagger(gr.sync_block):
+ """
+ docstring for block fcch_burst_tagger
+ """
+ def __init__(self, OSR):
+ gr.sync_block.__init__(self,
+ name="fcch_burst_tagger",
+ in_sig=[complex64, float32],
+ out_sig=[complex64])
+
+ self.state=False
+ self.symbol_rate = 1625000/6
+ self.OSR=OSR
+ self.samp_rate = self.symbol_rate*OSR
+ self.burst_size = int(156.25*self.OSR)
+ self.guard_period = int(round(8.25*self.OSR))
+ self.block_size = self.burst_size+self.guard_period
+ self.processed_block_size = int(142*self.OSR)
+ self.set_history(self.block_size)
+ self.set_output_multiple(self.guard_period)
+ self.prev_offset=0
+
+ #parameters of zoomfft frequency estimator
+ f1 = self.symbol_rate/4*0.9
+ f2 = self.symbol_rate/4*1.1
+ m=5000*self.OSR
+ self.zoomfft = ZoomFFT(self.processed_block_size, f1, f2, m, Fs=self.samp_rate)
+ self.f_axis = linspace(f1,f2,m)
+
+ def work(self, input_items, output_items):
+ in0=input_items[0]
+ output_items[0][:] = in0[self.history()-1:]
+
+ threshold = input_items[1][self.history()-1:]
+ threshold_diff = diff(concatenate([[0],threshold]))
+ up_to_high_indexes = nonzero(threshold_diff>0)[0]
+
+ up_to_high_idx=[]
+
+ for up_to_high_idx in up_to_high_indexes: #look for "high" value at the trigger
+ if up_to_high_idx==0 and self.state==True: #if it's not transition from "low" to "high"
+ continue #then continue
+ self.state=True #if found - change state
+
+ if self.state==True and up_to_high_idx and any(threshold_diff<0): #and look for transition from high to low
+ last_up_to_high_idx = up_to_high_idx
+ last_high_to_low_idx = nonzero(threshold_diff<0)[0][-1]
+
+ if last_high_to_low_idx-last_up_to_high_idx>0:
+ coarse_idx = int(last_high_to_low_idx+self.history()-self.block_size)
+ 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
+ precise_idx = self.find_best_position(inst_freq)
+# measured_freq = mean(inst_freq[precise_idx:precise_idx+self.processed_block_size])
+ expected_freq = self.symbol_rate/4
+
+ print "input_items:",len(in0)
+ print "coarse_idx",coarse_idx
+ print "coarse_idx+precise_idx",coarse_idx+precise_idx
+
+ zoomed_spectrum = abs(self.zoomfft(in0[coarse_idx+precise_idx:coarse_idx+precise_idx+self.processed_block_size]))
+ measured_freq = self.f_axis[argmax(zoomed_spectrum)]
+ freq_offset = measured_freq - expected_freq
+ offset = self.nitems_written(0) + coarse_idx + precise_idx - self.guard_period
+ key = pmt.string_to_symbol("fcch")
+ value = pmt.from_double(freq_offset)
+ self.add_item_tag(0,offset, key, value)
+ self.state=False
+
+# Some additional plots and prints for debugging
+# print "coarse_idx+precise_idx",coarse_idx+precise_idx
+# print "offset-self.nitems_written(0):",offset-self.nitems_written(0)
+ print offset-self.prev_offset
+ self.prev_offset=offset
+ print "freq offset", freq_offset
+# freq_offset = measured_freq - expected_freq
+# plot(self.f_axis, zoomed_spectrum)
+# show()
+# plot(inst_freq[precise_idx:precise_idx+self.burst_size])
+# show()
+# plot(unwrap(angle(in0[coarse_idx+precise_idx:coarse_idx+precise_idx+self.burst_size])))
+# show()
+#
+ return len(output_items[0])
+
+ def find_best_position(self, inst_freq):
+ lowest_max_min_diff = 1e6 #1e6 - just some large value
+ start_pos = 0
+
+ for ii in xrange(0,int(2*self.guard_period)):
+ min_inst_freq = min(inst_freq[ii:self.processed_block_size+ii-1]);
+ max_inst_freq = max(inst_freq[ii:self.processed_block_size+ii-1]);
+
+ if (lowest_max_min_diff > max_inst_freq - min_inst_freq):
+ lowest_max_min_diff = max_inst_freq - min_inst_freq;
+ start_pos = ii
+# print 'start_pos',start_pos
+
+# plot(xrange(start_pos,start_pos+self.processed_block_size),inst_freq[start_pos:start_pos+self.processed_block_size],'r.')
+# hold(True)
+# plot(inst_freq)
+# show()
+
+ return start_pos