def graph (args): print os.getpid() nargs = len (args) if nargs == 1: infile = args[0] else: sys.stderr.write('usage: interp.py input_file\n') sys.exit (1) tb = gr.top_block () srcf = gr.file_source (gr.sizeof_short,infile) s2ss = gr.stream_to_streams(gr.sizeof_short,2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src0 = gr.float_to_complex() lp_coeffs = gr.firdes.low_pass ( 3, 19.2e6, 3.2e6, .5e6, gr.firdes.WIN_HAMMING ) lp = gr.interp_fir_filter_ccf ( 3, lp_coeffs ) file = gr.file_sink(gr.sizeof_gr_complex,"/tmp/atsc_pipe_1") tb.connect( srcf, s2ss ) tb.connect( (s2ss, 0), s2f1, (src0,0) ) tb.connect( (s2ss, 1), s2f2, (src0,1) ) tb.connect( src0, lp, file) tb.start() raw_input ('Head End: Press Enter to stop') tb.stop()
def graph(args): print os.getpid() nargs = len(args) if nargs == 1: infile = args[0] else: sys.stderr.write('usage: interp.py input_file\n') sys.exit(1) tb = gr.top_block() srcf = gr.file_source(gr.sizeof_short, infile) s2ss = gr.stream_to_streams(gr.sizeof_short, 2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src0 = gr.float_to_complex() lp_coeffs = gr.firdes.low_pass(3, 19.2e6, 3.2e6, .5e6, gr.firdes.WIN_HAMMING) lp = gr.interp_fir_filter_ccf(3, lp_coeffs) file = gr.file_sink(gr.sizeof_gr_complex, "/tmp/atsc_pipe_1") tb.connect(srcf, s2ss) tb.connect((s2ss, 0), s2f1, (src0, 0)) tb.connect((s2ss, 1), s2f2, (src0, 1)) tb.connect(src0, lp, file) tb.start() raw_input('Head End: Press Enter to stop') tb.stop()
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 __init__(self, numchans, taps=None, oversample_rate=1, atten=100): gr.hier_block2.__init__( self, "pfb_channelizer_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(numchans, numchans, gr.sizeof_gr_complex)) # Output signature self._numchans = numchans self._oversample_rate = oversample_rate if taps is not None: self._taps = taps else: # Create a filter that covers the full bandwidth of the input signal bw = 0.4 tb = 0.2 ripple = 0.1 made = False while not made: try: self._taps = optfir.low_pass(1, self._numchans, bw, bw + tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 made = False print( "Warning: set ripple to %.4f dB. If this is a problem, adjust the attenuation or create your own filter taps." % (ripple)) # Build in an exit strategy; if we've come this far, it ain't working. if (ripple >= 1.0): raise RuntimeError( "optfir could not generate an appropriate filter.") self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans) self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps, self._oversample_rate) self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans) self.connect(self, self.s2ss) for i in xrange(self._numchans): self.connect((self.s2ss, i), (self.pfb, i)) # Get independent streams from the filterbank and send them out self.connect(self.pfb, self.v2s) for i in xrange(self._numchans): self.connect((self.v2s, i), (self, i))
def test_000(self): N = 1000 # number of samples to use M = 5 # Number of channels fs = 1000 # baseband sampling rate ifs = M * fs # input samp rate to decimator channel = 0 # Extract channel 0 taps = filter.firdes.low_pass_2( 1, ifs, fs / 2, fs / 10, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) signals = list() add = gr.add_cc() freqs = [-200, -100, 0, 100, 200] for i in xrange(len(freqs)): f = freqs[i] + (M / 2 - M + i + 1) * fs signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1)) self.tb.connect(signals[i], (add, i)) head = gr.head(gr.sizeof_gr_complex, N) s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M) pfb = filter.pfb_decimator_ccf(M, taps, channel) snk = gr.vector_sink_c() self.tb.connect(add, head, s2ss) for i in xrange(M): self.tb.connect((s2ss, i), (pfb, i)) self.tb.connect(pfb, snk) self.tb.run() Ntest = 50 L = len(snk.data()) t = map(lambda x: float(x) / fs, xrange(L)) # Create known data as complex sinusoids for the baseband freq # of the extracted channel is due to decimator output order. phase = 0 expected_data = map(lambda x: math.cos(2.*math.pi*freqs[2]*x+phase) + \ 1j*math.sin(2.*math.pi*freqs[2]*x+phase), t) dst_data = snk.data() self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 4)
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, mpoints, taps=None): """ Takes 1 complex stream in, produces M complex streams out that runs at 1/M times the input sample rate @param mpoints: number of freq bins/interpolation factor/subbands @param taps: filter taps for subband filter Same channel to frequency mapping as described above. """ item_size = gr.sizeof_gr_complex gr.hier_block2.__init__( self, "analysis_filterbank", gr.io_signature(1, 1, item_size), # Input signature gr.io_signature(mpoints, mpoints, 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) # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps) self.s2ss = gr.stream_to_streams(item_size, mpoints) # filters here self.ss2v = gr.streams_to_vector(item_size, mpoints) self.fft = gr.fft_vcc(mpoints, True, []) self.v2ss = gr.vector_to_streams(item_size, mpoints) self.connect(self, self.s2ss) # build mpoints fir filters... for i in range(mpoints): f = gr.fft_filter_ccc(1, sub_taps[mpoints - i - 1]) self.connect((self.s2ss, i), f) self.connect(f, (self.ss2v, i)) self.connect((self.v2ss, i), (self, i)) self.connect(self.ss2v, self.fft, self.v2ss)
def test_000(self): N = 1000 # number of samples to use M = 5 # Number of channels fs = 1000 # baseband sampling rate ifs = M * fs # input samp rate to decimator channel = 0 # Extract channel 0 taps = filter.firdes.low_pass_2( 1, ifs, fs / 2, fs / 10, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS ) signals = list() add = gr.add_cc() freqs = [-200, -100, 0, 100, 200] for i in xrange(len(freqs)): f = freqs[i] + (M / 2 - M + i + 1) * fs signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1)) self.tb.connect(signals[i], (add, i)) head = gr.head(gr.sizeof_gr_complex, N) s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M) pfb = filter.pfb_decimator_ccf(M, taps, channel) snk = gr.vector_sink_c() self.tb.connect(add, head, s2ss) for i in xrange(M): self.tb.connect((s2ss, i), (pfb, i)) self.tb.connect(pfb, snk) self.tb.run() Ntest = 50 L = len(snk.data()) t = map(lambda x: float(x) / fs, xrange(L)) # Create known data as complex sinusoids for the baseband freq # of the extracted channel is due to decimator output order. phase = 0 expected_data = map( lambda x: math.cos(2.0 * math.pi * freqs[2] * x + phase) + 1j * math.sin(2.0 * math.pi * freqs[2] * x + phase), t, ) dst_data = snk.data() self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 4)
def __init__(self, mpoints, taps=None): """ Takes 1 complex stream in, produces M complex streams out that runs at 1/M times the input sample rate @param mpoints: number of freq bins/interpolation factor/subbands @param taps: filter taps for subband filter Same channel to frequency mapping as described above. """ item_size = gr.sizeof_gr_complex gr.hier_block2.__init__( self, "analysis_filterbank", gr.io_signature(1, 1, item_size), # Input signature gr.io_signature(mpoints, mpoints, 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) # print >> sys.stderr, "mpoints =", mpoints, "len(sub_taps) =", len(sub_taps) self.s2ss = gr.stream_to_streams(item_size, mpoints) # filters here self.ss2v = gr.streams_to_vector(item_size, mpoints) self.fft = gr.fft_vcc(mpoints, True, []) self.v2ss = gr.vector_to_streams(item_size, mpoints) self.connect(self, self.s2ss) # build mpoints fir filters... for i in range(mpoints): f = gr.fft_filter_ccc(1, sub_taps[mpoints - i - 1]) self.connect((self.s2ss, i), f) self.connect(f, (self.ss2v, i)) self.connect((self.v2ss, i), (self, i)) self.connect(self.ss2v, self.fft, self.v2ss)
def __init__(self): gr.hier_block2.__init__(self, "binary_diff_decoder", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_char)) s_to_p = gr.stream_to_streams(gr.sizeof_gr_complex, 2) s_0_s = symbol_0_slicer() s_1_s = symbol_1_slicer() slicer = bit_slicer() #connect serial to parallel to the symbol 0 and symbol 1 slicers self.connect(self, s_to_p) self.connect((s_to_p, 0), (s_0_s, 0)) self.connect((s_to_p, 1), (s_0_s, 1)) self.connect((s_to_p, 0), (s_1_s, 0)) self.connect((s_to_p, 1), (s_1_s, 1)) #connect the slicers to bit slicers self.connect(s_0_s, (slicer, 0)) self.connect(s_1_s, (slicer, 1)) self.connect(slicer, self)
def __init__(self, decim, taps, channel=0): gr.hier_block2.__init__(self, "pfb_decimator_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._decim = decim self._taps = taps self._channel = channel self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._decim) self.pfb = gr.pfb_decimator_ccf(self._decim, self._taps, self._channel) self.connect(self, self.s2ss) for i in xrange(self._decim): self.connect((self.s2ss,i), (self.pfb,i)) self.connect(self.pfb, self)
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 __init__(self): gr.hier_block2.__init__(self, "binary_diff_decoder", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_char)) s_to_p = gr.stream_to_streams(gr.sizeof_gr_complex, 2) s_0_s = symbol_0_slicer() s_1_s = symbol_1_slicer() slicer = bit_slicer() #connect serial to parallel to the symbol 0 and symbol 1 slicers self.connect(self, s_to_p) self.connect((s_to_p, 0), (s_0_s,0)) self.connect((s_to_p, 1), (s_0_s,1)) self.connect((s_to_p, 0), (s_1_s,0)) self.connect((s_to_p, 1), (s_1_s,1)) #connect the slicers to bit slicers self.connect(s_0_s, (slicer, 0)) self.connect(s_1_s, (slicer, 1)) self.connect(slicer, self)
def __init__(self, decim, taps=None, channel=0, atten=100): gr.hier_block2.__init__(self, "pfb_decimator_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self._decim = decim self._channel = channel if taps is not None: self._taps = taps else: # Create a filter that covers the full bandwidth of the input signal bw = 0.4 tb = 0.2 ripple = 0.1 made = False while not made: try: self._taps = optfir.low_pass(1, self._decim, bw, bw + tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 made = False print( "Warning: set ripple to %.4f dB. If this is a problem, adjust the attenuation or create your own filter taps." % (ripple)) # Build in an exit strategy; if we've come this far, it ain't working. if (ripple >= 1.0): raise RuntimeError( "optfir could not generate an appropriate filter.") self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._decim) self.pfb = filter.pfb_decimator_ccf(self._decim, self._taps, self._channel) self.connect(self, self.s2ss) for i in xrange(self._decim): self.connect((self.s2ss, i), (self.pfb, i)) self.connect(self.pfb, 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 __init__(self, numchans, taps): gr.hier_block2.__init__(self, "pfb_channelizer_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(numchans, numchans, gr.sizeof_gr_complex)) # Output signature self._numchans = numchans self._taps = taps self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans) self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps) self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans) self.connect(self, self.s2ss) for i in xrange(self._numchans): self.connect((self.s2ss,i), (self.pfb,i)) # Get independent streams from the filterbank and send them out self.connect(self.pfb, self.v2s) for i in xrange(self._numchans): self.connect((self.v2s,i), (self,i))
def __init__(self, decim, taps=None, channel=0, atten=100): gr.hier_block2.__init__(self, "pfb_decimator_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self._decim = decim self._channel = channel if (taps is not None) and (len(taps) > 0): self._taps = taps else: # Create a filter that covers the full bandwidth of the input signal bw = 0.4 tb = 0.2 ripple = 0.1 made = False while not made: try: self._taps = optfir.low_pass(1, self._decim, bw, bw+tb, ripple, atten) made = True except RuntimeError: ripple += 0.01 made = False print("Warning: set ripple to %.4f dB. If this is a problem, adjust the attenuation or create your own filter taps." % (ripple)) # Build in an exit strategy; if we've come this far, it ain't working. if(ripple >= 1.0): raise RuntimeError("optfir could not generate an appropriate filter.") self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._decim) self.pfb = filter.pfb_decimator_ccf(self._decim, self._taps, self._channel) self.connect(self, self.s2ss) for i in xrange(self._decim): self.connect((self.s2ss,i), (self.pfb,i)) self.connect(self.pfb, self)
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 test_001(self): """ Test stream_to_streams. """ n = 8 src_len = n * 8 src_data = range(src_len) expected_results = calc_expected_result(src_data, n) #print "expected results: ", expected_results src = gr.vector_source_i(src_data) op = gr.stream_to_streams(gr.sizeof_int, n) self.tb.connect(src, op) dsts = [] for i in range(n): dst = gr.vector_sink_i() self.tb.connect((op, i), (dst, 0)) dsts.append(dst) self.tb.run() for d in range(n): self.assertEqual(expected_results[d], dsts[d].data())
def test_000(self): N = 1000 # number of samples to use M = 5 # Number of channels to channelize fs = 1000 # baseband sampling rate ifs = M*fs # input samp rate to channelizer taps = filter.firdes.low_pass_2(1, ifs, 500, 50, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) signals = list() add = gr.add_cc() freqs = [-200, -100, 0, 100, 200] for i in xrange(len(freqs)): f = freqs[i] + (M/2-M+i+1)*fs signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1)) self.tb.connect(signals[i], (add,i)) head = gr.head(gr.sizeof_gr_complex, N) s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M) pfb = filter.pfb_channelizer_ccf(M, taps, 1) self.tb.connect(add, head, s2ss) snks = list() for i in xrange(M): snks.append(gr.vector_sink_c()) self.tb.connect((s2ss,i), (pfb,i)) self.tb.connect((pfb, i), snks[i]) self.tb.run() Ntest = 50 L = len(snks[0].data()) t = map(lambda x: float(x)/fs, xrange(L)) # Adjusted phase rotations for data p0 = 0 p1 = math.pi*0.51998885 p2 = -math.pi*0.96002233 p3 = math.pi*0.96002233 p4 = -math.pi*0.51998885 # Create known data as complex sinusoids at the different baseband freqs # the different channel numbering is due to channelizer output order. expected0_data = map(lambda x: math.cos(2.*math.pi*freqs[2]*x+p0) + \ 1j*math.sin(2.*math.pi*freqs[2]*x+p0), t) expected1_data = map(lambda x: math.cos(2.*math.pi*freqs[3]*x+p1) + \ 1j*math.sin(2.*math.pi*freqs[3]*x+p1), t) expected2_data = map(lambda x: math.cos(2.*math.pi*freqs[4]*x+p2) + \ 1j*math.sin(2.*math.pi*freqs[4]*x+p2), t) expected3_data = map(lambda x: math.cos(2.*math.pi*freqs[0]*x+p3) + \ 1j*math.sin(2.*math.pi*freqs[0]*x+p3), t) expected4_data = map(lambda x: math.cos(2.*math.pi*freqs[1]*x+p4) + \ 1j*math.sin(2.*math.pi*freqs[1]*x+p4), t) dst0_data = snks[0].data() dst1_data = snks[1].data() dst2_data = snks[2].data() dst3_data = snks[3].data() dst4_data = snks[4].data() self.assertComplexTuplesAlmostEqual(expected0_data[-Ntest:], dst0_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected1_data[-Ntest:], dst1_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected2_data[-Ntest:], dst2_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected3_data[-Ntest:], dst3_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected4_data[-Ntest:], dst4_data[-Ntest:], 3)
def graph(args): nargs = len(args) if nargs == 2: infile = args[0] outfile = args[1] else: raise ValueError('usage: interp.py input_file output_file\n') tb = gr.top_block() # Convert to a from shorts to a stream of complex numbers. srcf = gr.file_source(gr.sizeof_short, infile) s2ss = gr.stream_to_streams(gr.sizeof_short, 2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src0 = gr.float_to_complex() tb.connect(srcf, s2ss) tb.connect((s2ss, 0), s2f1, (src0, 0)) tb.connect((s2ss, 1), s2f2, (src0, 1)) # Low pass filter it and increase sample rate by a factor of 3. lp_coeffs = gr.firdes.low_pass(3, 19.2e6, 3.2e6, .5e6, gr.firdes.WIN_HAMMING) lp = gr.interp_fir_filter_ccf(3, lp_coeffs) tb.connect(src0, lp) # Upconvert it. duc_coeffs = gr.firdes.low_pass(1, 19.2e6, 9e6, 1e6, gr.firdes.WIN_HAMMING) duc = gr.freq_xlating_fir_filter_ccf(1, duc_coeffs, 5.75e6, 19.2e6) # Discard the imaginary component. c2f = gr.complex_to_float() tb.connect(lp, duc, c2f) # Frequency Phase Lock Loop input_rate = 19.2e6 IF_freq = 5.75e6 # 1/2 as wide because we're designing lp filter symbol_rate = atsc.ATSC_SYMBOL_RATE / 2. NTAPS = 279 tt = gr.firdes.root_raised_cosine(1.0, input_rate, symbol_rate, .115, NTAPS) # heterodyne the low pass coefficients up to the specified bandpass # center frequency. Note that when we do this, the filter bandwidth # is effectively twice the low pass (2.69 * 2 = 5.38) and hence # matches the diagram in the ATSC spec. arg = 2. * math.pi * IF_freq / input_rate t = [] for i in range(len(tt)): t += [tt[i] * 2. * math.cos(arg * i)] rrc = gr.fir_filter_fff(1, t) fpll = atsc.fpll() pilot_freq = IF_freq - 3e6 + 0.31e6 lower_edge = 6e6 - 0.31e6 upper_edge = IF_freq - 3e6 + pilot_freq transition_width = upper_edge - lower_edge lp_coeffs = gr.firdes.low_pass(1.0, input_rate, (lower_edge + upper_edge) * 0.5, transition_width, gr.firdes.WIN_HAMMING) lp_filter = gr.fir_filter_fff(1, lp_coeffs) alpha = 1e-5 iir = gr.single_pole_iir_filter_ff(alpha) remove_dc = gr.sub_ff() tb.connect(c2f, fpll, lp_filter) tb.connect(lp_filter, iir) tb.connect(lp_filter, (remove_dc, 0)) tb.connect(iir, (remove_dc, 1)) # Bit Timing Loop, Field Sync Checker and Equalizer btl = atsc.bit_timing_loop() fsc = atsc.fs_checker() eq = atsc.equalizer() fsd = atsc.field_sync_demux() tb.connect(remove_dc, btl) tb.connect((btl, 0), (fsc, 0), (eq, 0), (fsd, 0)) tb.connect((btl, 1), (fsc, 1), (eq, 1), (fsd, 1)) # Viterbi viterbi = atsc.viterbi_decoder() deinter = atsc.deinterleaver() rs_dec = atsc.rs_decoder() derand = atsc.derandomizer() depad = atsc.depad() dst = gr.file_sink(gr.sizeof_char, outfile) tb.connect(fsd, viterbi, deinter, rs_dec, derand, depad, dst) dst2 = gr.file_sink(gr.sizeof_gr_complex, "atsc_complex.data") tb.connect(src0, dst2) tb.run()
def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) wxglade_tmp_menu = wx.Menu() self.Exit = wx.MenuItem(wxglade_tmp_menu, ID_EXIT, "Exit", "Exit", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendItem(self.Exit) self.frame_1_menubar.Append(wxglade_tmp_menu, "File") # Menu Bar end self.panel_1 = wx.Panel(self, -1) self.button_1 = wx.Button(self, ID_BUTTON_1, "LSB") self.button_2 = wx.Button(self, ID_BUTTON_2, "USB") self.button_3 = wx.Button(self, ID_BUTTON_3, "AM") self.button_4 = wx.Button(self, ID_BUTTON_4, "CW") self.button_5 = wx.ToggleButton(self, ID_BUTTON_5, "Upper") self.slider_fcutoff_hi = wx.Slider(self, ID_SLIDER_1, 0, -15798, 15799, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.button_6 = wx.ToggleButton(self, ID_BUTTON_6, "Lower") self.slider_fcutoff_lo = wx.Slider(self, ID_SLIDER_2, 0, -15799, 15798, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_5 = wx.Panel(self, -1) self.label_1 = wx.StaticText(self, -1, " Band\nCenter") self.text_ctrl_1 = wx.TextCtrl(self, ID_TEXT_1, "") self.panel_6 = wx.Panel(self, -1) self.panel_7 = wx.Panel(self, -1) self.panel_2 = wx.Panel(self, -1) self.button_7 = wx.ToggleButton(self, ID_BUTTON_7, "Freq") self.slider_3 = wx.Slider(self, ID_SLIDER_3, 3000, 0, 6000) self.spin_ctrl_1 = wx.SpinCtrl(self, ID_SPIN_1, "", min=0, max=100) self.button_8 = wx.ToggleButton(self, ID_BUTTON_8, "Vol") self.slider_4 = wx.Slider(self, ID_SLIDER_4, 0, 0, 500) self.slider_5 = wx.Slider(self, ID_SLIDER_5, 0, 0, 20) self.button_9 = wx.ToggleButton(self, ID_BUTTON_9, "Time") self.button_11 = wx.Button(self, ID_BUTTON_11, "Rew") self.button_10 = wx.Button(self, ID_BUTTON_10, "Fwd") self.panel_3 = wx.Panel(self, -1) self.label_2 = wx.StaticText(self, -1, "PGA ") self.panel_4 = wx.Panel(self, -1) self.panel_8 = wx.Panel(self, -1) self.panel_9 = wx.Panel(self, -1) self.label_3 = wx.StaticText(self, -1, "AM Sync\nCarrier") self.slider_6 = wx.Slider(self, ID_SLIDER_6, 50, 0, 200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.label_4 = wx.StaticText(self, -1, "Antenna Tune") self.slider_7 = wx.Slider(self, ID_SLIDER_7, 1575, 950, 2200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_10 = wx.Panel(self, -1) self.button_12 = wx.ToggleButton(self, ID_BUTTON_12, "Auto Tune") self.button_13 = wx.Button(self, ID_BUTTON_13, "Calibrate") self.button_14 = wx.Button(self, ID_BUTTON_14, "Reset") self.panel_11 = wx.Panel(self, -1) self.panel_12 = wx.Panel(self, -1) self.__set_properties() self.__do_layout() # end wxGlade parser = OptionParser(option_class=eng_option) parser.add_option("", "--address", type="string", default="addr=192.168.10.2", help="Address of UHD device, [default=%default]") parser.add_option("-c", "--ddc-freq", type="eng_float", default=3.9e6, help="set Rx DDC frequency to FREQ", metavar="FREQ") parser.add_option( "-s", "--samp-rate", type="eng_float", default=256e3, help="set sample rate (bandwidth) [default=%default]") parser.add_option("-a", "--audio_file", default="", help="audio output file", metavar="FILE") parser.add_option("-r", "--radio_file", default="", help="radio output file", metavar="FILE") parser.add_option("-i", "--input_file", default="", help="radio input file", metavar="FILE") parser.add_option( "-O", "--audio-output", type="string", default="", help="audio output device name. E.g., hw:0,0, /dev/dsp, or pulse") (options, args) = parser.parse_args() self.usrp_center = options.ddc_freq input_rate = options.samp_rate self.slider_range = input_rate * 0.9375 self.f_lo = self.usrp_center - (self.slider_range / 2) self.f_hi = self.usrp_center + (self.slider_range / 2) self.af_sample_rate = 32000 fir_decim = long(input_rate / self.af_sample_rate) # data point arrays for antenna tuner self.xdata = [] self.ydata = [] self.tb = gr.top_block() # radio variables, initial conditions self.frequency = self.usrp_center # these map the frequency slider (0-6000) to the actual range self.f_slider_offset = self.f_lo self.f_slider_scale = 10000 self.spin_ctrl_1.SetRange(self.f_lo, self.f_hi) self.text_ctrl_1.SetValue(str(int(self.usrp_center))) self.slider_5.SetValue(0) self.AM_mode = False self.slider_3.SetValue( (self.frequency - self.f_slider_offset) / self.f_slider_scale) self.spin_ctrl_1.SetValue(int(self.frequency)) POWERMATE = True try: self.pm = powermate.powermate(self) except: sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n") POWERMATE = False if POWERMATE: powermate.EVT_POWERMATE_ROTATE(self, self.on_rotate) powermate.EVT_POWERMATE_BUTTON(self, self.on_pmButton) self.active_button = 7 # command line options if options.audio_file == "": SAVE_AUDIO_TO_FILE = False else: SAVE_AUDIO_TO_FILE = True if options.radio_file == "": SAVE_RADIO_TO_FILE = False else: SAVE_RADIO_TO_FILE = True if options.input_file == "": self.PLAY_FROM_USRP = True else: self.PLAY_FROM_USRP = False if self.PLAY_FROM_USRP: self.src = uhd.usrp_source(device_addr=options.address, io_type=uhd.io_type.COMPLEX_FLOAT32, num_channels=1) self.src.set_samp_rate(input_rate) input_rate = self.src.get_samp_rate() self.src.set_center_freq(self.usrp_center, 0) self.tune_offset = 0 else: self.src = gr.file_source(gr.sizeof_short, options.input_file) self.tune_offset = 2200 # 2200 works for 3.5-4Mhz band # convert rf data in interleaved short int form to complex s2ss = gr.stream_to_streams(gr.sizeof_short, 2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src_f2c = gr.float_to_complex() self.tb.connect(self.src, s2ss) self.tb.connect((s2ss, 0), s2f1) self.tb.connect((s2ss, 1), s2f2) self.tb.connect(s2f1, (src_f2c, 0)) self.tb.connect(s2f2, (src_f2c, 1)) # save radio data to a file if SAVE_RADIO_TO_FILE: radio_file = gr.file_sink(gr.sizeof_short, options.radio_file) self.tb.connect(self.src, radio_file) # 2nd DDC xlate_taps = gr.firdes.low_pass ( \ 1.0, input_rate, 16e3, 4e3, gr.firdes.WIN_HAMMING ) self.xlate = gr.freq_xlating_fir_filter_ccf ( \ fir_decim, xlate_taps, self.tune_offset, input_rate ) # Complex Audio filter audio_coeffs = gr.firdes.complex_band_pass( 1.0, # gain self.af_sample_rate, # sample rate -3000, # low cutoff 0, # high cutoff 100, # transition gr.firdes.WIN_HAMMING) # window self.slider_fcutoff_hi.SetValue(0) self.slider_fcutoff_lo.SetValue(-3000) self.audio_filter = gr.fir_filter_ccc(1, audio_coeffs) # Main +/- 16Khz spectrum display self.fft = fftsink2.fft_sink_c(self.panel_2, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240)) # AM Sync carrier if AM_SYNC_DISPLAY: self.fft2 = fftsink.fft_sink_c(self.tb, self.panel_9, y_per_div=20, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240)) c2f = gr.complex_to_float() # AM branch self.sel_am = gr.multiply_const_cc(0) # the following frequencies turn out to be in radians/sample # gr.pll_refout_cc(alpha,beta,min_freq,max_freq) # suggested alpha = X, beta = .25 * X * X pll = gr.pll_refout_cc(.5, .0625, (2. * math.pi * 7.5e3 / self.af_sample_rate), (2. * math.pi * 6.5e3 / self.af_sample_rate)) self.pll_carrier_scale = gr.multiply_const_cc(complex(10, 0)) am_det = gr.multiply_cc() # these are for converting +7.5kHz to -7.5kHz # for some reason gr.conjugate_cc() adds noise ?? c2f2 = gr.complex_to_float() c2f3 = gr.complex_to_float() f2c = gr.float_to_complex() phaser1 = gr.multiply_const_ff(1) phaser2 = gr.multiply_const_ff(-1) # filter for pll generated carrier pll_carrier_coeffs = gr.firdes.complex_band_pass( 2.0, # gain self.af_sample_rate, # sample rate 7400, # low cutoff 7600, # high cutoff 100, # transition gr.firdes.WIN_HAMMING) # window self.pll_carrier_filter = gr.fir_filter_ccc(1, pll_carrier_coeffs) self.sel_sb = gr.multiply_const_ff(1) combine = gr.add_ff() #AGC sqr1 = gr.multiply_ff() intr = gr.iir_filter_ffd([.004, 0], [0, .999]) offset = gr.add_const_ff(1) agc = gr.divide_ff() self.scale = gr.multiply_const_ff(0.00001) dst = audio.sink(long(self.af_sample_rate), options.audio_output) if self.PLAY_FROM_USRP: self.tb.connect(self.src, self.xlate, self.fft) else: self.tb.connect(src_f2c, self.xlate, self.fft) self.tb.connect(self.xlate, self.audio_filter, self.sel_am, (am_det, 0)) self.tb.connect(self.sel_am, pll, self.pll_carrier_scale, self.pll_carrier_filter, c2f3) self.tb.connect((c2f3, 0), phaser1, (f2c, 0)) self.tb.connect((c2f3, 1), phaser2, (f2c, 1)) self.tb.connect(f2c, (am_det, 1)) self.tb.connect(am_det, c2f2, (combine, 0)) self.tb.connect(self.audio_filter, c2f, self.sel_sb, (combine, 1)) if AM_SYNC_DISPLAY: self.tb.connect(self.pll_carrier_filter, self.fft2) self.tb.connect(combine, self.scale) self.tb.connect(self.scale, (sqr1, 0)) self.tb.connect(self.scale, (sqr1, 1)) self.tb.connect(sqr1, intr, offset, (agc, 1)) self.tb.connect(self.scale, (agc, 0)) self.tb.connect(agc, dst) if SAVE_AUDIO_TO_FILE: f_out = gr.file_sink(gr.sizeof_short, options.audio_file) sc1 = gr.multiply_const_ff(64000) f2s1 = gr.float_to_short() self.tb.connect(agc, sc1, f2s1, f_out) self.tb.start() # for mouse position reporting on fft display self.fft.win.Bind(wx.EVT_LEFT_UP, self.Mouse) # and left click to re-tune self.fft.win.Bind(wx.EVT_LEFT_DOWN, self.Click) # start a timer to check for web commands if WEB_CONTROL: self.timer = UpdateTimer(self, 1000) # every 1000 mSec, 1 Sec wx.EVT_BUTTON(self, ID_BUTTON_1, self.set_lsb) wx.EVT_BUTTON(self, ID_BUTTON_2, self.set_usb) wx.EVT_BUTTON(self, ID_BUTTON_3, self.set_am) wx.EVT_BUTTON(self, ID_BUTTON_4, self.set_cw) wx.EVT_BUTTON(self, ID_BUTTON_10, self.fwd) wx.EVT_BUTTON(self, ID_BUTTON_11, self.rew) wx.EVT_BUTTON(self, ID_BUTTON_13, self.AT_calibrate) wx.EVT_BUTTON(self, ID_BUTTON_14, self.AT_reset) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_5, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_6, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_7, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_8, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_9, self.on_button) wx.EVT_SLIDER(self, ID_SLIDER_1, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_2, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_3, self.slide_tune) wx.EVT_SLIDER(self, ID_SLIDER_4, self.set_volume) wx.EVT_SLIDER(self, ID_SLIDER_5, self.set_pga) wx.EVT_SLIDER(self, ID_SLIDER_6, self.am_carrier) wx.EVT_SLIDER(self, ID_SLIDER_7, self.antenna_tune) wx.EVT_SPINCTRL(self, ID_SPIN_1, self.spin_tune) wx.EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def __init__(self, *args, **kwds): # begin wxGlade: MyFrame.__init__ kwds["style"] = wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) # Menu Bar self.frame_1_menubar = wx.MenuBar() self.SetMenuBar(self.frame_1_menubar) wxglade_tmp_menu = wx.Menu() self.Exit = wx.MenuItem(wxglade_tmp_menu, ID_EXIT, "Exit", "Exit", wx.ITEM_NORMAL) wxglade_tmp_menu.AppendItem(self.Exit) self.frame_1_menubar.Append(wxglade_tmp_menu, "File") # Menu Bar end self.panel_1 = wx.Panel(self, -1) self.button_1 = wx.Button(self, ID_BUTTON_1, "LSB") self.button_2 = wx.Button(self, ID_BUTTON_2, "USB") self.button_3 = wx.Button(self, ID_BUTTON_3, "AM") self.button_4 = wx.Button(self, ID_BUTTON_4, "CW") self.button_5 = wx.ToggleButton(self, ID_BUTTON_5, "Upper") self.slider_1 = wx.Slider(self, ID_SLIDER_1, 0, -15799, 15799, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.button_6 = wx.ToggleButton(self, ID_BUTTON_6, "Lower") self.slider_2 = wx.Slider(self, ID_SLIDER_2, 0, -15799, 15799, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_5 = wx.Panel(self, -1) self.label_1 = wx.StaticText(self, -1, " Band\nCenter") self.text_ctrl_1 = wx.TextCtrl(self, ID_TEXT_1, "") self.panel_6 = wx.Panel(self, -1) self.panel_7 = wx.Panel(self, -1) self.panel_2 = wx.Panel(self, -1) self.button_7 = wx.ToggleButton(self, ID_BUTTON_7, "Freq") self.slider_3 = wx.Slider(self, ID_SLIDER_3, 3000, 0, 6000) self.spin_ctrl_1 = wx.SpinCtrl(self, ID_SPIN_1, "", min=0, max=100) self.button_8 = wx.ToggleButton(self, ID_BUTTON_8, "Vol") self.slider_4 = wx.Slider(self, ID_SLIDER_4, 0, 0, 500) self.slider_5 = wx.Slider(self, ID_SLIDER_5, 0, 0, 20) self.button_9 = wx.ToggleButton(self, ID_BUTTON_9, "Time") self.button_11 = wx.Button(self, ID_BUTTON_11, "Rew") self.button_10 = wx.Button(self, ID_BUTTON_10, "Fwd") self.panel_3 = wx.Panel(self, -1) self.label_2 = wx.StaticText(self, -1, "PGA ") self.panel_4 = wx.Panel(self, -1) self.panel_8 = wx.Panel(self, -1) self.panel_9 = wx.Panel(self, -1) self.label_3 = wx.StaticText(self, -1, "AM Sync\nCarrier") self.slider_6 = wx.Slider(self, ID_SLIDER_6, 50, 0, 200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.label_4 = wx.StaticText(self, -1, "Antenna Tune") self.slider_7 = wx.Slider(self, ID_SLIDER_7, 1575, 950, 2200, style=wx.SL_HORIZONTAL | wx.SL_LABELS) self.panel_10 = wx.Panel(self, -1) self.button_12 = wx.ToggleButton(self, ID_BUTTON_12, "Auto Tune") self.button_13 = wx.Button(self, ID_BUTTON_13, "Calibrate") self.button_14 = wx.Button(self, ID_BUTTON_14, "Reset") self.panel_11 = wx.Panel(self, -1) self.panel_12 = wx.Panel(self, -1) self.__set_properties() self.__do_layout() # end wxGlade parser = OptionParser(option_class=eng_option) parser.add_option( "-c", "--ddc-freq", type="eng_float", default=3.9e6, help="set Rx DDC frequency to FREQ", metavar="FREQ" ) parser.add_option("-a", "--audio_file", default="", help="audio output file", metavar="FILE") parser.add_option("-r", "--radio_file", default="", help="radio output file", metavar="FILE") parser.add_option("-i", "--input_file", default="", help="radio input file", metavar="FILE") parser.add_option("-d", "--decim", type="int", default=250, help="USRP decimation") parser.add_option( "-R", "--rx-subdev-spec", type="subdev", default=None, help="select USRP Rx side A or B (default=first one with a daughterboard)", ) (options, args) = parser.parse_args() self.usrp_center = options.ddc_freq usb_rate = 64e6 / options.decim self.slider_range = usb_rate * 0.9375 self.f_lo = self.usrp_center - (self.slider_range / 2) self.f_hi = self.usrp_center + (self.slider_range / 2) self.af_sample_rate = 32000 fir_decim = long(usb_rate / self.af_sample_rate) # data point arrays for antenna tuner self.xdata = [] self.ydata = [] self.tb = gr.top_block() # radio variables, initial conditions self.frequency = self.usrp_center # these map the frequency slider (0-6000) to the actual range self.f_slider_offset = self.f_lo self.f_slider_scale = 10000 / options.decim self.spin_ctrl_1.SetRange(self.f_lo, self.f_hi) self.text_ctrl_1.SetValue(str(int(self.usrp_center))) self.slider_5.SetValue(0) self.AM_mode = False self.slider_3.SetValue((self.frequency - self.f_slider_offset) / self.f_slider_scale) self.spin_ctrl_1.SetValue(int(self.frequency)) POWERMATE = True try: self.pm = powermate.powermate(self) except: sys.stderr.write("Unable to find PowerMate or Contour Shuttle\n") POWERMATE = False if POWERMATE: powermate.EVT_POWERMATE_ROTATE(self, self.on_rotate) powermate.EVT_POWERMATE_BUTTON(self, self.on_pmButton) self.active_button = 7 # command line options if options.audio_file == "": SAVE_AUDIO_TO_FILE = False else: SAVE_AUDIO_TO_FILE = True if options.radio_file == "": SAVE_RADIO_TO_FILE = False else: SAVE_RADIO_TO_FILE = True if options.input_file == "": self.PLAY_FROM_USRP = True else: self.PLAY_FROM_USRP = False if self.PLAY_FROM_USRP: self.src = usrp.source_s(decim_rate=options.decim) if options.rx_subdev_spec is None: options.rx_subdev_spec = pick_subdevice(self.src) self.src.set_mux(usrp.determine_rx_mux_value(self.src, options.rx_subdev_spec)) self.subdev = usrp.selected_subdev(self.src, options.rx_subdev_spec) self.src.tune(0, self.subdev, self.usrp_center) self.tune_offset = 0 # -self.usrp_center - self.src.rx_freq(0) else: self.src = gr.file_source(gr.sizeof_short, options.input_file) self.tune_offset = 2200 # 2200 works for 3.5-4Mhz band # save radio data to a file if SAVE_RADIO_TO_FILE: file = gr.file_sink(gr.sizeof_short, options.radio_file) self.tb.connect(self.src, file) # 2nd DDC xlate_taps = gr.firdes.low_pass(1.0, usb_rate, 16e3, 4e3, gr.firdes.WIN_HAMMING) self.xlate = gr.freq_xlating_fir_filter_ccf(fir_decim, xlate_taps, self.tune_offset, usb_rate) # convert rf data in interleaved short int form to complex s2ss = gr.stream_to_streams(gr.sizeof_short, 2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src_f2c = gr.float_to_complex() self.tb.connect(self.src, s2ss) self.tb.connect((s2ss, 0), s2f1) self.tb.connect((s2ss, 1), s2f2) self.tb.connect(s2f1, (src_f2c, 0)) self.tb.connect(s2f2, (src_f2c, 1)) # Complex Audio filter audio_coeffs = gr.firdes.complex_band_pass( 1.0, # gain self.af_sample_rate, # sample rate -3000, # low cutoff 0, # high cutoff 100, # transition gr.firdes.WIN_HAMMING, ) # window self.slider_1.SetValue(0) self.slider_2.SetValue(-3000) self.audio_filter = gr.fir_filter_ccc(1, audio_coeffs) # Main +/- 16Khz spectrum display self.fft = fftsink2.fft_sink_c( self.panel_2, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240) ) # AM Sync carrier if AM_SYNC_DISPLAY: self.fft2 = fftsink.fft_sink_c( self.tb, self.panel_9, y_per_div=20, fft_size=512, sample_rate=self.af_sample_rate, average=True, size=(640, 240), ) c2f = gr.complex_to_float() # AM branch self.sel_am = gr.multiply_const_cc(0) # the following frequencies turn out to be in radians/sample # gr.pll_refout_cc(alpha,beta,min_freq,max_freq) # suggested alpha = X, beta = .25 * X * X pll = gr.pll_refout_cc( 0.5, 0.0625, (2.0 * math.pi * 7.5e3 / self.af_sample_rate), (2.0 * math.pi * 6.5e3 / self.af_sample_rate) ) self.pll_carrier_scale = gr.multiply_const_cc(complex(10, 0)) am_det = gr.multiply_cc() # these are for converting +7.5kHz to -7.5kHz # for some reason gr.conjugate_cc() adds noise ?? c2f2 = gr.complex_to_float() c2f3 = gr.complex_to_float() f2c = gr.float_to_complex() phaser1 = gr.multiply_const_ff(1) phaser2 = gr.multiply_const_ff(-1) # filter for pll generated carrier pll_carrier_coeffs = gr.firdes.complex_band_pass( 2.0, # gain self.af_sample_rate, # sample rate 7400, # low cutoff 7600, # high cutoff 100, # transition gr.firdes.WIN_HAMMING, ) # window self.pll_carrier_filter = gr.fir_filter_ccc(1, pll_carrier_coeffs) self.sel_sb = gr.multiply_const_ff(1) combine = gr.add_ff() # AGC sqr1 = gr.multiply_ff() intr = gr.iir_filter_ffd([0.004, 0], [0, 0.999]) offset = gr.add_const_ff(1) agc = gr.divide_ff() self.scale = gr.multiply_const_ff(0.00001) dst = audio.sink(long(self.af_sample_rate)) self.tb.connect(src_f2c, self.xlate, self.fft) self.tb.connect(self.xlate, self.audio_filter, self.sel_am, (am_det, 0)) self.tb.connect(self.sel_am, pll, self.pll_carrier_scale, self.pll_carrier_filter, c2f3) self.tb.connect((c2f3, 0), phaser1, (f2c, 0)) self.tb.connect((c2f3, 1), phaser2, (f2c, 1)) self.tb.connect(f2c, (am_det, 1)) self.tb.connect(am_det, c2f2, (combine, 0)) self.tb.connect(self.audio_filter, c2f, self.sel_sb, (combine, 1)) if AM_SYNC_DISPLAY: self.tb.connect(self.pll_carrier_filter, self.fft2) self.tb.connect(combine, self.scale) self.tb.connect(self.scale, (sqr1, 0)) self.tb.connect(self.scale, (sqr1, 1)) self.tb.connect(sqr1, intr, offset, (agc, 1)) self.tb.connect(self.scale, (agc, 0)) self.tb.connect(agc, dst) if SAVE_AUDIO_TO_FILE: f_out = gr.file_sink(gr.sizeof_short, options.audio_file) sc1 = gr.multiply_const_ff(64000) f2s1 = gr.float_to_short() self.tb.connect(agc, sc1, f2s1, f_out) self.tb.start() # for mouse position reporting on fft display em.eventManager.Register(self.Mouse, wx.EVT_MOTION, self.fft.win) # and left click to re-tune em.eventManager.Register(self.Click, wx.EVT_LEFT_DOWN, self.fft.win) # start a timer to check for web commands if WEB_CONTROL: self.timer = UpdateTimer(self, 1000) # every 1000 mSec, 1 Sec wx.EVT_BUTTON(self, ID_BUTTON_1, self.set_lsb) wx.EVT_BUTTON(self, ID_BUTTON_2, self.set_usb) wx.EVT_BUTTON(self, ID_BUTTON_3, self.set_am) wx.EVT_BUTTON(self, ID_BUTTON_4, self.set_cw) wx.EVT_BUTTON(self, ID_BUTTON_10, self.fwd) wx.EVT_BUTTON(self, ID_BUTTON_11, self.rew) wx.EVT_BUTTON(self, ID_BUTTON_13, self.AT_calibrate) wx.EVT_BUTTON(self, ID_BUTTON_14, self.AT_reset) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_5, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_6, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_7, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_8, self.on_button) wx.EVT_TOGGLEBUTTON(self, ID_BUTTON_9, self.on_button) wx.EVT_SLIDER(self, ID_SLIDER_1, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_2, self.set_filter) wx.EVT_SLIDER(self, ID_SLIDER_3, self.slide_tune) wx.EVT_SLIDER(self, ID_SLIDER_4, self.set_volume) wx.EVT_SLIDER(self, ID_SLIDER_5, self.set_pga) wx.EVT_SLIDER(self, ID_SLIDER_6, self.am_carrier) wx.EVT_SLIDER(self, ID_SLIDER_7, self.antenna_tune) wx.EVT_SPINCTRL(self, ID_SPIN_1, self.spin_tune) wx.EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def test_000(self): N = 1000 # number of samples to use M = 5 # Number of channels to channelize fs = 1000 # baseband sampling rate ifs = M * fs # input samp rate to channelizer taps = filter.firdes.low_pass_2( 1, ifs, 500, 50, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) signals = list() add = gr.add_cc() freqs = [-200, -100, 0, 100, 200] for i in xrange(len(freqs)): f = freqs[i] + (M / 2 - M + i + 1) * fs signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1)) self.tb.connect(signals[i], (add, i)) head = gr.head(gr.sizeof_gr_complex, N) s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M) pfb = filter.pfb_channelizer_ccf(M, taps, 1) self.tb.connect(add, head, s2ss) snks = list() for i in xrange(M): snks.append(gr.vector_sink_c()) self.tb.connect((s2ss, i), (pfb, i)) self.tb.connect((pfb, i), snks[i]) self.tb.run() Ntest = 50 L = len(snks[0].data()) t = map(lambda x: float(x) / fs, xrange(L)) # Adjusted phase rotations for data p0 = 0 p1 = math.pi * 0.51998885 p2 = -math.pi * 0.96002233 p3 = math.pi * 0.96002233 p4 = -math.pi * 0.51998885 # Create known data as complex sinusoids at the different baseband freqs # the different channel numbering is due to channelizer output order. expected0_data = map(lambda x: math.cos(2.*math.pi*freqs[2]*x+p0) + \ 1j*math.sin(2.*math.pi*freqs[2]*x+p0), t) expected1_data = map(lambda x: math.cos(2.*math.pi*freqs[3]*x+p1) + \ 1j*math.sin(2.*math.pi*freqs[3]*x+p1), t) expected2_data = map(lambda x: math.cos(2.*math.pi*freqs[4]*x+p2) + \ 1j*math.sin(2.*math.pi*freqs[4]*x+p2), t) expected3_data = map(lambda x: math.cos(2.*math.pi*freqs[0]*x+p3) + \ 1j*math.sin(2.*math.pi*freqs[0]*x+p3), t) expected4_data = map(lambda x: math.cos(2.*math.pi*freqs[1]*x+p4) + \ 1j*math.sin(2.*math.pi*freqs[1]*x+p4), t) dst0_data = snks[0].data() dst1_data = snks[1].data() dst2_data = snks[2].data() dst3_data = snks[3].data() dst4_data = snks[4].data() self.assertComplexTuplesAlmostEqual(expected0_data[-Ntest:], dst0_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected1_data[-Ntest:], dst1_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected2_data[-Ntest:], dst2_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected3_data[-Ntest:], dst3_data[-Ntest:], 3) self.assertComplexTuplesAlmostEqual(expected4_data[-Ntest:], dst4_data[-Ntest:], 3)
def graph (args): nargs = len(args) if nargs == 2: infile = args[0] outfile = args[1] else: raise ValueError('usage: interp.py input_file output_file\n') tb = gr.top_block () # Convert to a from shorts to a stream of complex numbers. srcf = gr.file_source (gr.sizeof_short,infile) s2ss = gr.stream_to_streams(gr.sizeof_short,2) s2f1 = gr.short_to_float() s2f2 = gr.short_to_float() src0 = gr.float_to_complex() tb.connect(srcf, s2ss) tb.connect((s2ss, 0), s2f1, (src0, 0)) tb.connect((s2ss, 1), s2f2, (src0, 1)) # Low pass filter it and increase sample rate by a factor of 3. lp_coeffs = gr.firdes.low_pass ( 3, 19.2e6, 3.2e6, .5e6, gr.firdes.WIN_HAMMING ) lp = gr.interp_fir_filter_ccf ( 3, lp_coeffs ) tb.connect(src0, lp) # Upconvert it. duc_coeffs = gr.firdes.low_pass ( 1, 19.2e6, 9e6, 1e6, gr.firdes.WIN_HAMMING ) duc = gr.freq_xlating_fir_filter_ccf ( 1, duc_coeffs, 5.75e6, 19.2e6 ) # Discard the imaginary component. c2f = gr.complex_to_float() tb.connect(lp, duc, c2f) # Frequency Phase Lock Loop input_rate = 19.2e6 IF_freq = 5.75e6 # 1/2 as wide because we're designing lp filter symbol_rate = atsc.ATSC_SYMBOL_RATE/2. NTAPS = 279 tt = gr.firdes.root_raised_cosine (1.0, input_rate, symbol_rate, .115, NTAPS) # heterodyne the low pass coefficients up to the specified bandpass # center frequency. Note that when we do this, the filter bandwidth # is effectively twice the low pass (2.69 * 2 = 5.38) and hence # matches the diagram in the ATSC spec. arg = 2. * math.pi * IF_freq / input_rate t=[] for i in range(len(tt)): t += [tt[i] * 2. * math.cos(arg * i)] rrc = gr.fir_filter_fff(1, t) fpll = atsc.fpll() pilot_freq = IF_freq - 3e6 + 0.31e6 lower_edge = 6e6 - 0.31e6 upper_edge = IF_freq - 3e6 + pilot_freq transition_width = upper_edge - lower_edge lp_coeffs = gr.firdes.low_pass (1.0, input_rate, (lower_edge + upper_edge) * 0.5, transition_width, gr.firdes.WIN_HAMMING); lp_filter = gr.fir_filter_fff (1,lp_coeffs) alpha = 1e-5 iir = gr.single_pole_iir_filter_ff(alpha) remove_dc = gr.sub_ff() tb.connect(c2f, fpll, lp_filter) tb.connect(lp_filter, iir) tb.connect(lp_filter, (remove_dc,0)) tb.connect(iir, (remove_dc,1)) # Bit Timing Loop, Field Sync Checker and Equalizer btl = atsc.bit_timing_loop() fsc = atsc.fs_checker() eq = atsc.equalizer() fsd = atsc.field_sync_demux() tb.connect(remove_dc, btl) tb.connect((btl, 0),(fsc, 0),(eq, 0),(fsd, 0)) tb.connect((btl, 1),(fsc, 1),(eq, 1),(fsd, 1)) # Viterbi viterbi = atsc.viterbi_decoder() deinter = atsc.deinterleaver() rs_dec = atsc.rs_decoder() derand = atsc.derandomizer() depad = atsc.depad() dst = gr.file_sink(gr.sizeof_char, outfile) tb.connect(fsd, viterbi, deinter, rs_dec, derand, depad, dst) dst2 = gr.file_sink(gr.sizeof_gr_complex, "atsc_complex.data") tb.connect(src0, dst2) tb.run ()