def run_test(f, Kb, bitspersymbol, K, dimensionality, constellation, N0, seed, P): tb = gr.top_block() # TX src = gr.lfsr_32k_source_s() src_head = gr.head(gr.sizeof_short, Kb / 16 * P) # packet size in shorts s2fsmi = gr.packed_to_unpacked_ss( bitspersymbol, gr.GR_MSB_FIRST ) # unpack shorts to symbols compatible with the FSM input cardinality s2p = gr.stream_to_streams(gr.sizeof_short, P) # serial to parallel enc = trellis.encoder_ss(f, 0) # initiali state = 0 mod = gr.chunks_to_symbols_sf(constellation, dimensionality) # CHANNEL add = [] noise = [] for i in range(P): add.append(gr.add_ff()) noise.append(gr.noise_source_f(gr.GR_GAUSSIAN, math.sqrt(N0 / 2), seed)) # RX metrics = trellis.metrics_f( f.O(), dimensionality, constellation, digital.TRELLIS_EUCLIDEAN ) # data preprocessing to generate metrics for Viterbi va = trellis.viterbi_s( f, K, 0, -1) # Put -1 if the Initial/Final states are not set. p2s = gr.streams_to_stream(gr.sizeof_short, P) # parallel to serial fsmi2s = gr.unpacked_to_packed_ss( bitspersymbol, gr.GR_MSB_FIRST) # pack FSM input symbols to shorts dst = gr.check_lfsr_32k_s() tb.connect(src, src_head, s2fsmi, s2p) for i in range(P): tb.connect((s2p, i), (enc, i), (mod, i)) tb.connect((mod, i), (add[i], 0)) tb.connect(noise[i], (add[i], 1)) tb.connect(add[i], (metrics, i)) tb.connect((metrics, i), (va, i), (p2s, i)) tb.connect(p2s, fsmi2s, dst) tb.run() # A bit of cheating: run the program once and print the # final encoder state. # Then put it as the last argument in the viterbi block #print "final state = " , enc.ST() ntotal = dst.ntotal() nright = dst.nright() runlength = dst.runlength() return (ntotal, ntotal - nright)
def run_test (f,Kb,bitspersymbol,K,dimensionality,constellation,N0,seed,P): fg = gr.flow_graph () # TX src = gr.lfsr_32k_source_s() src_head = gr.head (gr.sizeof_short,Kb/16*P) # packet size in shorts s2fsmi=gr.packed_to_unpacked_ss(bitspersymbol,gr.GR_MSB_FIRST) # unpack shorts to symbols compatible with the FSM input cardinality s2p = gr.stream_to_streams(gr.sizeof_short,P) # serial to parallel enc = trellis.encoder_ss(f,0) # initiali state = 0 mod = gr.chunks_to_symbols_sf(constellation,dimensionality) # CHANNEL add=[] noise=[] for i in range(P): add.append(gr.add_ff()) noise.append(gr.noise_source_f(gr.GR_GAUSSIAN,math.sqrt(N0/2),seed)) # RX metrics = trellis.metrics_f(f.O(),dimensionality,constellation,trellis.TRELLIS_EUCLIDEAN) # data preprocessing to generate metrics for Viterbi va = trellis.viterbi_s(f,K,0,-1) # Put -1 if the Initial/Final states are not set. p2s = gr.streams_to_stream(gr.sizeof_short,P) # parallel to serial fsmi2s=gr.unpacked_to_packed_ss(bitspersymbol,gr.GR_MSB_FIRST) # pack FSM input symbols to shorts dst = gr.check_lfsr_32k_s() fg.connect (src,src_head,s2fsmi,s2p) for i in range(P): fg.connect ((s2p,i),(enc,i),(mod,i)) fg.connect ((mod,i),(add[i],0)) fg.connect (noise[i],(add[i],1)) fg.connect (add[i],(metrics,i)) fg.connect ((metrics,i),(va,i),(p2s,i)) fg.connect (p2s,fsmi2s,dst) fg.run() # A bit of cheating: run the program once and print the # final encoder state. # Then put it as the last argument in the viterbi block #print "final state = " , enc.ST() ntotal = dst.ntotal () nright = dst.nright () runlength = dst.runlength () return (ntotal,ntotal-nright)
def __init__(self): gr.hier_block2.__init__( self, "interleaver", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self.demux = gr.stream_to_streams(gr.sizeof_char, INTERLEAVER_I) self.shift_registers = [ dvb_swig.fifo_shift_register_bb(INTERLEAVER_M * j) for j in range(INTERLEAVER_I) ] self.mux = gr.streams_to_stream(gr.sizeof_char, INTERLEAVER_I) self.connect(self, self.demux) for j in range(INTERLEAVER_I): self.connect((self.demux, j), self.shift_registers[j], (self.mux, j)) self.connect(self.mux, self)
def test_002(self): # Test streams_to_stream (using stream_to_streams). n = 8 src_len = n * 8 src_data = tuple(range(src_len)) expected_results = src_data src = gr.vector_source_i(src_data) op1 = gr.stream_to_streams(gr.sizeof_int, n) op2 = gr.streams_to_stream(gr.sizeof_int, n) dst = gr.vector_sink_i() self.tb.connect(src, op1) for i in range(n): self.tb.connect((op1, i), (op2, i)) self.tb.connect(op2, dst) self.tb.run() self.assertEqual(expected_results, dst.data())
def test_002(self): """ Test streams_to_stream (using stream_to_streams). """ n = 8 src_len = n * 8 src_data = tuple(range(src_len)) expected_results = src_data src = gr.vector_source_i(src_data) op1 = gr.stream_to_streams(gr.sizeof_int, n) op2 = gr.streams_to_stream(gr.sizeof_int, n) dst = gr.vector_sink_i() self.tb.connect(src, op1) for i in range(n): self.tb.connect((op1, i), (op2, i)) self.tb.connect(op2, dst) self.tb.run() self.assertEqual(expected_results, dst.data())
def test_004(self): """ Test vector_to_streams. """ n = 8 src_len = n * 8 src_data = tuple(range(src_len)) expected_results = src_data src = gr.vector_source_i(src_data) op1 = gr.stream_to_vector(gr.sizeof_int, n) op2 = gr.vector_to_streams(gr.sizeof_int, n) op3 = gr.streams_to_stream(gr.sizeof_int, n) dst = gr.vector_sink_i() self.fg.connect(src, op1, op2) for i in range(n): self.fg.connect((op2, i), (op3, i)) self.fg.connect(op3, dst) self.fg.run() self.assertEqual(expected_results, dst.data())
def __init__(self): gr.hier_block2.__init__( self, "deinterleaver", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self.demux = gr.stream_to_streams(gr.sizeof_char, INTERLEAVER_I) self.shift_registers = [ dvb_swig.fifo_shift_register_bb(INTERLEAVER_M * j) for j in range(INTERLEAVER_I) ] # Deinterleaver shift registers are reversed compared to interleaver self.shift_registers.reverse() self.mux = gr.streams_to_stream(gr.sizeof_char, INTERLEAVER_I) # Remove the uninitialised zeros that come out of the deinterleaver self.skip = gr.skiphead(gr.sizeof_char, DELAY) self.connect(self, self.demux) for j in range(INTERLEAVER_I): self.connect((self.demux, j), self.shift_registers[j], (self.mux, j)) self.connect(self.mux, self.skip, self)
def __init__(self, options): gr.hier_block2.__init__( self, "ais_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char), ) # Output signature self._samples_per_symbol = options.samples_per_symbol self._bits_per_sec = options.bits_per_sec self._samplerate = self._samples_per_symbol * self._bits_per_sec self._gain_mu = options.gain_mu self._mu = options.mu self._omega_relative_limit = options.omega_relative_limit self.fftlen = options.fftlen # right now we are going to hardcode the different options for VA mode here. later on we can use configurable options samples_per_symbol_viterbi = 2 bits_per_symbol = 2 samples_per_symbol = 6 samples_per_symbol_clockrec = samples_per_symbol / bits_per_symbol BT = 0.4 data_rate = 9600.0 samp_rate = options.samp_rate self.gmsk_sync = gmsk_sync.square_and_fft_sync(self._samplerate, self._bits_per_sec, self.fftlen) if options.viterbi is True: # calculate the required decimation and interpolation to achieve the desired samples per symbol denom = gcd(data_rate * samples_per_symbol, samp_rate) cr_interp = int(data_rate * samples_per_symbol / denom) cr_decim = int(samp_rate / denom) self.resample = blks2.rational_resampler_ccc(cr_interp, cr_decim) # here we take a different tack and use A.A.'s CPM decomposition technique self.clockrec = gr.clock_recovery_mm_cc( samples_per_symbol_clockrec, 0.005 * 0.005 * 0.25, 0.5, 0.005, 0.0005 ) # might have to futz with the max. deviation (fsm, constellation, MF, N, f0T) = make_gmsk( samples_per_symbol_viterbi, BT ) # calculate the decomposition required for demodulation self.costas = gr.costas_loop_cc( 0.015, 0.015 * 0.015 * 0.25, 100e-6, -100e-6, 4 ) # does fine freq/phase synchronization. should probably calc the coeffs instead of hardcode them. self.streams2stream = gr.streams_to_stream(int(gr.sizeof_gr_complex * 1), int(N)) self.mf0 = gr.fir_filter_ccc( samples_per_symbol_viterbi, MF[0].conjugate() ) # two matched filters for decomposition self.mf1 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[1].conjugate()) self.fo = gr.sig_source_c( samples_per_symbol_viterbi, gr.GR_COS_WAVE, -f0T, 1, 0 ) # the memoryless modulation component of the decomposition self.fomult = gr.multiply_cc(1) self.trellis = trellis.viterbi_combined_cb( fsm, int(data_rate), -1, -1, int(N), constellation, trellis.TRELLIS_EUCLIDEAN ) # the actual Viterbi decoder else: # this is probably not optimal and someone who knows what they're doing should correct me self.datafiltertaps = gr.firdes.root_raised_cosine( 10, # gain self._samplerate * 32, # sample rate self._bits_per_sec, # symbol rate 0.4, # alpha, same as BT? 50 * 32, ) # no. of taps self.datafilter = gr.fir_filter_fff(1, self.datafiltertaps) sensitivity = (math.pi / 2) / self._samples_per_symbol self.demod = gr.quadrature_demod_cf(sensitivity) # param is gain # self.clockrec = digital.clock_recovery_mm_ff(self._samples_per_symbol,0.25*self._gain_mu*self._gain_mu,self._mu,self._gain_mu,self._omega_relative_limit) self.clockrec = gr.pfb_clock_sync_ccf(self._samples_per_symbol, 0.04, self.datafiltertaps, 32, 0, 1.15) self.tcslicer = digital.digital.binary_slicer_fb() # self.dfe = digital.digital.lms_dd_equalizer_cc( # 32, # 0.005, # 1, # digital.digital.constellation_bpsk() # ) # self.delay = gr.delay(gr.sizeof_float, 64 + 16) #the correlator delays 64 bits, and the LMS delays some as well. self.slicer = digital.digital.binary_slicer_fb() # self.training_correlator = digital.correlate_access_code_bb("1100110011001100", 0) # self.cma = digital.cma_equalizer_cc # just a note here: a complex combined quad demod/slicer could be based on if's rather than an actual quad demod, right? # in fact all the constellation decoders up to QPSK could operate on complex data w/o doing the whole atan thing self.diff = gr.diff_decoder_bb(2) self.invert = ais.invert() # NRZI signal diff decoded and inverted should give original signal self.connect(self, self.gmsk_sync) if options.viterbi is False: self.connect(self.gmsk_sync, self.clockrec, self.demod, self.slicer, self.diff, self.invert, self) # self.connect(self.gmsk_sync, self.demod, self.clockrec, self.tcslicer, self.training_correlator) # self.connect(self.clockrec, self.delay, (self.dfe, 0)) # self.connect(self.training_correlator, (self.dfe, 1)) # self.connect(self.dfe, self.slicer, self.diff, self.invert, self) else: self.connect(self.gmsk_sync, self.costas, self.resample, self.clockrec) self.connect(self.clockrec, (self.fomult, 0)) self.connect(self.fo, (self.fomult, 1)) self.connect(self.fomult, self.mf0) self.connect(self.fomult, self.mf1) self.connect(self.mf0, (self.streams2stream, 0)) self.connect(self.mf1, (self.streams2stream, 1)) self.connect(self.streams2stream, self.trellis, self.diff, self.invert, self)
def run_test(seed, blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0 * K) / P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P, M, L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT = 0.3 tt = numpy.arange(0, L * Q) / (1.0 * Q) - L / 2.0 #print tt p = (0.5 * scipy.stats.erfc(2 * math.pi * BT * (tt - 0.5) / math.sqrt( math.log(2.0)) / math.sqrt(2.0)) - 0.5 * scipy.stats.erfc( 2 * math.pi * BT * (tt + 0.5) / math.sqrt(math.log(2.0)) / math.sqrt(2.0))) / 2.0 p = p / sum(p) * Q / 2.0 #print p q = numpy.cumsum(p) / Q q = q / q[-1] / 2.0 #print q (f0T, SS, S, F, Sf, Ff, N) = fsm_utils.make_cpm_signals(K, P, M, L, q, frac) #print N #print Ff Ffa = numpy.insert(Ff, Q, numpy.zeros(N), axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2, axis=0) Es = numpy.sum(E) / f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf), N * f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0 * EsN0_db) / 10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed * 666) data = numpy.random.randint(0, M, head + blocksize + tail + 1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i] = 0 for i in range(tail + 1): data[-i] = 0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data.tolist(), False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2 * math.pi * h * (1.0 / Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0 / 2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex * 1, int(N)) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex * 1, int(N * (1 + 0))) viterbi = trellis.viterbi_combined_cb(f, head + blocksize + tail, 0, -1, int(N), constellation, digital.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head + i] != dataest[head + i]: #print i err += 1 if err != 0: perr = 1 return (err, perr)
def __init__(self, fg, mpoints, taps=None): """ Takes M complex streams in, produces single complex stream out that runs at M times the input sample rate @param fg: flow_graph @param mpoints: number of freq bins/interpolation factor/subbands @param taps: filter taps for subband filter The channel spacing is equal to the input sample rate. The total bandwidth and output sample rate are equal the input sample rate * nchannels. Output stream to frequency mapping: channel zero is at zero frequency. if mpoints is odd: Channels with increasing positive frequencies come from channels 1 through (N-1)/2. Channel (N+1)/2 is the maximum negative frequency, and frequency increases through N-1 which is one channel lower than the zero frequency. if mpoints is even: Channels with increasing positive frequencies come from channels 1 through (N/2)-1. Channel (N/2) is evenly split between the max positive and negative bins. Channel (N/2)+1 is the maximum negative frequency, and frequency increases through N-1 which is one channel lower than the zero frequency. Channels near the frequency extremes end up getting cut off by subsequent filters and therefore have diminished utility. """ item_size = gr.sizeof_gr_complex if taps is None: taps = _generate_synthesis_taps(mpoints) # pad taps to multiple of mpoints r = len(taps) % mpoints if r != 0: taps = taps + (mpoints - r) * (0,) # split in mpoints separate set of taps sub_taps = _split_taps(taps, mpoints) self.ss2v = gr.streams_to_vector(item_size, mpoints) self.ifft = gr.fft_vcc(mpoints, False, []) self.v2ss = gr.vector_to_streams(item_size, mpoints) # mpoints filters go in here... self.ss2s = gr.streams_to_stream(item_size, mpoints) fg.connect(self.ss2v, self.ifft, self.v2ss) # build mpoints fir filters... for i in range(mpoints): f = gr.fft_filter_ccc(1, sub_taps[i]) fg.connect((self.v2ss, i), f) fg.connect(f, (self.ss2s, i)) gr.hier_block.__init__(self, fg, self.ss2v, self.ss2s)
def run_test(seed,blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0*K)/P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P,M,L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT=0.3; tt=numpy.arange(0,L*Q)/(1.0*Q)-L/2.0; #print tt p=(0.5*scipy.stats.erfc(2*math.pi*BT*(tt-0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0))-0.5*scipy.stats.erfc(2*math.pi*BT*(tt+0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0)))/2.0; p=p/sum(p)*Q/2.0; #print p q=numpy.cumsum(p)/Q; q=q/q[-1]/2.0; #print q (f0T,SS,S,F,Sf,Ff,N) = fsm_utils.make_cpm_signals(K,P,M,L,q,frac) #print N #print Ff Ffa = numpy.insert(Ff,Q,numpy.zeros(N),axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2,axis=0) Es = numpy.sum(E)/f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf),N*f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0*EsN0_db)/10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed*666) data = numpy.random.randint(0, M, head+blocksize+tail+1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i]=0 for i in range(tail+1): data[-i]=0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data, False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0/2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, N) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, N*(1+0)) viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, N, constellation, trellis.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head+i] != dataest[head+i]: #print i err += 1 if err != 0 : perr = 1 return (err,perr)
def __init__(self, options): gr.hier_block2.__init__(self, "ais_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature self._samples_per_symbol = options.samples_per_symbol self._bits_per_sec = options.bits_per_sec self._samplerate = self._samples_per_symbol * self._bits_per_sec self._gain_mu = options.gain_mu self._mu = options.mu self._omega_relative_limit = options.omega_relative_limit self.fftlen = options.fftlen #right now we are going to hardcode the different options for VA mode here. later on we can use configurable options samples_per_symbol_viterbi = 2 bits_per_symbol = 2 samples_per_symbol = 6 samples_per_symbol_clockrec = samples_per_symbol / bits_per_symbol BT = 0.4 data_rate = 9600.0 samp_rate = options.samp_rate self.gmsk_sync = gmsk_sync.square_and_fft_sync(self._samplerate, self._bits_per_sec, self.fftlen) if(options.viterbi is True): #calculate the required decimation and interpolation to achieve the desired samples per symbol denom = gcd(data_rate*samples_per_symbol, samp_rate) cr_interp = int(data_rate*samples_per_symbol/denom) cr_decim = int(samp_rate/denom) self.resample = blks2.rational_resampler_ccc(cr_interp, cr_decim) #here we take a different tack and use A.A.'s CPM decomposition technique self.clockrec = gr.clock_recovery_mm_cc(samples_per_symbol_clockrec, 0.005*0.005*0.25, 0.5, 0.005, 0.0005) #might have to futz with the max. deviation (fsm, constellation, MF, N, f0T) = make_gmsk(samples_per_symbol_viterbi, BT) #calculate the decomposition required for demodulation self.costas = gr.costas_loop_cc(0.015, 0.015*0.015*0.25, 100e-6, -100e-6, 4) #does fine freq/phase synchronization. should probably calc the coeffs instead of hardcode them. self.streams2stream = gr.streams_to_stream(int(gr.sizeof_gr_complex*1), int(N)) self.mf0 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[0].conjugate()) #two matched filters for decomposition self.mf1 = gr.fir_filter_ccc(samples_per_symbol_viterbi, MF[1].conjugate()) self.fo = gr.sig_source_c(samples_per_symbol_viterbi, gr.GR_COS_WAVE, -f0T, 1, 0) #the memoryless modulation component of the decomposition self.fomult = gr.multiply_cc(1) self.trellis = trellis.viterbi_combined_cb(fsm, int(data_rate), -1, -1, int(N), constellation, trellis.TRELLIS_EUCLIDEAN) #the actual Viterbi decoder else: #this is probably not optimal and someone who knows what they're doing should correct me self.datafiltertaps = gr.firdes.root_raised_cosine(10, #gain self._samplerate*32, #sample rate self._bits_per_sec, #symbol rate 0.4, #alpha, same as BT? 50*32) #no. of taps self.datafilter = gr.fir_filter_fff(1, self.datafiltertaps) sensitivity = (math.pi / 2) / self._samples_per_symbol self.demod = gr.quadrature_demod_cf(sensitivity) #param is gain #self.clockrec = digital.clock_recovery_mm_ff(self._samples_per_symbol,0.25*self._gain_mu*self._gain_mu,self._mu,self._gain_mu,self._omega_relative_limit) self.clockrec = gr.pfb_clock_sync_ccf(self._samples_per_symbol, 0.04, self.datafiltertaps, 32, 0, 1.15) self.tcslicer = digital.digital.binary_slicer_fb() # self.dfe = digital.digital.lms_dd_equalizer_cc( # 32, # 0.005, # 1, # digital.digital.constellation_bpsk() # ) # self.delay = gr.delay(gr.sizeof_float, 64 + 16) #the correlator delays 64 bits, and the LMS delays some as well. self.slicer = digital.digital.binary_slicer_fb() # self.training_correlator = digital.correlate_access_code_bb("1100110011001100", 0) # self.cma = digital.cma_equalizer_cc #just a note here: a complex combined quad demod/slicer could be based on if's rather than an actual quad demod, right? #in fact all the constellation decoders up to QPSK could operate on complex data w/o doing the whole atan thing self.diff = gr.diff_decoder_bb(2) self.invert = ais.invert() #NRZI signal diff decoded and inverted should give original signal self.connect(self, self.gmsk_sync) if(options.viterbi is False): self.connect(self.gmsk_sync, self.clockrec, self.demod, self.slicer, self.diff, self.invert, self) #self.connect(self.gmsk_sync, self.demod, self.clockrec, self.tcslicer, self.training_correlator) #self.connect(self.clockrec, self.delay, (self.dfe, 0)) #self.connect(self.training_correlator, (self.dfe, 1)) #self.connect(self.dfe, self.slicer, self.diff, self.invert, self) else: self.connect(self.gmsk_sync, self.costas, self.resample, self.clockrec) self.connect(self.clockrec, (self.fomult, 0)) self.connect(self.fo, (self.fomult, 1)) self.connect(self.fomult, self.mf0) self.connect(self.fomult, self.mf1) self.connect(self.mf0, (self.streams2stream, 0)) self.connect(self.mf1, (self.streams2stream, 1)) self.connect(self.streams2stream, self.trellis, self.diff, self.invert, self)
def __init__(self, mpoints, taps=None): """ Takes M complex streams in, produces single complex stream out that runs at M times the input sample rate @param mpoints: number of freq bins/interpolation factor/subbands @param taps: filter taps for subband filter The channel spacing is equal to the input sample rate. The total bandwidth and output sample rate are equal the input sample rate * nchannels. Output stream to frequency mapping: channel zero is at zero frequency. if mpoints is odd: Channels with increasing positive frequencies come from channels 1 through (N-1)/2. Channel (N+1)/2 is the maximum negative frequency, and frequency increases through N-1 which is one channel lower than the zero frequency. if mpoints is even: Channels with increasing positive frequencies come from channels 1 through (N/2)-1. Channel (N/2) is evenly split between the max positive and negative bins. Channel (N/2)+1 is the maximum negative frequency, and frequency increases through N-1 which is one channel lower than the zero frequency. Channels near the frequency extremes end up getting cut off by subsequent filters and therefore have diminished utility. """ item_size = gr.sizeof_gr_complex gr.hier_block2.__init__(self, "synthesis_filterbank", gr.io_signature(mpoints, mpoints, item_size), # Input signature gr.io_signature(1, 1, item_size)) # Output signature if taps is None: taps = _generate_synthesis_taps(mpoints) # pad taps to multiple of mpoints r = len(taps) % mpoints if r != 0: taps = taps + (mpoints - r) * (0,) # split in mpoints separate set of taps sub_taps = _split_taps(taps, mpoints) self.ss2v = gr.streams_to_vector(item_size, mpoints) self.ifft = gr.fft_vcc(mpoints, False, []) self.v2ss = gr.vector_to_streams(item_size, mpoints) # mpoints filters go in here... self.ss2s = gr.streams_to_stream(item_size, mpoints) for i in range(mpoints): self.connect((self, i), (self.ss2v, i)) self.connect(self.ss2v, self.ifft, self.v2ss) # build mpoints fir filters... for i in range(mpoints): f = gr.fft_filter_ccc(1, sub_taps[i]) self.connect((self.v2ss, i), f) self.connect(f, (self.ss2s, i)) self.connect(self.ss2s, self)