Example #1
0
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)
Example #3
0
    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())
Example #5
0
    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())
Example #7
0
    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)
Example #8
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)
Example #9
0
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)
Example #11
0
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)
Example #12
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, 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)