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.special.erfc(2*math.pi*BT*(tt-0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0))-0.5*scipy.special.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 = blocks.vector_source_b(data.tolist(), False) digital_chunks_to_symbols_xx_0 = digital.chunks_to_symbols_bf((-1, 1), 1) filter_interp_fir_filter_xxx_0 = filter.interp_fir_filter_fff(Q, p) analog_frequency_modulator_fc_0 = analog.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) blocks_add_vxx_0 = blocks.add_vcc(1) analog_noise_source_x_0 = analog.noise_source_c(analog.GR_GAUSSIAN, (N0/2.0)**0.5, -long(seed)) blocks_multiply_vxx_0 = blocks.multiply_vcc(1) analog_sig_source_x_0 = analog.sig_source_c(Q, analog.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... filter_fir_filter_xxx_0_0 = filter.fir_filter_ccc(Q, MF[0].conjugate()) filter_fir_filter_xxx_0_0_0 = filter.fir_filter_ccc(Q, MF[1].conjugate()) blocks_streams_to_stream_0 = blocks.streams_to_stream(gr.sizeof_gr_complex*1, int(N)) blocks_skiphead_0 = blocks.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) blocks_vector_sink_x_0 = blocks.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (digital_chunks_to_symbols_xx_0, 0)) tb.connect((digital_chunks_to_symbols_xx_0, 0), (filter_interp_fir_filter_xxx_0, 0)) tb.connect((filter_interp_fir_filter_xxx_0, 0), (analog_frequency_modulator_fc_0, 0)) tb.connect((analog_frequency_modulator_fc_0, 0), (blocks_add_vxx_0, 0)) tb.connect((analog_noise_source_x_0, 0), (blocks_add_vxx_0, 1)) tb.connect((blocks_add_vxx_0, 0), (blocks_multiply_vxx_0, 0)) tb.connect((analog_sig_source_x_0, 0), (blocks_multiply_vxx_0, 1)) tb.connect((blocks_multiply_vxx_0, 0), (filter_fir_filter_xxx_0_0, 0)) tb.connect((blocks_multiply_vxx_0, 0), (filter_fir_filter_xxx_0_0_0, 0)) tb.connect((filter_fir_filter_xxx_0_0, 0), (blocks_streams_to_stream_0, 0)) tb.connect((filter_fir_filter_xxx_0_0_0, 0), (blocks_streams_to_stream_0, 1)) tb.connect((blocks_streams_to_stream_0, 0), (blocks_skiphead_0, 0)) tb.connect((blocks_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (blocks_vector_sink_x_0, 0)) tb.run() dataest = blocks_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): gr.top_block.__init__(self, "Superposition Coding") Qt.QWidget.__init__(self) self.setWindowTitle("Superposition Coding") qtgui.util.check_set_qss() try: self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) except: pass self.top_scroll_layout = Qt.QVBoxLayout() self.setLayout(self.top_scroll_layout) self.top_scroll = Qt.QScrollArea() self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) self.top_scroll_layout.addWidget(self.top_scroll) self.top_scroll.setWidgetResizable(True) self.top_widget = Qt.QWidget() self.top_scroll.setWidget(self.top_widget) self.top_layout = Qt.QVBoxLayout(self.top_widget) self.top_grid_layout = Qt.QGridLayout() self.top_layout.addLayout(self.top_grid_layout) self.settings = Qt.QSettings("GNU Radio", "int_cancellation") self.restoreGeometry(self.settings.value("geometry").toByteArray()) ################################################## # Variables ################################################## self.snr_db = snr_db = 10 self.prefix = prefix = "/opt/usr/src/gnuradio/gr-trellis/examples/python/fsm_files/" self.noisevar = noisevar = 10**(-snr_db / 10) self.fsm2 = fsm2 = "awgn1o2_4.fsm" self.fsm1 = fsm1 = "awgn1o2_16.fsm" self.block = block = 1000 self.alpha = alpha = .1 self.R = R = 100e3 ################################################## # Blocks ################################################## self._alpha_range = Range(0, 1, .01, .1, 200) self._alpha_win = RangeWidget(self._alpha_range, self.set_alpha, 'P1/P', "counter_slider", float) self.top_layout.addWidget(self._alpha_win) self.trellis_viterbi_combined_xx_2 = trellis.viterbi_combined_cb( trellis.fsm(prefix + fsm2), block, -1, -1, 1, ((1 - alpha)**0.5 * 1, (1 - alpha)**0.5 * 1j, (1 - alpha)**0.5 * (-1j), (1 - alpha)**0.5 * (-1)), digital.TRELLIS_EUCLIDEAN) self.trellis_viterbi_combined_xx_1 = trellis.viterbi_combined_cb( trellis.fsm(prefix + fsm1), block, -1, -1, 1, (alpha**0.5 * 1, alpha**0.5 * 1j, alpha**0.5 * (-1j), alpha**0.5 * (-1)), digital.TRELLIS_EUCLIDEAN) self.trellis_viterbi_combined_xx_0_0 = trellis.viterbi_combined_cb( trellis.fsm(prefix + fsm1), block, -1, -1, 1, (alpha**0.5 * 1, alpha**0.5 * 1j, alpha**0.5 * (-1j), alpha**0.5 * (-1)), digital.TRELLIS_EUCLIDEAN) self.trellis_viterbi_combined_xx_0 = trellis.viterbi_combined_cb( trellis.fsm(prefix + fsm2), block, -1, -1, 1, ((1 - alpha)**0.5 * 1, (1 - alpha)**0.5 * 1j, (1 - alpha)**0.5 * (-1j), (1 - alpha)**0.5 * (-1)), digital.TRELLIS_EUCLIDEAN) self.trellis_encoder_xx_2_0 = trellis.encoder_bb( trellis.fsm(prefix + fsm2), 0, 0) if False else trellis.encoder_bb( trellis.fsm(prefix + fsm2), 0) self.trellis_encoder_xx_2 = trellis.encoder_bb( trellis.fsm(prefix + fsm1), 0, 0) if False else trellis.encoder_bb( trellis.fsm(prefix + fsm1), 0) self.trellis_encoder_xx_1 = trellis.encoder_bb( trellis.fsm(prefix + fsm2), 0, 0) if False else trellis.encoder_bb( trellis.fsm(prefix + fsm2), 0) self.trellis_encoder_xx_0 = trellis.encoder_bb( trellis.fsm(prefix + fsm1), 0, 0) if False else trellis.encoder_bb( trellis.fsm(prefix + fsm1), 0) self._snr_db_range = Range(0, 20, 1, 10, 200) self._snr_db_win = RangeWidget(self._snr_db_range, self.set_snr_db, 'P/sigma^2 (dB)', "counter_slider", float) self.top_layout.addWidget(self._snr_db_win) self.qtgui_number_sink_0_0_0_0 = qtgui.number_sink( gr.sizeof_float, 0, qtgui.NUM_GRAPH_HORIZ, 1) self.qtgui_number_sink_0_0_0_0.set_update_time(0.10) self.qtgui_number_sink_0_0_0_0.set_title( 'BER 1 (after cancelling user 2)') labels = ['BER', '', '', '', '', '', '', '', '', ''] units = ['', '', '', '', '', '', '', '', '', ''] colors = [("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black")] factor = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] for i in xrange(1): self.qtgui_number_sink_0_0_0_0.set_min(i, 0) self.qtgui_number_sink_0_0_0_0.set_max(i, 1) self.qtgui_number_sink_0_0_0_0.set_color(i, colors[i][0], colors[i][1]) if len(labels[i]) == 0: self.qtgui_number_sink_0_0_0_0.set_label( i, "Data {0}".format(i)) else: self.qtgui_number_sink_0_0_0_0.set_label(i, labels[i]) self.qtgui_number_sink_0_0_0_0.set_unit(i, units[i]) self.qtgui_number_sink_0_0_0_0.set_factor(i, factor[i]) self.qtgui_number_sink_0_0_0_0.enable_autoscale(False) self._qtgui_number_sink_0_0_0_0_win = sip.wrapinstance( self.qtgui_number_sink_0_0_0_0.pyqwidget(), Qt.QWidget) self.top_grid_layout.addWidget(self._qtgui_number_sink_0_0_0_0_win, 1, 0, 1, 1) self.qtgui_number_sink_0_0_0 = qtgui.number_sink( gr.sizeof_float, 0, qtgui.NUM_GRAPH_HORIZ, 1) self.qtgui_number_sink_0_0_0.set_update_time(0.10) self.qtgui_number_sink_0_0_0.set_title( "BER 2 (after cancelling user 1)") labels = ['BER', '', '', '', '', '', '', '', '', ''] units = ['', '', '', '', '', '', '', '', '', ''] colors = [("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black")] factor = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] for i in xrange(1): self.qtgui_number_sink_0_0_0.set_min(i, 0) self.qtgui_number_sink_0_0_0.set_max(i, 1) self.qtgui_number_sink_0_0_0.set_color(i, colors[i][0], colors[i][1]) if len(labels[i]) == 0: self.qtgui_number_sink_0_0_0.set_label(i, "Data {0}".format(i)) else: self.qtgui_number_sink_0_0_0.set_label(i, labels[i]) self.qtgui_number_sink_0_0_0.set_unit(i, units[i]) self.qtgui_number_sink_0_0_0.set_factor(i, factor[i]) self.qtgui_number_sink_0_0_0.enable_autoscale(False) self._qtgui_number_sink_0_0_0_win = sip.wrapinstance( self.qtgui_number_sink_0_0_0.pyqwidget(), Qt.QWidget) self.top_grid_layout.addWidget(self._qtgui_number_sink_0_0_0_win, 1, 1, 1, 1) self.qtgui_number_sink_0_0 = qtgui.number_sink(gr.sizeof_float, 0, qtgui.NUM_GRAPH_HORIZ, 1) self.qtgui_number_sink_0_0.set_update_time(0.10) self.qtgui_number_sink_0_0.set_title("BER 2 (Raw)") labels = ['BER', '', '', '', '', '', '', '', '', ''] units = ['', '', '', '', '', '', '', '', '', ''] colors = [("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black")] factor = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] for i in xrange(1): self.qtgui_number_sink_0_0.set_min(i, 0) self.qtgui_number_sink_0_0.set_max(i, 1) self.qtgui_number_sink_0_0.set_color(i, colors[i][0], colors[i][1]) if len(labels[i]) == 0: self.qtgui_number_sink_0_0.set_label(i, "Data {0}".format(i)) else: self.qtgui_number_sink_0_0.set_label(i, labels[i]) self.qtgui_number_sink_0_0.set_unit(i, units[i]) self.qtgui_number_sink_0_0.set_factor(i, factor[i]) self.qtgui_number_sink_0_0.enable_autoscale(False) self._qtgui_number_sink_0_0_win = sip.wrapinstance( self.qtgui_number_sink_0_0.pyqwidget(), Qt.QWidget) self.top_grid_layout.addWidget(self._qtgui_number_sink_0_0_win, 0, 1, 1, 1) self.qtgui_number_sink_0 = qtgui.number_sink(gr.sizeof_float, 0, qtgui.NUM_GRAPH_HORIZ, 1) self.qtgui_number_sink_0.set_update_time(0.10) self.qtgui_number_sink_0.set_title("BER1 (Raw)") labels = ['BER', '', '', '', '', '', '', '', '', ''] units = ['', '', '', '', '', '', '', '', '', ''] colors = [("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black"), ("black", "black")] factor = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] for i in xrange(1): self.qtgui_number_sink_0.set_min(i, 0) self.qtgui_number_sink_0.set_max(i, 1) self.qtgui_number_sink_0.set_color(i, colors[i][0], colors[i][1]) if len(labels[i]) == 0: self.qtgui_number_sink_0.set_label(i, "Data {0}".format(i)) else: self.qtgui_number_sink_0.set_label(i, labels[i]) self.qtgui_number_sink_0.set_unit(i, units[i]) self.qtgui_number_sink_0.set_factor(i, factor[i]) self.qtgui_number_sink_0.enable_autoscale(False) self._qtgui_number_sink_0_win = sip.wrapinstance( self.qtgui_number_sink_0.pyqwidget(), Qt.QWidget) self.top_grid_layout.addWidget(self._qtgui_number_sink_0_win, 0, 0, 1, 1) self.qtgui_const_sink_x_0 = qtgui.const_sink_c( 1024, #size "", #name 1 #number of inputs ) self.qtgui_const_sink_x_0.set_update_time(0.10) self.qtgui_const_sink_x_0.set_y_axis(-2, 2) self.qtgui_const_sink_x_0.set_x_axis(-2, 2) self.qtgui_const_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, "") self.qtgui_const_sink_x_0.enable_autoscale(False) self.qtgui_const_sink_x_0.enable_grid(False) self.qtgui_const_sink_x_0.enable_axis_labels(True) if not True: self.qtgui_const_sink_x_0.disable_legend() labels = ['', '', '', '', '', '', '', '', '', ''] widths = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] colors = [ "blue", "red", "red", "red", "red", "red", "red", "red", "red", "red" ] styles = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] markers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] alphas = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] for i in xrange(1): if len(labels[i]) == 0: self.qtgui_const_sink_x_0.set_line_label( i, "Data {0}".format(i)) else: self.qtgui_const_sink_x_0.set_line_label(i, labels[i]) self.qtgui_const_sink_x_0.set_line_width(i, widths[i]) self.qtgui_const_sink_x_0.set_line_color(i, colors[i]) self.qtgui_const_sink_x_0.set_line_style(i, styles[i]) self.qtgui_const_sink_x_0.set_line_marker(i, markers[i]) self.qtgui_const_sink_x_0.set_line_alpha(i, alphas[i]) self._qtgui_const_sink_x_0_win = sip.wrapinstance( self.qtgui_const_sink_x_0.pyqwidget(), Qt.QWidget) self.top_layout.addWidget(self._qtgui_const_sink_x_0_win) self.digital_chunks_to_symbols_xx_0_0_1 = digital.chunks_to_symbols_bc( (1, 1j, -1j, -1), 1) self.digital_chunks_to_symbols_xx_0_0_0 = digital.chunks_to_symbols_bc( (1, 1j, -1j, -1), 1) self.digital_chunks_to_symbols_xx_0_0 = digital.chunks_to_symbols_bc( (1, 1j, -1j, -1), 1) self.digital_chunks_to_symbols_xx_0 = digital.chunks_to_symbols_bc( (1, 1j, -1j, -1), 1) self.blocks_throttle_0 = blocks.throttle(gr.sizeof_char * 1, R, True) self.blocks_sub_xx_2_0 = blocks.sub_cc(1) self.blocks_sub_xx_2 = blocks.sub_cc(1) self.blocks_multiply_const_vxx_2_0 = blocks.multiply_const_vcc( ((1 - alpha)**0.5, )) self.blocks_multiply_const_vxx_2 = blocks.multiply_const_vcc( (alpha**0.5, )) self.blocks_multiply_const_vxx_1 = blocks.multiply_const_vcc( ((1 - alpha)**0.5, )) self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc( (alpha**0.5, )) self.blocks_add_xx_0 = blocks.add_vcc(1) self.blks2_error_rate_0_0_0_0 = grc_blks2.error_rate( type='BER', win_size=block * 100, bits_per_symbol=2, ) self.blks2_error_rate_0_0_0 = grc_blks2.error_rate( type='BER', win_size=block * 100, bits_per_symbol=2, ) self.blks2_error_rate_0_0 = grc_blks2.error_rate( type='BER', win_size=block * 100, bits_per_symbol=2, ) self.blks2_error_rate_0 = grc_blks2.error_rate( type='BER', win_size=block * 100, bits_per_symbol=2, ) self.analog_random_source_x_1 = blocks.vector_source_b( map(int, numpy.random.randint(0, 2, block)), True) self.analog_random_source_x_0 = blocks.vector_source_b( map(int, numpy.random.randint(0, 2, block)), True) self.analog_noise_source_x_0 = analog.noise_source_c( analog.GR_GAUSSIAN, noisevar, -42) ################################################## # Connections ################################################## self.connect((self.analog_noise_source_x_0, 0), (self.blocks_add_xx_0, 2)) self.connect((self.analog_random_source_x_0, 0), (self.blks2_error_rate_0, 0)) self.connect((self.analog_random_source_x_0, 0), (self.blks2_error_rate_0_0_0_0, 0)) self.connect((self.analog_random_source_x_0, 0), (self.trellis_encoder_xx_0, 0)) self.connect((self.analog_random_source_x_1, 0), (self.blks2_error_rate_0_0, 0)) self.connect((self.analog_random_source_x_1, 0), (self.blks2_error_rate_0_0_0, 0)) self.connect((self.analog_random_source_x_1, 0), (self.trellis_encoder_xx_1, 0)) self.connect((self.blks2_error_rate_0, 0), (self.qtgui_number_sink_0, 0)) self.connect((self.blks2_error_rate_0_0, 0), (self.qtgui_number_sink_0_0, 0)) self.connect((self.blks2_error_rate_0_0_0, 0), (self.qtgui_number_sink_0_0_0, 0)) self.connect((self.blks2_error_rate_0_0_0_0, 0), (self.qtgui_number_sink_0_0_0_0, 0)) self.connect((self.blocks_add_xx_0, 0), (self.blocks_sub_xx_2, 0)) self.connect((self.blocks_add_xx_0, 0), (self.blocks_sub_xx_2_0, 0)) self.connect((self.blocks_add_xx_0, 0), (self.qtgui_const_sink_x_0, 0)) self.connect((self.blocks_add_xx_0, 0), (self.trellis_viterbi_combined_xx_1, 0)) self.connect((self.blocks_add_xx_0, 0), (self.trellis_viterbi_combined_xx_2, 0)) self.connect((self.blocks_multiply_const_vxx_0, 0), (self.blocks_add_xx_0, 0)) self.connect((self.blocks_multiply_const_vxx_1, 0), (self.blocks_add_xx_0, 1)) self.connect((self.blocks_multiply_const_vxx_2, 0), (self.blocks_sub_xx_2, 1)) self.connect((self.blocks_multiply_const_vxx_2_0, 0), (self.blocks_sub_xx_2_0, 1)) self.connect((self.blocks_sub_xx_2, 0), (self.trellis_viterbi_combined_xx_0, 0)) self.connect((self.blocks_sub_xx_2_0, 0), (self.trellis_viterbi_combined_xx_0_0, 0)) self.connect((self.blocks_throttle_0, 0), (self.digital_chunks_to_symbols_xx_0, 0)) self.connect((self.digital_chunks_to_symbols_xx_0, 0), (self.blocks_multiply_const_vxx_0, 0)) self.connect((self.digital_chunks_to_symbols_xx_0_0, 0), (self.blocks_multiply_const_vxx_1, 0)) self.connect((self.digital_chunks_to_symbols_xx_0_0_0, 0), (self.blocks_multiply_const_vxx_2, 0)) self.connect((self.digital_chunks_to_symbols_xx_0_0_1, 0), (self.blocks_multiply_const_vxx_2_0, 0)) self.connect((self.trellis_encoder_xx_0, 0), (self.blocks_throttle_0, 0)) self.connect((self.trellis_encoder_xx_1, 0), (self.digital_chunks_to_symbols_xx_0_0, 0)) self.connect((self.trellis_encoder_xx_2, 0), (self.digital_chunks_to_symbols_xx_0_0_0, 0)) self.connect((self.trellis_encoder_xx_2_0, 0), (self.digital_chunks_to_symbols_xx_0_0_1, 0)) self.connect((self.trellis_viterbi_combined_xx_0, 0), (self.blks2_error_rate_0_0_0, 1)) self.connect((self.trellis_viterbi_combined_xx_0_0, 0), (self.blks2_error_rate_0_0_0_0, 1)) self.connect((self.trellis_viterbi_combined_xx_1, 0), (self.blks2_error_rate_0, 1)) self.connect((self.trellis_viterbi_combined_xx_1, 0), (self.trellis_encoder_xx_2, 0)) self.connect((self.trellis_viterbi_combined_xx_2, 0), (self.blks2_error_rate_0_0, 1)) self.connect((self.trellis_viterbi_combined_xx_2, 0), (self.trellis_encoder_xx_2_0, 0))
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, 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 = filter.rational_resampler_ccc(cr_interp, cr_decim) #here we take a different tack and use A.A.'s CPM decomposition technique self.clockrec = digital.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 = digital.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 = blocks.streams_to_stream(int(gr.sizeof_gr_complex*1), int(N)) self.mf0 = filter.fir_filter_ccc(samples_per_symbol_viterbi, MF[0].conjugate()) #two matched filters for decomposition self.mf1 = filter.fir_filter_ccc(samples_per_symbol_viterbi, MF[1].conjugate()) self.fo = analog.sig_source_c(samples_per_symbol_viterbi, gr.GR_COS_WAVE, -f0T, 1, 0) #the memoryless modulation component of the decomposition self.fomult = blocks.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 = filter.firdes.root_raised_cosine(10, #gain self._samplerate*16, #sample rate self._bits_per_sec, #symbol rate 0.4, #alpha, same as BT? 50*16) #no. of taps sensitivity = (math.pi / 2) / self._samples_per_symbol self.demod = analog.quadrature_demod_cf(sensitivity) #param is gain self.clockrec = digital.pfb_clock_sync_ccf(self._samples_per_symbol, 0.04, self.datafiltertaps, 16, 0, 1.15) self.tcslicer = digital.digital.binary_slicer_fb() self.slicer = digital.binary_slicer_fb() self.diff = digital.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) 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)