piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- |
Piotr Krysik | a6268a5 | 2017-08-23 16:02:19 +0200 | [diff] [blame] | 3 | # @file |
| 4 | # @author (C) 2014 by Piotr Krysik <ptrkrysik@gmail.com> |
| 5 | # @section LICENSE |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 6 | # |
| 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 | |
| 23 | from numpy import * |
Piotr Krysik | 6985131 | 2014-12-06 20:57:32 +0100 | [diff] [blame] | 24 | #from pylab import * |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 25 | from gnuradio import gr |
| 26 | import pmt |
| 27 | from scipy.ndimage.filters import uniform_filter1d |
| 28 | |
| 29 | class 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] |
ptrkrysik | 2e5b7fb | 2014-12-13 10:11:51 +0100 | [diff] [blame] | 41 | self.sync_seq_msk_interp = zeros(self.OSR*len(self.sync_seq_msk), dtype=complex64) |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 42 | 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)) |
ptrkrysik | 2e5b7fb | 2014-12-13 10:11:51 +0100 | [diff] [blame] | 53 | correlation_bl = zeros(shape(sch_burst_bl), dtype=complex64) |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 54 | 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) |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 58 | power_bl_mov_avg = uniform_filter1d(abs(correlation_bl)**2,self.L+1,mode='constant',axis=0) |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 59 | |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 60 | 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) |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 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) |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 64 | (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 | |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 67 | # 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)) |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 70 | # 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() |
| 82 | print 'r_powmax: ',r_powmax |
| 83 | # plot(abs(correlation_bl[range(r_powmax-(self.L+1)/2+1,r_powmax+(self.L+1)/2+1), c_powmax]),'g') |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 84 | # hold(True) |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 85 | # 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 | |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 88 | def receive(self, input_corr, chan_imp_resp): |
| 89 | pass |
| 90 | |
| 91 | class 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 |
piotr | d8506d6 | 2014-07-20 23:52:57 +0200 | [diff] [blame] | 146 | |
| 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) |
piotr | 6b78abc | 2014-07-08 23:29:13 +0200 | [diff] [blame] | 157 | |