diff options
-rw-r--r-- | examples/gsm_fcch_detector.grc | 567 | ||||
-rw-r--r-- | grc/CMakeLists.txt | 5 | ||||
-rw-r--r-- | grc/gsm_fcch_burst_tagger.xml | 28 | ||||
-rw-r--r-- | grc/gsm_fcch_detector.xml | 28 | ||||
-rw-r--r-- | grc/gsm_sch_detector.xml | 24 | ||||
-rw-r--r-- | python/CMakeLists.txt | 5 | ||||
-rw-r--r-- | python/__init__.py | 4 | ||||
-rw-r--r-- | python/fcch_burst_tagger.py | 125 | ||||
-rw-r--r-- | python/fcch_detector.py | 71 | ||||
-rw-r--r-- | python/sch_detector.py | 132 |
10 files changed, 987 insertions, 2 deletions
diff --git a/examples/gsm_fcch_detector.grc b/examples/gsm_fcch_detector.grc new file mode 100644 index 0000000..1d69b53 --- /dev/null +++ b/examples/gsm_fcch_detector.grc @@ -0,0 +1,567 @@ +<?xml version='1.0' encoding='ASCII'?> +<flow_graph> + <timestamp>Tue Jul 8 19:32:53 2014</timestamp> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>samp_rate</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>f_symb*OSR</value> + </param> + <param> + <key>_coordinate</key> + <value>(10, 170)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable</key> + <param> + <key>id</key> + <value>f_symb</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>value</key> + <value>1625000.0/6.0</value> + </param> + <param> + <key>_coordinate</key> + <value>(11, 239)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>parameter</key> + <param> + <key>id</key> + <value>OSR</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>OverSamplingRatio</value> + </param> + <param> + <key>value</key> + <value>4</value> + </param> + <param> + <key>type</key> + <value>intx</value> + </param> + <param> + <key>short_id</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(264, 4)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_complex_to_arg</key> + <param> + <key>id</key> + <value>blocks_complex_to_arg_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(641, 158)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_multiply_conjugate_cc</key> + <param> + <key>id</key> + <value>blocks_multiply_conjugate_cc_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(444, 141)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_delay</key> + <param> + <key>id</key> + <value>blocks_delay_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>delay</key> + <value>int(OSR)</value> + </param> + <param> + <key>num_ports</key> + <value>1</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(319, 171)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_moving_average_xx</key> + <param> + <key>id</key> + <value>blocks_moving_average_xx_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>float</value> + </param> + <param> + <key>length</key> + <value>int((142)*samp_rate/f_symb)</value> + </param> + <param> + <key>scale</key> + <value>1</value> + </param> + <param> + <key>max_iter</key> + <value>int(1e6)</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(971, 138)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_threshold_ff</key> + <param> + <key>id</key> + <value>blocks_threshold_ff_0_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>low</key> + <value>0</value> + </param> + <param> + <key>high</key> + <value>0</value> + </param> + <param> + <key>init</key> + <value>0</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(815, 138)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>pad_source</key> + <param> + <key>id</key> + <value>pad_source_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>in</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>num_streams</key> + <value>1</value> + </param> + <param> + <key>optional</key> + <value>False</value> + </param> + <param> + <key>_coordinate</key> + <value>(155, 137)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>blocks_threshold_ff</key> + <param> + <key>id</key> + <value>blocks_threshold_ff_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>low</key> + <value>int((138)*samp_rate/f_symb)</value> + </param> + <param> + <key>high</key> + <value>int((138)*samp_rate/f_symb)</value> + </param> + <param> + <key>init</key> + <value>0</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(1150, 138)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>gsm_fcch_burst_tagger</key> + <param> + <key>id</key> + <value>gsm_fcch_burst_tagger_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>OSR</key> + <value>OSR</value> + </param> + <param> + <key>affinity</key> + <value></value> + </param> + <param> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>maxoutbuf</key> + <value>0</value> + </param> + <param> + <key>_coordinate</key> + <value>(348, 303)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>pad_sink</key> + <param> + <key>id</key> + <value>pad_sink_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>out</value> + </param> + <param> + <key>type</key> + <value>complex</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>num_streams</key> + <value>1</value> + </param> + <param> + <key>optional</key> + <value>False</value> + </param> + <param> + <key>_coordinate</key> + <value>(584, 316)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>options</key> + <param> + <key>id</key> + <value>fcch_detector</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>title</key> + <value>FCCH Bursts Detector</value> + </param> + <param> + <key>author</key> + <value>Piotr Krysik</value> + </param> + <param> + <key>description</key> + <value>Detects positions of FCCH bursts. At the end of each detected FCCH burst adds to the stream a tag with key "fcch" and value which is a frequency offset estimate. The input sampling frequency should be integer multiply of GSM GMKS symbol rate - 1625000/6 Hz.</value> + </param> + <param> + <key>window_size</key> + <value>1280, 1024</value> + </param> + <param> + <key>generate_options</key> + <value>hb</value> + </param> + <param> + <key>category</key> + <value>GSM</value> + </param> + <param> + <key>run_options</key> + <value>prompt</value> + </param> + <param> + <key>run</key> + <value>True</value> + </param> + <param> + <key>max_nouts</key> + <value>0</value> + </param> + <param> + <key>realtime_scheduling</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(8, 0)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <connection> + <source_block_id>pad_source_0</source_block_id> + <sink_block_id>blocks_multiply_conjugate_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_delay_0</source_block_id> + <sink_block_id>blocks_multiply_conjugate_cc_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> + <connection> + <source_block_id>blocks_complex_to_arg_0</source_block_id> + <sink_block_id>blocks_threshold_ff_0_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>pad_source_0</source_block_id> + <sink_block_id>blocks_delay_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_multiply_conjugate_cc_0</source_block_id> + <sink_block_id>blocks_complex_to_arg_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_moving_average_xx_0</source_block_id> + <sink_block_id>blocks_threshold_ff_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_threshold_ff_0_0</source_block_id> + <sink_block_id>blocks_moving_average_xx_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>gsm_fcch_burst_tagger_0</source_block_id> + <sink_block_id>pad_sink_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>pad_source_0</source_block_id> + <sink_block_id>gsm_fcch_burst_tagger_0</sink_block_id> + <source_key>0</source_key> + <sink_key>0</sink_key> + </connection> + <connection> + <source_block_id>blocks_threshold_ff_0</source_block_id> + <sink_block_id>gsm_fcch_burst_tagger_0</sink_block_id> + <source_key>0</source_key> + <sink_key>1</sink_key> + </connection> +</flow_graph> diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 2c73b8d..6de687a 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -18,5 +18,8 @@ # Boston, MA 02110-1301, USA. install(FILES gsm_receiver_hier.xml - gsm_bursts_printer.xml DESTINATION share/gnuradio/grc/blocks + gsm_bursts_printer.xml + gsm_fcch_burst_tagger.xml + gsm_sch_detector.xml + gsm_fcch_detector.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/gsm_fcch_burst_tagger.xml b/grc/gsm_fcch_burst_tagger.xml new file mode 100644 index 0000000..90f5688 --- /dev/null +++ b/grc/gsm_fcch_burst_tagger.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<block> + <name>fcch_burst_tagger</name> + <key>gsm_fcch_burst_tagger</key> + <category>GSM</category> + <import>import gsm</import> + <make>gsm.fcch_burst_tagger($OSR)</make> + <param> + <name>OSR</name> + <key>OSR</key> + <type>int</type> + </param> + + <sink> + <name>in</name> + <type>complex</type> + </sink> + + <sink> + <name>threshold</name> + <type>float</type> + </sink> + + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/grc/gsm_fcch_detector.xml b/grc/gsm_fcch_detector.xml new file mode 100644 index 0000000..32d5379 --- /dev/null +++ b/grc/gsm_fcch_detector.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<block> + <name>fcch_detector</name> + <key>gsm_fcch_detector</key> + <category>GSM</category> + <import>import gsm</import> + <make>gsm.fcch_detector($OSR)</make> +<callback>set_OSR($OSR)</callback> + <param> + <name>OverSamplingRatio</name> + <key>OSR</key> + <value>4</value> + <type>raw</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + <vlen>1</vlen> + </sink> + <source> + <name>out</name> + <type>complex</type> + <vlen>1</vlen> + </source> + <doc>Piotr Krysik +Detects positions of FCCH bursts. At the end of each detected FCCH burst adds to the stream a tag with key "fcch" and value which is a frequency offset estimate. The input sampling frequency should be integer multiply of GSM GMKS symbol rate - 1625000/6 Hz.</doc> + <grc_source>/home/piotr/Odbiornik_gsm/gr-gsm/examples/gsm_fcch_detector.grc</grc_source> +</block> diff --git a/grc/gsm_sch_detector.xml b/grc/gsm_sch_detector.xml new file mode 100644 index 0000000..7832f4a --- /dev/null +++ b/grc/gsm_sch_detector.xml @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<block> + <name>sch_detector</name> + <key>gsm_sch_detector</key> + <category>GSM</category> + <import>import gsm</import> + <make>gsm.sch_detector($OSR)</make> + <param> + <name>OSR</name> + <key>OSR</key> + <type>int</type> +<!-- <value>OSR</value>--> + </param> + + <sink> + <name>in</name> + <type>complex</type> + </sink> + + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 8640d73..2c76806 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -31,7 +31,10 @@ endif() GR_PYTHON_INSTALL( FILES __init__.py - receiver_hier.py DESTINATION ${GR_PYTHON_DIR}/gsm + receiver_hier.py + fcch_burst_tagger.py + sch_detector.py + fcch_detector.py DESTINATION ${GR_PYTHON_DIR}/gsm ) ######################################################################## diff --git a/python/__init__.py b/python/__init__.py index d6dec38..ee72a0b 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -46,6 +46,10 @@ from gsm_swig import * # import any pure python here from receiver_hier import receiver_hier + +from fcch_burst_tagger import fcch_burst_tagger +from sch_detector import sch_detector +from fcch_detector import fcch_detector # # ---------------------------------------------------------------- diff --git a/python/fcch_burst_tagger.py b/python/fcch_burst_tagger.py new file mode 100644 index 0000000..5142096 --- /dev/null +++ b/python/fcch_burst_tagger.py @@ -0,0 +1,125 @@ +#!/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 scipy.signal.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.burst_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.guard_period-self.burst_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 + 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(30*self.OSR)): + 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 diff --git a/python/fcch_detector.py b/python/fcch_detector.py new file mode 100644 index 0000000..627dd00 --- /dev/null +++ b/python/fcch_detector.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +################################################## +# Gnuradio Python Flow Graph +# Title: FCCH Bursts Detector +# Author: Piotr Krysik +# +# Description: Detects positions of FCCH bursts. At the end of each +# detected FCCH burst adds to the stream a tag with key "fcch" and value +# which is a frequency offset estimate. The input sampling frequency +# should be integer multiply of GSM GMKS symbol rate - 1625000/6 Hz. +################################################## + +from gnuradio import blocks +from gnuradio import gr +from gnuradio.filter import firdes +import gsm + +class fcch_detector(gr.hier_block2): + + def __init__(self, OSR=4): + gr.hier_block2.__init__( + self, "FCCH bursts detector", + gr.io_signature(1, 1, gr.sizeof_gr_complex*1), + gr.io_signature(1, 1, gr.sizeof_gr_complex*1), + ) + + ################################################## + # Parameters + ################################################## + self.OSR = OSR + + ################################################## + # Variables + ################################################## + self.f_symb = f_symb = 1625000.0/6.0 + self.samp_rate = samp_rate = f_symb*OSR + + ################################################## + # Blocks + ################################################## + self.gsm_fcch_burst_tagger_0 = gsm.fcch_burst_tagger(OSR) + self.blocks_threshold_ff_0_0 = blocks.threshold_ff(0, 0, 0) + self.blocks_threshold_ff_0 = blocks.threshold_ff(int((138)*samp_rate/f_symb), int((138)*samp_rate/f_symb), 0) + self.blocks_multiply_conjugate_cc_0 = blocks.multiply_conjugate_cc(1) + self.blocks_moving_average_xx_0 = blocks.moving_average_ff(int((142)*samp_rate/f_symb), 1, int(1e6)) + self.blocks_delay_0 = blocks.delay(gr.sizeof_gr_complex*1, int(OSR)) + self.blocks_complex_to_arg_0 = blocks.complex_to_arg(1) + + ################################################## + # Connections + ################################################## + self.connect((self, 0), (self.blocks_multiply_conjugate_cc_0, 0)) + self.connect((self.blocks_delay_0, 0), (self.blocks_multiply_conjugate_cc_0, 1)) + self.connect((self.blocks_complex_to_arg_0, 0), (self.blocks_threshold_ff_0_0, 0)) + self.connect((self, 0), (self.blocks_delay_0, 0)) + self.connect((self.blocks_multiply_conjugate_cc_0, 0), (self.blocks_complex_to_arg_0, 0)) + self.connect((self.blocks_moving_average_xx_0, 0), (self.blocks_threshold_ff_0, 0)) + self.connect((self.blocks_threshold_ff_0_0, 0), (self.blocks_moving_average_xx_0, 0)) + self.connect((self.gsm_fcch_burst_tagger_0, 0), (self, 0)) + self.connect((self, 0), (self.gsm_fcch_burst_tagger_0, 0)) + self.connect((self.blocks_threshold_ff_0, 0), (self.gsm_fcch_burst_tagger_0, 1)) + + def get_OSR(self): + return self.OSR + + def set_OSR(self, OSR): + self.OSR = OSR + self.set_samp_rate(self.f_symb*self.OSR) + self.blocks_delay_0.set_dly(int(self.OSR)) + + diff --git a/python/sch_detector.py b/python/sch_detector.py new file mode 100644 index 0000000..d80d032 --- /dev/null +++ b/python/sch_detector.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2014 <+YOU OR YOUR COMPANY+>. +# +# 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 scipy.ndimage.filters import uniform_filter1d + +class sch_receiver(): + """ + docstring for class sch_reciever + """ + def __init__(self, OSR): + self.sync_seq = array([1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, + 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1]) + self.OSR = OSR + sync_seq_msk_tmp = self.msk_mod(self.sync_seq, -1j) + self.sync_seq_msk = sync_seq_msk_tmp[5:59] + self.sync_seq_msk_interp = zeros(self.OSR*len(self.sync_seq_msk), dtype=np.complex64) + self.sync_seq_msk_interp[::OSR] = self.sync_seq_msk + self.L = 5 + + def msk_mod(self, x, start_point): + x_nrz = 2*x-1 + x_diffenc = x_nrz[1:]*x_nrz[0:-1] + mod_tmp = concatenate((array([start_point]),1j*x_diffenc)) + return cumprod(mod_tmp) + + def get_chan_imp_resp(self, sch_burst): + sch_burst_bl = resize(array(sch_burst), (int(len(sch_burst)/self.OSR),self.OSR)) + correlation_bl = zeros(shape(sch_burst_bl), dtype=np.complex64) + for ii in xrange(0,self.OSR): + correlation_bl[:,ii]=correlate(sch_burst_bl[:,ii],self.sync_seq_msk,'same') + + correlation_bl = correlation_bl/len(self.sync_seq_msk) + power_bl_mov_avg = uniform_filter1d(abs(correlation_bl)**2,5,mode='constant',axis=0) + + print "correlation_bl.argmax()",argmax(abs(hstack(correlation_bl))) + print "power_bl_mov_avg.argmax()",hstack(power_bl_mov_avg).argmax() + print 'unravel_index(correlation_bl.argmax(), correlation_bl.shape)',unravel_index(correlation_bl.argmax(), correlation_bl.shape) + 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) +# correlation = zeros(shape(sch_burst)) +# correlation = correlate(sch_burst, self.sync_seq_msk_interp,'same')/len(self.sync_seq_msk) +# print "pozycja maksimum",argmax(abs(correlation)) + plot(abs(hstack(correlation_bl))*1000) +# hold(True) +# plot(abs(sch_burst)*500) +# print shape(range(0,len(sch_burst),self.OSR)) +# print shape(correlation_bl[:,0]) + for ii in range(0,self.OSR): + plot(range(ii,len(correlation_bl[:,0])*self.OSR,self.OSR),power_bl_mov_avg[:,ii]*5e6,'r.') + show() + def receive(self, input_corr, chan_imp_resp): + pass + +class sch_detector(gr.sync_block): + """ + docstring for block sch_detector + """ + def __init__(self, OSR): + gr.sync_block.__init__(self, + name="sch_detector", + in_sig=[complex64], + out_sig=[complex64]) + self.OSR = OSR + self.states = {"waiting_for_fcch_tag":1, "reaching_sch_burst":2, "sch_at_input_buffer":3} + self.state = self.states["waiting_for_fcch_tag"] + self.sch_offset = -100 #-100 - just some invalid value of sch burst position in the stream + self.burst_size = int(round(156.25*self.OSR)) + self.guard_period = int(round(8.25*self.OSR)) + self.block_size = self.burst_size + self.guard_period + self.set_history(self.block_size) + self.set_output_multiple(self.guard_period) + self.sch_receiver = sch_receiver(OSR) + + def work(self, input_items, output_items): + in0 = input_items[0] + out = output_items[0] + to_consume = len(in0)-self.history() + + if self.state == self.states["waiting_for_fcch_tag"]: + fcch_tags = [] + + start = self.nitems_written(0) + stop = start + len(in0) + key = pmt.string_to_symbol("fcch") + fcch_tags = self.get_tags_in_range(0, start, stop, key) + if fcch_tags: + 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, + #8.25 is arbitrary safety margin in order to avoid cutting boundary of SCH burst + self.state = self.states["reaching_sch_burst"] + + elif self.state == self.states["reaching_sch_burst"]: + samples_left = self.sch_offset-self.nitems_written(0) + if samples_left <= len(in0)-self.history(): + to_consume = samples_left + self.state = self.states["sch_at_input_buffer"] + + elif self.state == self.states["sch_at_input_buffer"]: + offset = self.nitems_written(0) + key = pmt.string_to_symbol("sch") + value = pmt.from_double(0) + self.add_item_tag(0,offset, key, value) + self.state = self.states["waiting_for_fcch_tag"] + self.sch_receiver.get_chan_imp_resp(in0[0:self.block_size+self.guard_period]) +# plot(unwrap(angle(in0[0:2*self.block_size]))) +# show() + + out[:] = in0[self.history()-1:] + return to_consume + |