Example #1
0
  def __init__(self, fft_length):
    gr.hier_block2.__init__(self, "timing_metric",
        gr.io_signature(1,1,gr.sizeof_gr_complex),
        gr.io_signature(1,1,gr.sizeof_float))

    self.input = gr.kludge_copy(gr.sizeof_gr_complex)
    self.connect(self,self.input)

    # P(d)
    nominator = schmidl_nominator(fft_length)

    # R(d)
    denominator = schmidl_denominator(fft_length)

    # |P(d)| ** 2 / (R(d)) ** 2
    p_mag_sqrd = gr.complex_to_mag_squared()
    r_sqrd = gr.multiply_ff()
    self.timing_metric = gr.divide_ff()

    self.connect(self.input, nominator, p_mag_sqrd, (self.timing_metric,0))
    self.connect(self.input, denominator, (r_sqrd,0))
    self.connect(denominator, (r_sqrd,1))
    self.connect(r_sqrd, (self.timing_metric,1))
    self.connect(self.timing_metric, self)

    # calculate epsilon from P(d), epsilon is normalized fractional frequency offset
    #angle = gr.complex_to_arg()
    #self.epsilon = gr.multiply_const_ff(1.0/math.pi)
    #self.connect(nominator, angle, self.epsilon)

    try:
        gr.hier_block.update_var_names(self, "schmidl", vars())
        gr.hier_block.update_var_names(self, "schmidl", vars(self))
    except:
        pass
Example #2
0
    def __init__(self):
        gr.top_block.__init__(self)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-I", "--audio-input", type="string", default="",
                          help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_option("-O", "--audio-output", type="string", default="",
                          help="pcm output device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_option("-r", "--sample-rate", type="eng_float", default=8000,
                          help="set sample rate to RATE (8000)")
        (options, args) = parser.parse_args ()
        if len(args) != 0:
            parser.print_help()
            raise SystemExit, 1

        sample_rate = int(options.sample_rate)
        src = audio.source (sample_rate, options.audio_input)
        dst = audio.sink (sample_rate, options.audio_output)

	vec1 = [1, -1]
	vsource = gr.vector_source_f(vec1, True)
	multiply = gr.multiply_ff()

	self.connect(src, (multiply, 0))
	self.connect(vsource, (multiply, 1))
	self.connect(multiply, dst)
Example #3
0
    def __init__(self):
        gr.top_block.__init__(self)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-O", "--audio-output", type="string", default="",
                          help="pcm output device name")
        parser.add_option("-r", "--sample-rate", type="eng_float", default=192000,
                          help="set sample rate to RATE (192000)")
        parser.add_option("-f", "--frequency", type="eng_float", default=1000)
        parser.add_option("-a", "--amplitude", type="eng_float", default=0.5)

        (options, args) = parser.parse_args ()
        if len(args) != 0:
            parser.print_help()
            raise SystemExit, 1

        sample_rate = int(options.sample_rate)
        ampl = float(options.amplitude)
        pulse_freq = 1.0 # 1Hz
        pulse_dc = 0.1 # Low DC value to give high/low value rather than on/off
        if ampl > 1.0: ampl = 1.0

        osc = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, options.frequency, ampl)
        pulse =  gr.sig_source_f (sample_rate, gr.GR_SQR_WAVE, pulse_freq, .8, pulse_dc)
        mixer = gr.multiply_ff ()
        self.connect (osc, (mixer, 0))
        self.connect (pulse, (mixer, 1))
        dst = audio.sink (sample_rate, options.audio_output, True)
        self.connect (mixer, dst)
Example #4
0
  def __init__(self, fft_length, pn_weights):
    gr.hier_block2.__init__(self, "modified_timing_metric",
        gr.io_signature(1,1,gr.sizeof_gr_complex),
        gr.io_signature(1,1,gr.sizeof_float))

    assert(len(pn_weights) == fft_length)

    self.input = gr.kludge_copy(gr.sizeof_gr_complex)
    self.connect(self,self.input)

    # P(d) = sum(0 to L-1, conj(delayed(r)) * r)
    conj = gr.conjugate_cc()
    mixer = gr.multiply_cc()
    nominator = gr.fir_filter_ccf(1,[pn_weights[fft_length-i-1]*pn_weights[fft_length/2-i-1] for i in range(fft_length/2)])

    self.connect(self.input, delay(gr.sizeof_gr_complex,fft_length/2), conj, (mixer,0))
    self.connect(self.input, (mixer,1))
    self.connect(mixer, nominator)
    # moving_avg = P(d)

    # R(d)
    denominator = schmidl_denominator(fft_length)

    # |P(d)| ** 2 / (R(d)) ** 2
    p_mag_sqrd = gr.complex_to_mag_squared()
    r_sqrd = gr.multiply_ff()
    self.timing_metric = gr.divide_ff()

    self.connect(nominator, p_mag_sqrd, (self.timing_metric,0))
    self.connect(self.input, denominator, (r_sqrd,0))
    self.connect(denominator, (r_sqrd,1))
    self.connect(r_sqrd, (self.timing_metric,1))
    self.connect(self.timing_metric, self)
Example #5
0
 def test_mult_ff (self):
     src1_data = (1,  2, 3, 4, 5)
     src2_data = (8, -3, 4, 8, 2)
     expected_result = (8, -6, 12, 32, 10)
     op = gr.multiply_ff ()
     self.help_ff ((src1_data, src2_data),
                   expected_result, op)
 def test_mult_ff (self):
     # Note: the GNUHawk multiply_ff only outputs data in multiples of 8,
     # so this test has been modified accordingly
     src1_data = (1,  2, 3, 4, 5, 6, 7, 8)
     src2_data = (8, -3, 4, 8, 2, -0.5, -1, 1.5)
     expected_result = (8, -6, 12, 32, 10, -3, -7, 12)
     op = gr.multiply_ff ()
     self.help_ff ((src1_data, src2_data),
                   expected_result, op)
    def __init__(self, audio_rate):
	gr.hier_block2.__init__(self, "standard_squelch",
				gr.io_signature(1, 1, gr.sizeof_float), # Input signature
				gr.io_signature(1, 1, gr.sizeof_float)) # Output signature

        self.input_node = gr.add_const_ff(0)          # FIXME kludge

        self.low_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.9524,-0.9615))
        self.low_square = gr.multiply_ff()
        self.low_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))   # 100ms time constant

        self.hi_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.3597,-0.9615))
        self.hi_square = gr.multiply_ff()
        self.hi_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))

        self.sub = gr.sub_ff();
        self.add = gr.add_ff();
        self.gate = gr.threshold_ff(0.3,0.43,0)
        self.squelch_lpf = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))

        self.div = gr.divide_ff()
        self.squelch_mult = gr.multiply_ff()

	self.connect (self, self.input_node)
        self.connect (self.input_node, (self.squelch_mult, 0))

        self.connect (self.input_node,self.low_iir)
        self.connect (self.low_iir,(self.low_square,0))
        self.connect (self.low_iir,(self.low_square,1))
        self.connect (self.low_square,self.low_smooth,(self.sub,0))
        self.connect (self.low_smooth, (self.add,0))

        self.connect (self.input_node,self.hi_iir)
        self.connect (self.hi_iir,(self.hi_square,0))
        self.connect (self.hi_iir,(self.hi_square,1))
        self.connect (self.hi_square,self.hi_smooth,(self.sub,1))
        self.connect (self.hi_smooth, (self.add,1))

        self.connect (self.sub, (self.div, 0))
        self.connect (self.add, (self.div, 1))
        self.connect (self.div, self.gate, self.squelch_lpf, (self.squelch_mult,1))
	self.connect (self.squelch_mult, self)
	def __init__(self):
		gr.top_block.__init__(self, "FSK Demod Demo")

		# Variables
		self.symbol_rate = symbol_rate = 125e3
		self.samp_rate = samp_rate = symbol_rate
		self.f_center = f_center = 868e6
		self.sps = sps = 2
		self.sensitivity = sensitivity = (pi / 2) / sps
		self.alpha = alpha = 0.0512/sps
		self.bandwidth = bandwidth = 100e3

		# Blocks
		self.uhd_usrp_source_0 = uhd.usrp_source(
			device_addr="",
			stream_args=uhd.stream_args(
				cpu_format="fc32",
				channels=range(1),
			),
		)
		self.uhd_usrp_source_0.set_samp_rate(samp_rate)
		self.uhd_usrp_source_0.set_center_freq(f_center, 0)
		self.uhd_usrp_source_0.set_gain(0, 0)
		self.uhd_usrp_source_0.set_bandwidth(bandwidth, 0)

		self.fm_demod = gr.quadrature_demod_cf(1 / sensitivity)
		
		self.freq_offset = gr.single_pole_iir_filter_ff(alpha)
		self.sub = gr.sub_ff()
		self.add = gr.add_ff()
		self.multiply = gr.multiply_ff()
		self.invert = gr.multiply_const_vff((-1, ))

		# recover the clock
		omega = sps
		gain_mu = 0.03
		mu = 0.5
		omega_relative_limit = 0.0002
		freq_error = 0.0
		gain_omega = .25 * gain_mu * gain_mu        # critically damped
		self.clock_recovery = digital.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, omega_relative_limit)

		self.slice = digital.binary_slicer_fb()
		self.sink = gr.vector_sink_b(1)
		self.file_sink = gr.file_sink(gr.sizeof_char, 'fsk_dump.log')

		# Connections
		self.connect(self.fm_demod, (self.add, 0))
		self.connect(self.fm_demod, self.freq_offset, (self.add, 1))
		self.connect(self.uhd_usrp_source_0, self.fm_demod)
		self.connect(self.add, self.clock_recovery, self.invert, self.slice, self.file_sink)
		self.connect(self.slice, self.sink)
    def __init__(self, fg, audio_rate):
    
        self.input_node = gr.add_const_ff(0)          # FIXME kludge
        
        self.low_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.9524,-0.9615))
        self.low_square = gr.multiply_ff()
        self.low_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))   # 100ms time constant

        self.hi_iir = gr.iir_filter_ffd((0.0193,0,-0.0193),(1,1.3597,-0.9615))
        self.hi_square = gr.multiply_ff()
        self.hi_smooth = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))

        self.sub = gr.sub_ff();
        self.add = gr.add_ff();
        self.gate = gr.threshold_ff(0.3,0.43,0)
        self.squelch_lpf = gr.single_pole_iir_filter_ff(1/(0.01*audio_rate))

        self.div = gr.divide_ff()
        self.squelch_mult = gr.multiply_ff()

        fg.connect (self.input_node, (self.squelch_mult, 0))

        fg.connect (self.input_node,self.low_iir)
        fg.connect (self.low_iir,(self.low_square,0))
        fg.connect (self.low_iir,(self.low_square,1))
        fg.connect (self.low_square,self.low_smooth,(self.sub,0))
        fg.connect (self.low_smooth, (self.add,0))

        fg.connect (self.input_node,self.hi_iir)
        fg.connect (self.hi_iir,(self.hi_square,0))
        fg.connect (self.hi_iir,(self.hi_square,1))
        fg.connect (self.hi_square,self.hi_smooth,(self.sub,1))
        fg.connect (self.hi_smooth, (self.add,1))

        fg.connect (self.sub, (self.div, 0))
        fg.connect (self.add, (self.div, 1))
        fg.connect (self.div, self.gate, self.squelch_lpf, (self.squelch_mult,1))

        gr.hier_block.__init__(self, fg, self.input_node, self.squelch_mult)
Example #10
0
  def __init__(self,vlen):
    gr.hier_block2.__init__(self,"snr_estimator",
      gr.io_signature(2,2,gr.sizeof_gr_complex*vlen),
      gr.io_signature(1,1,gr.sizeof_float))

    reference = gr.kludge_copy(gr.sizeof_gr_complex*vlen)
    received = gr.kludge_copy(gr.sizeof_gr_complex*vlen)
    self.connect((self,0),reference)
    self.connect((self,1),received)

    received_conjugated = gr.conjugate_cc(vlen)
    self.connect(received,received_conjugated)

    R_innerproduct = gr.multiply_vcc(vlen)
    self.connect(reference,R_innerproduct)
    self.connect(received_conjugated,(R_innerproduct,1))

    R_sum = vector_sum_vcc(vlen)
    self.connect(R_innerproduct,R_sum)

    R = gr.complex_to_mag_squared()
    self.connect(R_sum,R)

    received_magsqrd = gr.complex_to_mag_squared(vlen)
    reference_magsqrd = gr.complex_to_mag_squared(vlen)
    self.connect(received,received_magsqrd)
    self.connect(reference,reference_magsqrd)

    received_sum = vector_sum_vff(vlen)
    reference_sum = vector_sum_vff(vlen)
    self.connect(received_magsqrd,received_sum)
    self.connect(reference_magsqrd,reference_sum)

    P = gr.multiply_ff()
    self.connect(received_sum,(P,0))
    self.connect(reference_sum,(P,1))

    denominator = gr.sub_ff()
    self.connect(P,denominator)
    self.connect(R,(denominator,1))

    rho_hat = gr.divide_ff()
    self.connect(R,rho_hat)
    self.connect(denominator,(rho_hat,1))
    self.connect(rho_hat,self)
    def __init__(self, fg,  lo_freq, usrp_rate):


        cl = dcf77.clock(07, # hour
                         35-2, # min
                         6,  # day in month
                         7,  # day of week
                         2,  # month
                         8,  # year
                         0)  # loop
        tx = dcf77.mod(usrp_rate)
	f2c = gr.float_to_complex()

        mixer = gr.multiply_ff()

        fg.connect (cl, tx, f2c)
        
        gr.hier_block.__init__(self, fg, cl, f2c)
Example #12
0
File: ssbagc.py Project: jinjoh/SDR
    def __init__(self, fg):
        self.split = gr.multiply_const_ff(1)
        self.sqr = gr.multiply_ff()
        self.int0 = gr.iir_filter_ffd([0.004, 0], [0, 0.999])
        self.offs = gr.add_const_ff(-30)
        self.gain = gr.multiply_const_ff(70)
        self.log = gr.nlog10_ff(10, 1)
        self.agc = gr.divide_ff()

        fg.connect(self.split, (self.agc, 0))
        fg.connect(self.split, (self.sqr, 0))
        fg.connect(self.split, (self.sqr, 1))
        fg.connect(self.sqr, self.int0)
        fg.connect(self.int0, self.log)
        fg.connect(self.log, self.offs)
        fg.connect(self.offs, self.gain)
        fg.connect(self.gain, (self.agc, 1))

        gr.hier_block.__init__(self, fg, self.split, self.agc)
Example #13
0
    def __init__(self):

        gr.hier_block2.__init__(self,"BER Estimator",
                                gr.io_signature(1,1,gr.sizeof_float),
                                gr.io_signature(1,1,gr.sizeof_float))
        
        #TODO Implement a polynomial block in C++ and approximate with polynomials
        #of arbitrary order
        self.add = gr.add_const_vff((-1, ))
        self.square = gr.multiply_ff()
        self.mult_lin = gr.multiply_const_ff(-0.20473967)
        self.mult_sq = gr.multiply_const_ff(1.5228658)
        self.sum = gr.add_ff()
        self.connect(self,self.add)
        self.connect(self.add,(self.square,0))
        self.connect(self.add,(self.square,1))
        self.connect(self.square,self.mult_sq,(self.sum,0))
        self.connect(self.add,self.mult_lin,(self.sum,1))
        self.connect(self.sum,self)
Example #14
0
 def __init__ ( self, fft_length ):
   gr.hier_block2.__init__(self, "recursive_timing_metric",
       gr.io_signature(1,1,gr.sizeof_gr_complex),
       gr.io_signature(1,1,gr.sizeof_float))
   
   self.input = gr.kludge_copy(gr.sizeof_gr_complex)
   self.connect(self, self.input)
   
   # P(d) = sum(0 to L-1, conj(delayed(r)) * r)
   conj = gr.conjugate_cc()
   mixer = gr.multiply_cc()
   mix_delay = delay(gr.sizeof_gr_complex,fft_length/2+1)
   mix_diff = gr.sub_cc()
   nominator = accumulator_cc()
   inpdelay = delay(gr.sizeof_gr_complex,fft_length/2)
   
   self.connect(self.input, inpdelay, 
                conj, (mixer,0))
   self.connect(self.input, (mixer,1))
   self.connect(mixer,(mix_diff,0))
   self.connect(mixer, mix_delay, (mix_diff,1))
   self.connect(mix_diff,nominator)
   
   rmagsqrd = gr.complex_to_mag_squared()
   rm_delay = delay(gr.sizeof_float,fft_length+1)
   rm_diff = gr.sub_ff()
   denom = accumulator_ff()
   self.connect(self.input,rmagsqrd,rm_diff,gr.multiply_const_ff(0.5),denom)
   self.connect(rmagsqrd,rm_delay,(rm_diff,1))
   
   
   ps = gr.complex_to_mag_squared()
   rs = gr.multiply_ff()
   self.connect(nominator,ps)
   self.connect(denom,rs)
   self.connect(denom,(rs,1))
   
   div = gr.divide_ff()
   self.connect(ps,div)
   self.connect(rs,(div,1))
   
   self.connect(div,self)
Example #15
0
    def __init__(self):
        """
        Hierarchical block for FSK demodulation.
    
        The input is the complex modulated signal at baseband
        and the output is a stream of floats.
        """
        # Initialize base class
        gr.hier_block2.__init__(
            self, "fsk_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)
        )

        # Variables
        self.sps = sps = 2
        self.sensitivity = sensitivity = (pi / 2) / sps
        self.alpha = alpha = 0.0512 / sps

        self.fm_demod = gr.quadrature_demod_cf(1 / sensitivity)

        self.freq_offset = gr.single_pole_iir_filter_ff(alpha)
        self.sub = gr.sub_ff()
        self.add = gr.add_ff()
        self.multiply = gr.multiply_ff()
        self.invert = gr.multiply_const_vff((-1,))

        # recover the clock
        omega = sps
        gain_mu = 0.03
        mu = 0.5
        omega_relative_limit = 0.0002
        freq_error = 0.0
        gain_omega = 0.25 * gain_mu * gain_mu  # critically damped
        self.clock_recovery = digital.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, omega_relative_limit)

        self.slice = digital.binary_slicer_fb()

        # Connections
        self.connect(self.fm_demod, (self.add, 0))
        self.connect(self.fm_demod, self.freq_offset, (self.add, 1))
        self.connect(self, self.fm_demod)
        self.connect(self.add, self.clock_recovery, self.invert, self)
Example #16
0
    def __init__( self ):
        gr.hier_block2.__init__(self, "agc",
                                gr.io_signature(1,1,gr.sizeof_float),
                                gr.io_signature(1,1,gr.sizeof_float))

        self.split = gr.multiply_const_ff( 1 )
        self.sqr   = gr.multiply_ff( )
        self.int0  = gr.iir_filter_ffd( [.004, 0], [0, .999] )
        self.offs  = gr.add_const_ff( -30 )
        self.gain  = gr.multiply_const_ff( 70 )
        self.log   = gr.nlog10_ff( 10, 1 )
        self.agc   = gr.divide_ff( )

        self.connect(self,       self.split)
        self.connect(self.split, (self.agc, 0))
        self.connect(self.split, (self.sqr, 0))
        self.connect(self.split, (self.sqr, 1))
        self.connect(self.sqr,    self.int0)
        self.connect(self.int0,   self.log)
        self.connect(self.log,    self.offs)
        self.connect(self.offs,   self.gain)
        self.connect(self.gain,  (self.agc, 1))
        self.connect(self.agc,    self)
Example #17
0
    def __init__(self):
        gr.hier_block2.__init__(self, "agc",
                                gr.io_signature(1, 1, gr.sizeof_float),
                                gr.io_signature(1, 1, gr.sizeof_float))

        self.split = gr.multiply_const_ff(1)
        self.sqr = gr.multiply_ff()
        self.int0 = gr.iir_filter_ffd([.004, 0], [0, .999])
        self.offs = gr.add_const_ff(-30)
        self.gain = gr.multiply_const_ff(70)
        self.log = gr.nlog10_ff(10, 1)
        self.agc = gr.divide_ff()

        self.connect(self, self.split)
        self.connect(self.split, (self.agc, 0))
        self.connect(self.split, (self.sqr, 0))
        self.connect(self.split, (self.sqr, 1))
        self.connect(self.sqr, self.int0)
        self.connect(self.int0, self.log)
        self.connect(self.log, self.offs)
        self.connect(self.offs, self.gain)
        self.connect(self.gain, (self.agc, 1))
        self.connect(self.agc, self)
Example #18
0
    def __init__(self, fft_length, pn_weights):
        gr.hier_block2.__init__(self, "modified_timing_metric",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                gr.io_signature(1, 1, gr.sizeof_float))

        assert (len(pn_weights) == fft_length)

        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, self.input)

        # P(d) = sum(0 to L-1, conj(delayed(r)) * r)
        conj = gr.conjugate_cc()
        mixer = gr.multiply_cc()
        nominator = gr.fir_filter_ccf(1, [
            pn_weights[fft_length - i - 1] * pn_weights[fft_length / 2 - i - 1]
            for i in range(fft_length / 2)
        ])

        self.connect(self.input, delay(gr.sizeof_gr_complex, fft_length / 2),
                     conj, (mixer, 0))
        self.connect(self.input, (mixer, 1))
        self.connect(mixer, nominator)
        # moving_avg = P(d)

        # R(d)
        denominator = schmidl_denominator(fft_length)

        # |P(d)| ** 2 / (R(d)) ** 2
        p_mag_sqrd = gr.complex_to_mag_squared()
        r_sqrd = gr.multiply_ff()
        self.timing_metric = gr.divide_ff()

        self.connect(nominator, p_mag_sqrd, (self.timing_metric, 0))
        self.connect(self.input, denominator, (r_sqrd, 0))
        self.connect(denominator, (r_sqrd, 1))
        self.connect(r_sqrd, (self.timing_metric, 1))
        self.connect(self.timing_metric, self)
    def __init__(self):
        gr.top_block.__init__(self)

        parser = OptionParser(option_class=eng_option)
        parser.add_option(
            "-I",
            "--audio-input",
            type="string",
            default="",
            help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_option(
            "-O",
            "--audio-output",
            type="string",
            default="",
            help="pcm output device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_option("-r",
                          "--sample-rate",
                          type="eng_float",
                          default=8000,
                          help="set sample rate to RATE (8000)")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            raise SystemExit, 1

        sample_rate = int(options.sample_rate)
        src = audio.source(sample_rate, options.audio_input)
        dst = audio.sink(sample_rate, options.audio_output)

        vec1 = [1, -1]
        vsource = gr.vector_source_f(vec1, True)
        multiply = gr.multiply_ff()

        self.connect(src, (multiply, 0))
        self.connect(vsource, (multiply, 1))
        self.connect(multiply, dst)
Example #20
0
    def __init__(self, fft_length):
        gr.hier_block2.__init__(self, "timing_metric",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                gr.io_signature(1, 1, gr.sizeof_float))

        self.input = gr.kludge_copy(gr.sizeof_gr_complex)
        self.connect(self, self.input)

        # P(d)
        nominator = schmidl_nominator(fft_length)

        # R(d)
        denominator = schmidl_denominator(fft_length)

        # |P(d)| ** 2 / (R(d)) ** 2
        p_mag_sqrd = gr.complex_to_mag_squared()
        r_sqrd = gr.multiply_ff()
        self.timing_metric = gr.divide_ff()

        self.connect(self.input, nominator, p_mag_sqrd,
                     (self.timing_metric, 0))
        self.connect(self.input, denominator, (r_sqrd, 0))
        self.connect(denominator, (r_sqrd, 1))
        self.connect(r_sqrd, (self.timing_metric, 1))
        self.connect(self.timing_metric, self)

        # calculate epsilon from P(d), epsilon is normalized fractional frequency offset
        #angle = gr.complex_to_arg()
        #self.epsilon = gr.multiply_const_ff(1.0/math.pi)
        #self.connect(nominator, angle, self.epsilon)

        try:
            gr.hier_block.update_var_names(self, "schmidl", vars())
            gr.hier_block.update_var_names(self, "schmidl", vars(self))
        except:
            pass
    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)
Example #22
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-T",
                          "--tx-subdev-spec",
                          type="subdev",
                          default=None,
                          help="select USRP Tx side A or B")
        parser.add_option("-f",
                          "--freq",
                          type="eng_float",
                          default=107.2e6,
                          help="set Tx frequency to FREQ [required]",
                          metavar="FREQ")
        parser.add_option("--wavfile",
                          type="string",
                          default="",
                          help="read input from FILE")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        self.usrp_interp = 200
        self.u = usrp.sink_c(0, self.usrp_interp)
        print "USRP Serial: ", self.u.serial_number()
        self.dac_rate = self.u.dac_rate()  # 128 MS/s
        self.usrp_rate = self.dac_rate / self.usrp_interp  # 640 kS/s
        self.sw_interp = 5
        self.audio_rate = self.usrp_rate / self.sw_interp  # 128 kS/s

        # determine the daughterboard subdevice we're using
        if options.tx_subdev_spec is None:
            options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
        self.u.set_mux(
            usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec))
        self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec)
        print "Using d'board: ", self.subdev.side_and_name()

        # set max Tx gain, tune frequency and enable transmitter
        self.subdev.set_gain(self.subdev.gain_range()[1])
        if self.u.tune(self.subdev.which(), self.subdev, options.freq):
            print "Tuned to", options.freq / 1e6, "MHz"
        else:
            sys.exit(1)
        self.subdev.set_enable(True)

        # open wav file containing floats in the [-1, 1] range, repeat
        if options.wavfile is None:
            print "Please provide a wavfile to transmit! Exiting\n"
            sys.exit(1)
        self.src = gr.wavfile_source(options.wavfile, True)
        nchans = self.src.channels()
        sample_rate = self.src.sample_rate()
        bits_per_sample = self.src.bits_per_sample()
        print nchans, "channels,", sample_rate, "kS/s,", bits_per_sample, "bits/sample"

        # resample to 128kS/s
        if sample_rate == 44100:
            self.resample_left = blks2.rational_resampler_fff(32, 11)
            self.resample_right = blks2.rational_resampler_fff(32, 11)
        elif sample_rate == 48000:
            self.resample_left == blks2.rational_resampler_fff(8, 3)
            self.resample_right == blks2.rational_resampler_fff(8, 3)
        elif sample_rate == 8000:
            self.resample_left == blks2.rational_resampler_fff(16, 1)
            self.resample_right == blks2.rational_resampler_fff(16, 1)
        else:
            print sample_rate, "is an unsupported sample rate"
            sys.exit(1)
        self.connect((self.src, 0), self.resample_left)
        self.connect((self.src, 1), self.resample_right)

        # create L+R (mono) and L-R (stereo)
        self.audio_lpr = gr.add_ff()
        self.audio_lmr = gr.sub_ff()
        self.connect(self.resample_left, (self.audio_lpr, 0))
        self.connect(self.resample_left, (self.audio_lmr, 0))
        self.connect(self.resample_right, (self.audio_lpr, 1))
        self.connect(self.resample_right, (self.audio_lmr, 1))

        # low-pass filter for L+R
        audio_lpr_taps = gr.firdes.low_pass(
            0.3,  # gain
            self.audio_rate,  # sampling rate
            15e3,  # passband cutoff
            2e3,  # transition width
            gr.firdes.WIN_HANN)
        self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps)
        self.connect(self.audio_lpr, self.audio_lpr_filter)

        # create pilot tone at 19 kHz
        self.pilot = gr.sig_source_f(
            self.audio_rate,  # sampling freq
            gr.GR_SIN_WAVE,  # waveform
            19e3,  # frequency
            3e-2)  # amplitude

        # create the L-R signal carrier at 38 kHz, high-pass to remove 0Hz tone
        self.stereo_carrier = gr.multiply_ff()
        self.connect(self.pilot, (self.stereo_carrier, 0))
        self.connect(self.pilot, (self.stereo_carrier, 1))
        stereo_carrier_taps = gr.firdes.high_pass(
            1,  # gain
            self.audio_rate,  # sampling rate
            1e4,  # cutoff freq
            2e3,  # transition width
            gr.firdes.WIN_HANN)
        self.stereo_carrier_filter = gr.fir_filter_fff(1, stereo_carrier_taps)
        self.connect(self.stereo_carrier, self.stereo_carrier_filter)

        # upconvert L-R to 23-53 kHz and band-pass
        self.mix_stereo = gr.multiply_ff()
        audio_lmr_taps = gr.firdes.band_pass(
            3e3,  # gain
            self.audio_rate,  # sampling rate
            23e3,  # low cutoff
            53e3,  # high cuttof
            2e3,  # transition width
            gr.firdes.WIN_HANN)
        self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps)
        self.connect(self.audio_lmr, (self.mix_stereo, 0))
        self.connect(self.stereo_carrier_filter, (self.mix_stereo, 1))
        self.connect(self.mix_stereo, self.audio_lmr_filter)

        # mix L+R, pilot and L-R
        self.mixer = gr.add_ff()
        self.connect(self.audio_lpr_filter, (self.mixer, 0))
        self.connect(self.pilot, (self.mixer, 1))
        self.connect(self.audio_lmr_filter, (self.mixer, 2))

        # interpolation & pre-emphasis
        interp_taps = gr.firdes.low_pass(
            self.sw_interp,  # gain
            self.audio_rate,  # Fs
            60e3,  # cutoff freq
            5e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.interpolator = gr.interp_fir_filter_fff(self.sw_interp,
                                                     interp_taps)
        self.pre_emph = blks2.fm_preemph(self.usrp_rate, tau=50e-6)
        self.connect(self.mixer, self.interpolator, self.pre_emph)

        # fm modulation, gain & TX
        max_dev = 100e3
        k = 2 * math.pi * max_dev / self.usrp_rate  # modulator sensitivity
        self.modulator = gr.frequency_modulator_fc(k)
        self.gain = gr.multiply_const_cc(1e3)
        self.connect(self.pre_emph, self.modulator, self.gain, self.u)

        # plot an FFT to verify we are sending what we want
        pre_mod = fftsink2.fft_sink_f(panel,
                                      title="Before Interpolation",
                                      fft_size=512,
                                      sample_rate=self.audio_rate,
                                      y_per_div=20,
                                      ref_level=20)
        self.connect(self.mixer, pre_mod)
        vbox.Add(pre_mod.win, 1, wx.EXPAND)
Example #23
0
	def __init__(self, dab_params, rx_params, verbose=False, debug=False):
		"""
		Hierarchical block for OFDM demodulation

		@param dab_params DAB parameter object (dab.parameters.dab_parameters)
		@param rx_params RX parameter object (dab.parameters.receiver_parameters)
		@param debug enables debug output to files
		@param verbose whether to produce verbose messages
		"""

		self.dp = dp = dab_params
		self.rp = rp = rx_params
		self.verbose = verbose

		if self.rp.softbits:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_float*self.dp.num_carriers*2, gr.sizeof_char)) # output signature
		else:
			gr.hier_block2.__init__(self,"ofdm_demod",
						gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature
						gr.io_signature2(2, 2, gr.sizeof_char*self.dp.num_carriers/4, gr.sizeof_char)) # output signature

		

		# workaround for a problem that prevents connecting more than one block directly (see trac ticket #161)
		self.input = gr.kludge_copy(gr.sizeof_gr_complex)
		self.connect(self, self.input)
		
		# input filtering
		if self.rp.input_fft_filter: 
			if verbose: print "--> RX filter enabled"
			lowpass_taps = gr.firdes_low_pass(1.0,                     # gain
							  dp.sample_rate,          # sampling rate
							  rp.filt_bw,              # cutoff frequency
							  rp.filt_tb,              # width of transition band
							  gr.firdes.WIN_HAMMING)   # Hamming window
			self.fft_filter = gr.fft_filter_ccc(1, lowpass_taps)
		

		# correct sample rate offset, if enabled
		if self.rp.autocorrect_sample_rate:
			if verbose: print "--> dynamic sample rate correction enabled"
			self.rate_detect_ns = detect_null.detect_null(dp.ns_length, False)
			self.rate_estimator = dab_swig.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length)
			self.rate_prober = gr.probe_signal_f()
			self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober)
			# self.resample = gr.fractional_interpolator_cc(0, 1)
			self.resample = dab_swig.fractional_interpolator_triggered_update_cc(0,1)
			self.connect(self.rate_detect_ns, (self.resample,1))
			self.updater = Timer(0.1,self.update_correction)
			# self.updater = threading.Thread(target=self.update_correction)
			self.run_interpolater_update_thread = True
			self.updater.setDaemon(True)
			self.updater.start()
		else:
			self.run_interpolater_update_thread = False
			if self.rp.sample_rate_correction_factor != 1:
				if verbose: print "--> static sample rate correction enabled"
				self.resample = gr.fractional_interpolator_cc(0, self.rp.sample_rate_correction_factor)

		# timing and fine frequency synchronisation
		self.sync = ofdm_sync_dab2.ofdm_sync_dab(self.dp, self.rp, debug)

		# ofdm symbol sampler
		self.sampler = dab_swig.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap)
		
		# fft for symbol vectors
		self.fft = gr.fft_vcc(dp.fft_length, True, [], True)

		# coarse frequency synchronisation
		self.cfs = dab_swig.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length)

		# diff phasor
		self.phase_diff = dab_swig.diff_phasor_vcc(dp.num_carriers)

		# remove pilot symbol
		self.remove_pilot = dab_swig.ofdm_remove_first_symbol_vcc(dp.num_carriers)

		# magnitude equalisation
		if self.rp.equalize_magnitude:
			if verbose: print "--> magnitude equalization enabled"
			self.equalizer = dab_swig.magnitude_equalizer_vcc(dp.num_carriers, rp.symbols_for_magnitude_equalization)

		# frequency deinterleaving
		self.deinterleave = dab_swig.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array)
		
		# symbol demapping
		self.demapper = dab_swig.qpsk_demapper_vcb(dp.num_carriers)

		#
		# connect everything
		#

		if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1:
			self.connect(self.input, self.resample)
			self.input2 = self.resample
		else:
			self.input2 = self.input
		if self.rp.input_fft_filter:
			self.connect(self.input2, self.fft_filter, self.sync)
		else:
			self.connect(self.input2, self.sync)

		# data stream
		self.connect((self.sync, 0), (self.sampler, 0), self.fft, (self.cfs, 0), self.phase_diff, (self.remove_pilot,0))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,0), (self.equalizer,0), self.deinterleave)
		else:
			self.connect((self.remove_pilot,0), self.deinterleave)
		if self.rp.softbits:
			if verbose: print "--> using soft bits"
			self.softbit_interleaver = dab_swig.complex_to_interleaved_float_vcf(self.dp.num_carriers)
			self.connect(self.deinterleave, self.softbit_interleaver, (self,0))
		else:
			self.connect(self.deinterleave, self.demapper, (self,0))

		# control stream
		self.connect((self.sync, 1), (self.sampler, 1), (self.cfs, 1), (self.remove_pilot,1))
		if self.rp.equalize_magnitude:
			self.connect((self.remove_pilot,1), (self.equalizer,1), (self,1))
		else:
			self.connect((self.remove_pilot,1), (self,1))
			
		# calculate an estimate of the SNR
		self.phase_var_decim   = gr.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample)
		self.phase_var_arg     = gr.complex_to_arg(dp.num_carriers)
		self.phase_var_v2s     = gr.vector_to_stream(gr.sizeof_float, dp.num_carriers)
		self.phase_var_mod     = dab_swig.modulo_ff(pi/2)
		self.phase_var_avg_mod = gr.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.phase_var_sub_avg = gr.sub_ff()
		self.phase_var_sqr     = gr.multiply_ff()
		self.phase_var_avg     = gr.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.probe_phase_var   = gr.probe_signal_f()
		self.connect((self.remove_pilot,0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg,0), (self.phase_var_sqr,0))
		self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg,1))
		self.connect(self.phase_var_sub_avg, (self.phase_var_sqr,1))
		self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var)

		# measure processing rate
		self.measure_rate = dab_swig.measure_processing_rate(gr.sizeof_gr_complex, 2000000) 
		self.connect(self.input, self.measure_rate)

		# debugging
		if debug:
			self.connect(self.fft, gr.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat"))
			self.connect((self.cfs,0), gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat"))
			self.connect(self.phase_diff, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat"))
			self.connect((self.remove_pilot,0), gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat"))
			self.connect((self.remove_pilot,1), gr.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat"))
			self.connect(self.deinterleave, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat"))
			if self.rp.equalize_magnitude:
				self.connect(self.equalizer, gr.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat"))
			if self.rp.softbits:
				self.connect(self.softbit_interleaver, gr.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
 def test_mult_ff(self):
     src1_data = (1, 2, 3, 4, 5)
     src2_data = (8, -3, 4, 8, 2)
     expected_result = (8, -6, 12, 32, 10)
     op = gr.multiply_ff()
     self.help_ff((src1_data, src2_data), expected_result, op)
Example #25
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-V",
                          "--volume",
                          type="eng_float",
                          default=None,
                          help="set volume (default is midpoint)")
        parser.add_option("-O",
                          "--audio-output",
                          type="string",
                          default="plughw:0,0",
                          help="pcm device name (default is plughw:0,0)")

        # print help when called with wrong arguments
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        self.file_source = gr.file_source(gr.sizeof_gr_complex * 1,
                                          offline_samples, True)

        chan_filter_coeffs = gr.firdes.low_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            80e3,  # passband cutoff
            35e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.chan_filter = gr.fir_filter_ccf(1, chan_filter_coeffs)
        print "# channel filter:", len(chan_filter_coeffs), "taps"

        # PLL-based WFM demod
        fm_alpha = 0.25 * 250e3 * math.pi / usrp_rate  # 0.767
        fm_beta = fm_alpha * fm_alpha / 4.0  # 0.147
        fm_max_freq = 2.0 * math.pi * 90e3 / usrp_rate  # 2.209
        self.fm_demod = gr.pll_freqdet_cf(
            fm_alpha,  # phase gain
            fm_beta,  # freq gain
            fm_max_freq,  # in radians/sample
            -fm_max_freq)
        self.connect(self.file_source, self.chan_filter, self.fm_demod)

        # L+R, pilot, L-R, RDS filters
        lpr_filter_coeffs = gr.firdes.low_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            15e3,  # passband cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.lpr_filter = gr.fir_filter_fff(audio_decim, lpr_filter_coeffs)
        pilot_filter_coeffs = gr.firdes.band_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            19e3 - 500,  # low cutoff
            19e3 + 500,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
        dsbsc_filter_coeffs = gr.firdes.band_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            38e3 - 15e3 / 2,  # low cutoff
            38e3 + 15e3 / 2,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.dsbsc_filter = gr.fir_filter_fff(1, dsbsc_filter_coeffs)
        rds_filter_coeffs = gr.firdes.band_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            57e3 - 3e3,  # low cutoff
            57e3 + 3e3,  # high cutoff
            3e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
        print "# lpr filter:", len(lpr_filter_coeffs), "taps"
        print "# pilot filter:", len(pilot_filter_coeffs), "taps"
        print "# dsbsc filter:", len(dsbsc_filter_coeffs), "taps"
        print "# rds filter:", len(rds_filter_coeffs), "taps"
        self.connect(self.fm_demod, self.lpr_filter)
        self.connect(self.fm_demod, self.pilot_filter)
        self.connect(self.fm_demod, self.dsbsc_filter)
        self.connect(self.fm_demod, self.rds_filter)

        # down-convert L-R, RDS
        self.stereo_baseband = gr.multiply_ff()
        self.connect(self.pilot_filter, (self.stereo_baseband, 0))
        self.connect(self.pilot_filter, (self.stereo_baseband, 1))
        self.connect(self.dsbsc_filter, (self.stereo_baseband, 2))
        self.rds_baseband = gr.multiply_ff()
        self.connect(self.pilot_filter, (self.rds_baseband, 0))
        self.connect(self.pilot_filter, (self.rds_baseband, 1))
        self.connect(self.pilot_filter, (self.rds_baseband, 2))
        self.connect(self.rds_filter, (self.rds_baseband, 3))

        # low-pass and downsample L-R
        lmr_filter_coeffs = gr.firdes.low_pass(
            1.0,  # gain
            usrp_rate,  # sampling rate
            15e3,  # passband cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.lmr_filter = gr.fir_filter_fff(audio_decim, lmr_filter_coeffs)
        self.connect(self.stereo_baseband, self.lmr_filter)

        # create L, R from L-R, L+R
        self.left = gr.add_ff()
        self.right = gr.sub_ff()
        self.connect(self.lpr_filter, (self.left, 0))
        self.connect(self.lmr_filter, (self.left, 1))
        self.connect(self.lpr_filter, (self.right, 0))
        self.connect(self.lmr_filter, (self.right, 1))

        # send audio to null sink
        self.null0 = gr.null_sink(gr.sizeof_float)
        self.null1 = gr.null_sink(gr.sizeof_float)
        self.connect(self.left, self.null0)
        self.connect(self.right, self.null1)

        # low-pass the baseband RDS signal at 1.5kHz
        rds_bb_filter_coeffs = gr.firdes.low_pass(
            1,  # gain
            usrp_rate,  # sampling rate
            1.5e3,  # passband cutoff
            2e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_bb_filter = gr.fir_filter_fff(audio_decim,
                                               rds_bb_filter_coeffs)
        print "# rds bb filter:", len(rds_bb_filter_coeffs), "taps"
        self.connect(self.rds_baseband, self.rds_bb_filter)

        # 1187.5bps = 19kHz/16
        self.clock_divider = rds.freq_divider(16)
        rds_clock_taps = gr.firdes.low_pass(
            1,  # gain
            usrp_rate,  # sampling rate
            1.2e3,  # passband cutoff
            1.5e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_clock = gr.fir_filter_fff(audio_decim, rds_clock_taps)
        print "# rds clock filter:", len(rds_clock_taps), "taps"
        self.connect(self.pilot_filter, self.clock_divider, self.rds_clock)

        # bpsk_demod, diff_decoder, rds_decoder
        self.bpsk_demod = rds.bpsk_demod(audio_rate)
        self.differential_decoder = gr.diff_decoder_bb(2)
        self.msgq = gr.msg_queue()
        self.rds_decoder = rds.data_decoder(self.msgq)
        self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
        self.connect(self.rds_clock, (self.bpsk_demod, 1))
        self.connect(self.bpsk_demod, self.differential_decoder)
        self.connect(self.differential_decoder, self.rds_decoder)

        self.frame = frame
        self.panel = panel
        self._build_gui(vbox, usrp_rate, audio_rate)
Example #26
0
    def __init__(self, fft_length, cp_length, half_sync, kstime, ks1time, threshold, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char,  # timing indicator
            ),
        )

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        # offset by -1
        phi = gr.sample_and_hold_ff()
        self.corrmag = gr.complex_to_mag_squared()
        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle, (phi, 0))

        cross_correlate = 1
        if cross_correlate == 1:
            # cross-correlate with the known symbol
            kstime = [k.conjugate() for k in kstime]
            kstime.reverse()
            self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

            """
        self.f2b = gr.float_to_char()
        self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length)
        #self.connect(self, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)
	self.connect(self.f2b, (phi,1))
	self.connect(self.f2b, (self,2))
	self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	"""

            # new method starts here - only crosscorrelate and use peak_detect block #
            peak_detect = gr.peak_detector_fb(100, 100, 30, 0.001)
            self.corrmag1 = gr.complex_to_mag_squared()
            self.connect(self, self.crosscorr_filter, self.corrmag, peak_detect)

            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))

            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length)), (self, 0))

        else:
            # Get the power of the input signal to normalize the output of the correlation
            R_d = gr.moving_average_ff(window, 1.0)
            self.connect(self, gr.complex_to_mag_squared(), R_d)
            R_d_squared = gr.multiply_ff()  # this is retarded
            self.connect(R_d, (R_d_squared, 0))
            self.connect(R_d, (R_d_squared, 1))
            M_d = gr.divide_ff()
            self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
            self.connect(R_d_squared, (M_d, 1))

            # Now we need to detect peak of M_d
            matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)
            peak_detect = gr.peak_detector_fb(0.25, 0.25, 30, 0.001)
            self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)
            offset = cp_length / 2  # cp_length/2
            self.connect(peak_detect, (phi, 1))
            self.connect(peak_detect, (self, 2))
            self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
            self.connect(
                self, gr.delay(gr.sizeof_gr_complex, (fft_length + offset)), (self, 0)
            )  # delay the input to follow the freq offset
            self.connect(peak_detect, gr.delay(gr.sizeof_char, (fft_length + offset)), (self, 2))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks_b.dat"))
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))

        self.connect(phi, (self, 1))

        if logging:
            self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
Example #27
0
    def __init__(self, options, noutputs=2):
        """
    @param options: parsed raw.ofdm_params
    """
        self.params = ofdm_params(options)
        params = self.params

        if noutputs == 2:
            output_signature = gr.io_signature2(
                2, 2, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char)
        elif noutputs == 3:
            output_signature = gr.io_signature3(
                3, 3, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char,
                gr.sizeof_float)
        elif noutputs == 4:
            output_signature = gr.io_signature4(
                4, 4, gr.sizeof_gr_complex * params.data_tones, gr.sizeof_char,
                gr.sizeof_float, gr.sizeof_float)
        else:
            # error
            raise Exception("unsupported number of outputs")

        gr.hier_block2.__init__(self, "ofdm_demod",
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                output_signature)

        self.ofdm_recv = ofdm_receiver(params, options.log)

        # FIXME: magic parameters
        phgain = 0.4
        frgain = phgain * phgain / 4.0
        eqgain = 0.05
        self.ofdm_demod = raw.ofdm_demapper(params.carriers, phgain, frgain,
                                            eqgain)

        # the studios can't handle the whole ofdm in one thread
        #ofdm_recv = raw.wrap_sts(self.ofdm_recv)
        ofdm_recv = self.ofdm_recv

        self.connect(self, ofdm_recv)
        self.connect((ofdm_recv, 0), (self.ofdm_demod, 0))
        self.connect((ofdm_recv, 1), (self.ofdm_demod, 1))

        self.connect(self.ofdm_demod, (self, 0))
        self.connect((ofdm_recv, 1), (self, 1))

        if noutputs > 2:
            # average noise power per (pilot) subcarrier
            self.connect((self.ofdm_demod, 1), (self, 2))

        if noutputs > 3:
            # average signal power per subcarrier
            self.connect(
                (ofdm_recv, 0),
                gr.vector_to_stream(gr.sizeof_float, params.occupied_tones),
                gr.integrate_ff(params.occupied_tones),
                gr.multiply_ff(1.0 / params.occupied_tones), (self, 3))

        if options.log:
            self.connect(
                (self.ofdm_demod, 2),
                gr.file_sink(gr.sizeof_gr_complex * params.occupied_tones,
                             'rx-eq.dat'))
            self.connect((self.ofdm_demod, 1),
                         gr.file_sink(gr.sizeof_float, 'rx-noise.dat'))
            self.connect((self.ofdm_demod, 0),
                         gr.file_sink(gr.sizeof_gr_complex * params.data_tones,
                                      'rx-demap.dat'))
Example #28
0
	def __init__(self):
		gr.top_block.__init__ (self)

		parser=OptionParser(option_class=eng_option)
		parser.add_option("-H", "--hostname", type="string", default="localhost",
						  help="set hostname of generic sdr")
		parser.add_option("-P", "--portnum", type="int", default=None,
						  help="set portnum of generic sdr")
		parser.add_option("-r", "--sdr_rate", type="eng_float", default=250e3,
						  help="set sample rate of generic sdr")
		parser.add_option("-V", "--volume", type="eng_float", default=None,
						  help="set volume (default is midpoint)")
		parser.add_option("-O", "--audio-output", type="string", default="plughw:0,0",
						  help="pcm device name (default is plughw:0,0)")

		# print help when called with wrong arguments
		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.print_help()
			sys.exit(1)

		self.vol = options.volume
		if self.vol is None:
			self.vol = 0.1

		# connect to generic SDR
		sdr_rate = options.sdr_rate
		audio_decim = 8
		audio_rate = int(sdr_rate/audio_decim)
		print "audio_rate = ", audio_rate
		self.interleaved_short_to_complex = gr.interleaved_short_to_complex()
		self.char_to_short = gr.char_to_short(1)
		self.sdr_source = grc_blks2.tcp_source(
			itemsize=gr.sizeof_char*1,
			addr=options.hostname,
			port=options.portnum,
			server=False
		)
#		self.sdr_source = gr.file_source(1, 'sdrs_baseband.dat')
#		self.throttle = gr.throttle(1, 500e3)
#		self.connect(self.sdr_source, self.file_sink)
		self.logger = gr.file_sink(1, 'log.out')
		self.connect(self.sdr_source, self.logger)


		# channel filter
		chan_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			80e3,			# passband cutoff
			35e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.chan_filter = gr.fir_filter_ccf(1, chan_filter_coeffs)
#		print "# channel filter:", len(chan_filter_coeffs), "taps"

		# PLL-based WFM demod
		fm_alpha = 0.25 * 250e3 * math.pi / sdr_rate		# 0.767
		fm_beta = fm_alpha * fm_alpha / 4.0			# 0.147
		fm_max_freq = 2.0 * math.pi * 90e3 / sdr_rate		# 2.209
		self.fm_demod = gr.pll_freqdet_cf(
			1.0,				# Loop BW
			fm_max_freq,		# in radians/sample
			-fm_max_freq)
		self.fm_demod.set_alpha(fm_alpha)
		self.fm_demod.set_beta(fm_beta)
		self.connect(self.sdr_source, self.char_to_short)
		self.connect(self.char_to_short, self.interleaved_short_to_complex)
		self.connect(self.interleaved_short_to_complex, self.chan_filter, self.fm_demod)

		# L+R, pilot, L-R, RDS filters
		lpr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lpr_filter = gr.fir_filter_fff(audio_decim, lpr_filter_coeffs)
		pilot_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			19e3-500,		# low cutoff
			19e3+500,		# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
		dsbsc_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			38e3-15e3/2,	# low cutoff
			38e3+15e3/2,	# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.dsbsc_filter = gr.fir_filter_fff(1, dsbsc_filter_coeffs)
		rds_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			57e3-3e3,		# low cutoff
			57e3+3e3,		# high cutoff
			3e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
#		print "# lpr filter:", len(lpr_filter_coeffs), "taps"
#		print "# pilot filter:", len(pilot_filter_coeffs), "taps"
#		print "# dsbsc filter:", len(dsbsc_filter_coeffs), "taps"
#		print "# rds filter:", len(rds_filter_coeffs), "taps"
		self.connect(self.fm_demod, self.lpr_filter)
		self.connect(self.fm_demod, self.pilot_filter)
		self.connect(self.fm_demod, self.dsbsc_filter)
		self.connect(self.fm_demod, self.rds_filter)

		# down-convert L-R, RDS
		self.stereo_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.stereo_baseband, 0))
		self.connect(self.pilot_filter, (self.stereo_baseband, 1))
		self.connect(self.dsbsc_filter, (self.stereo_baseband, 2))
		self.rds_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.rds_baseband, 0))
		self.connect(self.pilot_filter, (self.rds_baseband, 1))
		self.connect(self.pilot_filter, (self.rds_baseband, 2))
		self.connect(self.rds_filter, (self.rds_baseband, 3))

		# low-pass and downsample L-R
		lmr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lmr_filter = gr.fir_filter_fff(audio_decim, lmr_filter_coeffs)
		self.connect(self.stereo_baseband, self.lmr_filter)

		# create L, R from L-R, L+R
		self.left = gr.add_ff()
		self.right = gr.sub_ff()
		self.connect(self.lpr_filter, (self.left, 0))
		self.connect(self.lmr_filter, (self.left, 1))
		self.connect(self.lpr_filter, (self.right, 0))
		self.connect(self.lmr_filter, (self.right, 1))

		# volume control, complex2flot, audio sink
		self.volume_control_l = gr.multiply_const_ff(self.vol)
		self.volume_control_r = gr.multiply_const_ff(self.vol)
		output_audio_rate = 48000
		self.resamp_L = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.resamp_R = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.connect(self.left,  self.volume_control_l, self.resamp_L)
		self.connect(self.right, self.volume_control_r, self.resamp_R)
#		self.audio_sink = audio.sink(int(output_audio_rate),
#							options.audio_output, False)
# 		self.connect(self.resamp_L, (self.audio_sink, 0))
#		self.connect(self.resamp_R, (self.audio_sink, 1))
		self.file_sink1 = gr.file_sink(gr.sizeof_float, 'audioL.dat')
		self.file_sink2 = gr.file_sink(gr.sizeof_float, 'audioR.dat')
		self.file_sink3 = gr.file_sink(gr.sizeof_float, 'fmDemod.dat')
       		self.connect(self.resamp_L, self.file_sink1)
		self.connect(self.resamp_R, self.file_sink2)
		self.connect(self.fm_demod, self.file_sink3)

		# low-pass the baseband RDS signal at 1.5kHz
		rds_bb_filter_coeffs = gr.firdes.low_pass(
			1,				# gain
			sdr_rate,		# sampling rate
			1.5e3,			# passband cutoff
			2e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_bb_filter = gr.fir_filter_fff(audio_decim, rds_bb_filter_coeffs)
#		print "# rds bb filter:", len(rds_bb_filter_coeffs), "taps"
		self.connect(self.rds_baseband, self.rds_bb_filter)

		# 1187.5bps = 19kHz/16
		self.clock_divider = rds.freq_divider(16)
		rds_clock_taps = gr.firdes.low_pass(
			1,				# gain
			sdr_rate,		# sampling rate
			1.2e3,			# passband cutoff
			1.5e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_clock = gr.fir_filter_fff(audio_decim, rds_clock_taps)
#		print "# rds clock filter:", len(rds_clock_taps), "taps"
		self.connect(self.pilot_filter, self.clock_divider, self.rds_clock)

		# bpsk_demod, diff_decoder, rds_decoder
		self.bpsk_demod = rds.bpsk_demod(audio_rate)
		self.differential_decoder = gr.diff_decoder_bb(2)
		self.msgq = gr.msg_queue()
		self.rds_decoder = rds.data_decoder(self.msgq)
		self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
		self.connect(self.rds_clock, (self.bpsk_demod, 1))
		self.connect(self.bpsk_demod, self.differential_decoder)
		self.connect(self.differential_decoder, self.rds_decoder)
Example #29
0
	def __init__(self):
		gr.top_block.__init__ (self)

		parser=OptionParser(option_class=eng_option)
		parser.add_option("-H", "--hostname", type="string", default="localhost",
						  help="set hostname of generic sdr")
		parser.add_option("-P", "--portnum", type="int", default=None,
						  help="set portnum of generic sdr")
		parser.add_option("-W", "--wsportnum", type="int", default=None,
						  help="set portnum of audio websocket server")
		parser.add_option("-r", "--sdr_rate", type="eng_float", default=250e3,
						  help="set sample rate of generic sdr")
		parser.add_option("-V", "--volume", type="eng_float", default=None,
						  help="set volume (default is midpoint)")
		parser.add_option("-O", "--audio-output", type="string", default="plughw:0,0",
						  help="pcm device name (default is plughw:0,0)")

		# print help when called with wrong arguments
		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.print_help()
			sys.exit(1)

		self.vol = options.volume
		if self.vol is None:
			self.vol = 0.1

		# connect to generic SDR
		sdr_rate = options.sdr_rate
		audio_decim = 8
		audio_rate = int(sdr_rate/audio_decim)
		print "audio_rate = ", audio_rate
		self.interleaved_short_to_complex = gr.interleaved_short_to_complex()
		self.char_to_short = gr.char_to_short(1)
		self.sdr_source = grc_blks2.tcp_source(
			itemsize=gr.sizeof_char*1,
			addr=options.hostname,
			port=options.portnum,
			server=False
		)
#		self.sdr_source = gr.file_source(1, 'sdrs_baseband.dat')
#		self.throttle = gr.throttle(1, 500e3)
#		self.connect(self.sdr_source, self.file_sink)
		self.logger = gr.file_sink(1, 'log.out')
		self.connect(self.sdr_source, self.logger)


		# channel filter
		chan_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			80e3,			# passband cutoff
			35e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.chan_filter = gr.fir_filter_ccf(1, chan_filter_coeffs)
#		print "# channel filter:", len(chan_filter_coeffs), "taps"

		# PLL-based WFM demod
		fm_alpha = 0.25 * 250e3 * math.pi / sdr_rate		# 0.767
		fm_beta = fm_alpha * fm_alpha / 4.0			# 0.147
		fm_max_freq = 2.0 * math.pi * 90e3 / sdr_rate		# 2.209
		self.fm_demod = gr.pll_freqdet_cf(
			1.0,				# Loop BW
			fm_max_freq,		# in radians/sample
			-fm_max_freq)
		self.fm_demod.set_alpha(fm_alpha)
		self.fm_demod.set_beta(fm_beta)
		self.connect(self.sdr_source, self.char_to_short)
		self.connect(self.char_to_short, self.interleaved_short_to_complex)
		self.connect(self.interleaved_short_to_complex, self.chan_filter, self.fm_demod)

		# L+R, pilot, L-R, RDS filters
		lpr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lpr_filter = gr.fir_filter_fff(audio_decim, lpr_filter_coeffs)
		pilot_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			19e3-500,		# low cutoff
			19e3+500,		# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
		dsbsc_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			38e3-15e3/2,	# low cutoff
			38e3+15e3/2,	# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.dsbsc_filter = gr.fir_filter_fff(1, dsbsc_filter_coeffs)
		rds_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			57e3-3e3,		# low cutoff
			57e3+3e3,		# high cutoff
			3e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
#		print "# lpr filter:", len(lpr_filter_coeffs), "taps"
#		print "# pilot filter:", len(pilot_filter_coeffs), "taps"
#		print "# dsbsc filter:", len(dsbsc_filter_coeffs), "taps"
#		print "# rds filter:", len(rds_filter_coeffs), "taps"
		self.connect(self.fm_demod, self.lpr_filter)
		self.connect(self.fm_demod, self.pilot_filter)
		self.connect(self.fm_demod, self.dsbsc_filter)
		self.connect(self.fm_demod, self.rds_filter)

		# down-convert L-R, RDS
		self.stereo_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.stereo_baseband, 0))
		self.connect(self.pilot_filter, (self.stereo_baseband, 1))
		self.connect(self.dsbsc_filter, (self.stereo_baseband, 2))
		self.rds_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.rds_baseband, 0))
		self.connect(self.pilot_filter, (self.rds_baseband, 1))
		self.connect(self.pilot_filter, (self.rds_baseband, 2))
		self.connect(self.rds_filter, (self.rds_baseband, 3))

		# low-pass and downsample L-R
		lmr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			sdr_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lmr_filter = gr.fir_filter_fff(audio_decim, lmr_filter_coeffs)
		self.connect(self.stereo_baseband, self.lmr_filter)

		# create L, R from L-R, L+R
		self.left = gr.add_ff()
		self.right = gr.sub_ff()
		self.connect(self.lpr_filter, (self.left, 0))
		self.connect(self.lmr_filter, (self.left, 1))
		self.connect(self.lpr_filter, (self.right, 0))
		self.connect(self.lmr_filter, (self.right, 1))

		# volume control, complex2flot, audio sink
		self.volume_control_l = gr.multiply_const_ff(self.vol)
		self.volume_control_r = gr.multiply_const_ff(self.vol)
		output_audio_rate = 48000
		self.resamp_L = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.resamp_R = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.connect(self.left,  self.volume_control_l, self.resamp_L)
		self.connect(self.right, self.volume_control_r, self.resamp_R)
#		self.audio_sink = audio.sink(int(output_audio_rate),
#							options.audio_output, False)
# 		self.connect(self.resamp_L, (self.audio_sink, 0))
#		self.connect(self.resamp_R, (self.audio_sink, 1))
#		self.file_sink1 = gr.file_sink(gr.sizeof_float, 'audioL.dat')
#		self.file_sink2 = gr.file_sink(gr.sizeof_float, 'audioR.dat')
#		self.file_sink3 = gr.file_sink(gr.sizeof_float, 'fmDemod.dat')
#       		self.connect(self.resamp_L, self.file_sink1)
#		self.connect(self.resamp_R, self.file_sink2)
#		self.connect(self.fm_demod, self.file_sink3)

		# Interleave both channels so that we can push over one websocket connection
		self.audio_interleaver = gr.float_to_complex(1)
		self.connect(self.resamp_L, (self.audio_interleaver, 0))
		self.connect(self.resamp_R, (self.audio_interleaver, 1))
		
		self.ws_audio_server = sdrportal.ws_sink_c(True, options.wsportnum, "FLOAT")
		self.connect(self.audio_interleaver, self.ws_audio_server)

		# low-pass the baseband RDS signal at 1.5kHz
		rds_bb_filter_coeffs = gr.firdes.low_pass(
			1,				# gain
			sdr_rate,		# sampling rate
			1.5e3,			# passband cutoff
			2e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_bb_filter = gr.fir_filter_fff(audio_decim, rds_bb_filter_coeffs)
#		print "# rds bb filter:", len(rds_bb_filter_coeffs), "taps"
		self.connect(self.rds_baseband, self.rds_bb_filter)

		# 1187.5bps = 19kHz/16
		self.clock_divider = rds.freq_divider(16)
		rds_clock_taps = gr.firdes.low_pass(
			1,				# gain
			sdr_rate,		# sampling rate
			1.2e3,			# passband cutoff
			1.5e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_clock = gr.fir_filter_fff(audio_decim, rds_clock_taps)
#		print "# rds clock filter:", len(rds_clock_taps), "taps"
		self.connect(self.pilot_filter, self.clock_divider, self.rds_clock)

		# bpsk_demod, diff_decoder, rds_decoder
		self.bpsk_demod = rds.bpsk_demod(audio_rate)
		self.differential_decoder = gr.diff_decoder_bb(2)
		self.msgq = gr.msg_queue()
		self.rds_decoder = rds.data_decoder(self.msgq)
		self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
		self.connect(self.rds_clock, (self.bpsk_demod, 1))
		self.connect(self.bpsk_demod, self.differential_decoder)
		self.connect(self.differential_decoder, self.rds_decoder)
Example #30
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        #self.sub1 = gr.add_const_ff(-1)
        self.sub1 = gr.add_const_ff(0)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #31
0
  def __init__(self, subc, vlen, ss):
    gr.hier_block2.__init__(self, "new_snr_estimator",
        gr.io_signature(1,1,gr.sizeof_gr_complex*vlen),
        gr.io_signature(1,1,gr.sizeof_float))

    print "Created Milan's SNR estimator"

    trigger = [0]*vlen
    trigger[0] = 1


    u = range (vlen/ss*(ss-1))
    zeros_ind= map(lambda z: z+1+z/(ss-1),u)

    skip1 = skip(gr.sizeof_gr_complex,vlen)
    for x in zeros_ind:
      skip1.skip(x)

    #print "skipped zeros",zeros_ind

    v = range (vlen/ss)
    ones_ind= map(lambda z: z*ss,v)

    skip2 = skip(gr.sizeof_gr_complex,vlen)
    for x in ones_ind:
      skip2.skip(x)

    #print "skipped ones",ones_ind

    v2s = gr.vector_to_stream(gr.sizeof_gr_complex,vlen)
    s2v1 = gr.stream_to_vector(gr.sizeof_gr_complex,vlen/ss)
    trigger_src_1 = gr.vector_source_b(trigger,True)

    s2v2 = gr.stream_to_vector(gr.sizeof_gr_complex,vlen/ss*(ss-1))
    trigger_src_2 = gr.vector_source_b(trigger,True)

    mag_sq_ones = gr.complex_to_mag_squared(vlen/ss)
    mag_sq_zeros = gr.complex_to_mag_squared(vlen/ss*(ss-1))

    filt_ones = gr.single_pole_iir_filter_ff(0.1,vlen/ss)
    filt_zeros = gr.single_pole_iir_filter_ff(0.1,vlen/ss*(ss-1))

    sum_ones = vector_sum_vff(vlen/ss)
    sum_zeros = vector_sum_vff(vlen/ss*(ss-1))

    D = gr.divide_ff()
    P = gr.multiply_ff()
    mult1 = gr.multiply_const_ff(ss-1.0)
    add1 = gr.add_const_ff(-1.0)
    mult2 = gr.multiply_const_ff(1./ss)
    scsnrdb = gr.nlog10_ff(10,1,0)
    filt_end = gr.single_pole_iir_filter_ff(0.1)

    self.connect(self,v2s,skip1,s2v1,mag_sq_ones,filt_ones,sum_ones)
    self.connect(trigger_src_1,(skip1,1))

    self.connect(v2s,skip2,s2v2,mag_sq_zeros,filt_zeros,sum_zeros)
    self.connect(trigger_src_2,(skip2,1))

    self.connect(sum_ones,D)
    self.connect(sum_zeros,(D,1))
    self.connect(D,mult1,add1,mult2)

    self.connect(mult2,scsnrdb,filt_end,self)
Example #32
0
    def __init__(self,
                 fft_length,
                 cp_length,
                 kstime,
                 threshold,
                 threshold_type,
                 threshold_gap,
                 logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """

        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature2(2, 2, gr.sizeof_float,
                             gr.sizeof_char))  # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length / 2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc()
        self.corr = gr.multiply_cc()

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length // 2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1, moving_sum_taps)
        else:
            moving_sum_taps = [
                complex(1.0, 0.0) for i in range(fft_length // 2)
            ]
            self.moving_sum_filter = gr.fft_filter_ccc(1, moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length // 2)]
        #movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1, movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1, movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()

        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(
            0.20, 0.20, 30, 0.001
        )  #apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)

        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr, 0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr, 1))

        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold, 0))  # apurv--
        #self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

        cross_correlate = 1
        if cross_correlate == 1:
            # cross-correlate with the known symbol
            kstime = [k.conjugate() for k in kstime]
            kstime.reverse()
            self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

            # get the magnitude #
            self.corrmag = gr.complex_to_mag_squared()

            self.f2b = gr.float_to_char()
            self.threshold_factor = threshold  #0.0012 #0.012   #0.0015
            if 0:
                self.slice = gr.threshold_ff(self.threshold_factor,
                                             self.threshold_factor, 0,
                                             fft_length)
            else:
                #thresholds = [self.threshold_factor, 9e-5]
                self.slice = gr.threshold_ff(threshold, threshold, 0,
                                             fft_length, threshold_type,
                                             threshold_gap)

            self.connect(self.input, self.crosscorr_filter, self.corrmag,
                         self.slice, self.f2b)

            # some debug dump #
            self.connect(self.corrmag,
                         gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
            #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))

        self.connect(self.f2b, (self.sample_and_hold, 1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self, 0))
        #self.connect(self.pk_detect, (self,1))									#removed
        #self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
        self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(
                self.matched_filter,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(
                self.normalize,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(
                self.angle,
                gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                gr.file_sink(gr.sizeof_float,
                             "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #33
0
	def __init__(self, frame, panel, vbox, argv):
		stdgui2.std_top_block.__init__ (self, frame, panel, vbox, argv)

		parser = OptionParser (option_class=eng_option)
		parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
						help="select USRP Tx side A or B")
		parser.add_option("-f", "--freq", type="eng_float", default=107.2e6,
						help="set Tx frequency to FREQ [required]", metavar="FREQ")
		parser.add_option("--wavfile", type="string", default="",
						help="read input from FILE")
		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.print_help()
			sys.exit(1)

		self.usrp_interp = 200
		self.u = usrp.sink_c (0, self.usrp_interp)
		print "USRP Serial: ", self.u.serial_number()
		self.dac_rate = self.u.dac_rate()					# 128 MS/s
		self.usrp_rate = self.dac_rate / self.usrp_interp	# 640 kS/s
		self.sw_interp = 5
		self.audio_rate = self.usrp_rate / self.sw_interp	# 128 kS/s

		# determine the daughterboard subdevice we're using
		if options.tx_subdev_spec is None:
			options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
		self.u.set_mux(usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec))
		self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec)
		print "Using d'board: ", self.subdev.side_and_name()

		# set max Tx gain, tune frequency and enable transmitter
		self.subdev.set_gain(self.subdev.gain_range()[1])
		if self.u.tune(self.subdev.which(), self.subdev, options.freq):
			print "Tuned to", options.freq/1e6, "MHz"
		else:
			sys.exit(1)
		self.subdev.set_enable(True)

		# open wav file containing floats in the [-1, 1] range, repeat
		if options.wavfile is None:
			print "Please provide a wavfile to transmit! Exiting\n"
			sys.exit(1)
		self.src = gr.wavfile_source (options.wavfile, True)
		nchans = self.src.channels()
		sample_rate = self.src.sample_rate()
		bits_per_sample = self.src.bits_per_sample()
		print nchans, "channels,", sample_rate, "kS/s,", bits_per_sample, "bits/sample"

		# resample to 128kS/s
		if sample_rate == 44100:
			self.resample_left = blks2.rational_resampler_fff(32,11)
			self.resample_right = blks2.rational_resampler_fff(32,11)
		elif sample_rate == 48000:
			self.resample_left == blks2.rational_resampler_fff(8,3)
			self.resample_right == blks2.rational_resampler_fff(8,3)
		elif sample_rate == 8000:
			self.resample_left == blks2.rational_resampler_fff(16,1)
			self.resample_right == blks2.rational_resampler_fff(16,1)
		else:
			print sample_rate, "is an unsupported sample rate"
			sys.exit(1)
		self.connect ((self.src, 0), self.resample_left)
		self.connect ((self.src, 1), self.resample_right)

		# create L+R (mono) and L-R (stereo)
		self.audio_lpr = gr.add_ff()
		self.audio_lmr = gr.sub_ff()
		self.connect (self.resample_left, (self.audio_lpr, 0))
		self.connect (self.resample_left, (self.audio_lmr, 0))
		self.connect (self.resample_right, (self.audio_lpr, 1))
		self.connect (self.resample_right, (self.audio_lmr, 1))

		# low-pass filter for L+R
		audio_lpr_taps = gr.firdes.low_pass (0.3,	# gain
											self.audio_rate,	# sampling rate
											15e3,				# passband cutoff
											2e3,				# transition width
											gr.firdes.WIN_HANN)
		self.audio_lpr_filter = gr.fir_filter_fff (1, audio_lpr_taps)
		self.connect (self.audio_lpr, self.audio_lpr_filter)

		# create pilot tone at 19 kHz
		self.pilot = gr.sig_source_f(self.audio_rate,	# sampling freq
									gr.GR_SIN_WAVE,		# waveform
									19e3,				# frequency
									3e-2)				# amplitude

		# create the L-R signal carrier at 38 kHz, high-pass to remove 0Hz tone
		self.stereo_carrier = gr.multiply_ff()
		self.connect (self.pilot, (self.stereo_carrier, 0))
		self.connect (self.pilot, (self.stereo_carrier, 1))
		stereo_carrier_taps = gr.firdes.high_pass (1,			# gain
											self.audio_rate,	# sampling rate
											1e4,				# cutoff freq
											2e3,				# transition width
											gr.firdes.WIN_HANN)
		self.stereo_carrier_filter = gr.fir_filter_fff(1, stereo_carrier_taps)
		self.connect (self.stereo_carrier, self.stereo_carrier_filter)

		# upconvert L-R to 23-53 kHz and band-pass
		self.mix_stereo = gr.multiply_ff()
		audio_lmr_taps = gr.firdes.band_pass (3e3,				# gain
											self.audio_rate,	# sampling rate
											23e3,				# low cutoff
											53e3,				# high cuttof
											2e3,				# transition width
											gr.firdes.WIN_HANN)
		self.audio_lmr_filter = gr.fir_filter_fff (1, audio_lmr_taps)
		self.connect (self.audio_lmr, (self.mix_stereo, 0))
		self.connect (self.stereo_carrier_filter, (self.mix_stereo, 1))
		self.connect (self.mix_stereo, self.audio_lmr_filter)

		# mix L+R, pilot and L-R
		self.mixer = gr.add_ff()
		self.connect (self.audio_lpr_filter, (self.mixer, 0))
		self.connect (self.pilot, (self.mixer, 1))
		self.connect (self.audio_lmr_filter, (self.mixer, 2))

		# interpolation & pre-emphasis
		interp_taps = gr.firdes.low_pass (self.sw_interp,	# gain
										self.audio_rate,	# Fs
										60e3,				# cutoff freq
										5e3,				# transition width
										gr.firdes.WIN_HAMMING)
		self.interpolator = gr.interp_fir_filter_fff (self.sw_interp, interp_taps)
		self.pre_emph = blks2.fm_preemph(self.usrp_rate, tau=50e-6)
		self.connect (self.mixer, self.interpolator, self.pre_emph)

		# fm modulation, gain & TX
		max_dev = 100e3
		k = 2 * math.pi * max_dev / self.usrp_rate		# modulator sensitivity
		self.modulator = gr.frequency_modulator_fc (k)
		self.gain = gr.multiply_const_cc (1e3)
		self.connect (self.pre_emph, self.modulator, self.gain, self.u)

		# plot an FFT to verify we are sending what we want
		pre_mod = fftsink2.fft_sink_f(panel, title="Before Interpolation",
			fft_size=512, sample_rate=self.audio_rate, y_per_div=20, ref_level=20)
		self.connect (self.mixer, pre_mod)
		vbox.Add (pre_mod.win, 1, wx.EXPAND)
    def __init__(self, fft_length, cp_length, snr, kstime, logging):
        ''' Maximum Likelihood OFDM synchronizer:
        J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation
        of Time and Frequency Offset in OFDM Systems," IEEE Trans.
        Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997.
        '''

	gr.hier_block2.__init__(self, "ofdm_sync_ml",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        SNR = 10.0**(snr/10.0)
        rho = SNR / (SNR + 1.0)
        symbol_length = fft_length + cp_length

        # ML Sync

        # Energy Detection from ML Sync

        self.connect(self, self.input)

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

        # magnitude squared blocks
        self.magsqrd1 = gr.complex_to_mag_squared()
        self.magsqrd2 = gr.complex_to_mag_squared()
        self.adder = gr.add_ff()

        moving_sum_taps = [rho/2 for i in range(cp_length)]
        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
        
        self.connect(self.input,self.magsqrd1)
        self.connect(self.delay,self.magsqrd2)
        self.connect(self.magsqrd1,(self.adder,0))
        self.connect(self.magsqrd2,(self.adder,1))
        self.connect(self.adder,self.moving_sum_filter)
        

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.mixer = gr.multiply_cc();

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
        
        # Correlator data handler
        self.c2mag = gr.complex_to_mag()
        self.angle = gr.complex_to_arg()
        self.connect(self.input,(self.mixer,1))
        self.connect(self.delay,self.conjg,(self.mixer,0))
        self.connect(self.mixer,self.movingsum2,self.c2mag)
        self.connect(self.movingsum2,self.angle)

        # ML Sync output arg, need to find maximum point of this
        self.diff = gr.sub_ff()
        self.connect(self.c2mag,(self.diff,0))
        self.connect(self.moving_sum_filter,(self.diff,1))

        #ML measurements input to sampler block and detect
        self.f2c = gr.float_to_complex()
        self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005)
        self.sample_and_hold = gr.sample_and_hold_ff()

        # use the sync loop values to set the sampler and the NCO
        #     self.diff = theta
        #     self.angle = epsilon
                          
        self.connect(self.diff, self.pk_detect)

        # The DPLL corrects for timing differences between CP correlations
        use_dpll = 0
        if use_dpll:
            self.dpll = gr.dpll_bb(float(symbol_length),0.01)
            self.connect(self.pk_detect, self.dpll)
            self.connect(self.dpll, (self.sample_and_hold,1))
        else:
            self.connect(self.pk_detect, (self.sample_and_hold,1))
            
        self.connect(self.angle, (self.sample_and_hold,0))

        ################################
        # correlate against known symbol
        # This gives us the same timing signal as the PN sync block only on the preamble
        # we don't use the signal generated from the CP correlation because we don't want
        # to readjust the timing in the middle of the packet or we ruin the equalizer settings.
        kstime = [k.conjugate() for k in kstime]
        kstime.reverse()
        self.kscorr = gr.fir_filter_ccc(1, kstime)
        self.corrmag = gr.complex_to_mag_squared()
        self.div = gr.divide_ff()

        # The output signature of the correlation has a few spikes because the rest of the
        # system uses the repeated preamble symbol. It needs to work that generically if 
        # anyone wants to use this against a WiMAX-like signal since it, too, repeats.
        # The output theta of the correlator above is multiplied with this correlation to
        # identify the proper peak and remove other products in this cross-correlation
        self.threshold_factor = 0.1
        self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0)
        self.f2b = gr.float_to_char()
        self.b2f = gr.char_to_float()
        self.mul = gr.multiply_ff()
        
        # Normalize the power of the corr output by the energy. This is not really needed
        # and could be removed for performance, but it makes for a cleaner signal.
        # if this is removed, the threshold value needs adjustment.
        self.connect(self.input, self.kscorr, self.corrmag, (self.div,0))
        self.connect(self.moving_sum_filter, (self.div,1))
        
        self.connect(self.div, (self.mul,0))
        self.connect(self.pk_detect, self.b2f, (self.mul,1))
        self.connect(self.mul, self.slice)
        
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.slice, self.f2b, (self,1))


        if logging:
            self.connect(self.moving_sum_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat"))
            self.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
            self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat"))
            self.connect(self.kscorr, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat"))
            self.connect(self.div, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat"))
            self.connect(self.mul, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat"))
            self.connect(self.slice, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
            if use_dpll:
                self.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))

            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
Example #35
0
	def __init__(self):
		gr.top_block.__init__ (self)

		parser=OptionParser(option_class=eng_option)
		parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
						  help="select USRP Rx side A or B (default=A)")
		parser.add_option("-f", "--freq", type="eng_float", default=91.2e6,
						  help="set frequency to FREQ", metavar="FREQ")
		parser.add_option("-g", "--gain", type="eng_float", default=None,
						  help="set gain in dB")
		parser.add_option("-s", "--squelch", type="eng_float", default=0,
						  help="set squelch level (default is 0)")
		parser.add_option("-V", "--volume", type="eng_float", default=None,
						  help="set volume (default is midpoint)")
		parser.add_option("-O", "--audio-output", type="string", default="plughw:0,0",
						  help="pcm device name (default is plughw:0,0)")
		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.print_help()
			sys.exit(1)

		# connect to USRP
		usrp_decim = 250
		self.u = usrp.source_c(0, usrp_decim)
		print "USRP Serial: ", self.u.serial_number()
		demod_rate = self.u.adc_rate() / usrp_decim		# 256 kS/s
		audio_decim = 8
		audio_rate = demod_rate / audio_decim			# 32 kS/s
		if options.rx_subdev_spec is None:
			options.rx_subdev_spec = usrp.pick_subdev(self.u, dblist)

		self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
		self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
		print "Using d'board", self.subdev.side_and_name()


		# gain, volume, frequency
		self.gain = options.gain
		if options.gain is None:
			self.gain = self.subdev.gain_range()[1]

		self.vol = options.volume
		if self.vol is None:
			g = self.volume_range()
			self.vol = float(g[0]+g[1])/2

		self.freq = options.freq
		if abs(self.freq) < 1e6:
			self.freq *= 1e6
		
		print "Volume:%r, Gain:%r, Freq:%3.1f MHz" % (self.vol, self.gain, self.freq/1e6)

		# channel filter, wfm_rcv_pll
		chan_filt_coeffs = optfir.low_pass(
			1,				# gain
			demod_rate,		# rate
			80e3,			# passband cutoff
			115e3,			# stopband cutoff
			0.1,			# passband ripple
			60)				# stopband attenuation
		self.chan_filt = gr.fir_filter_ccf (1, chan_filt_coeffs)
		self.guts = blks2.wfm_rcv_pll (demod_rate, audio_decim)
		self.connect(self.u, self.chan_filt, self.guts)

		# volume control, audio sink
		self.volume_control_l = gr.multiply_const_ff(self.vol)
		self.volume_control_r = gr.multiply_const_ff(self.vol)
		self.audio_sink = audio.sink(int(audio_rate), options.audio_output, False)
		self.connect ((self.guts, 0), self.volume_control_l, (self.audio_sink, 0))
		self.connect ((self.guts, 1), self.volume_control_r, (self.audio_sink, 1))

		# pilot channel filter (band-pass, 18.5-19.5kHz)
		pilot_filter_coeffs = gr.firdes.band_pass(
			1,				# gain
			demod_rate,		# sampling rate
			18.5e3,			# low cutoff
			19.5e3,			# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
		self.connect(self.guts.fm_demod, self.pilot_filter)

		# RDS channel filter (band-pass, 54-60kHz)
		rds_filter_coeffs = gr.firdes.band_pass(
			1,				# gain
			demod_rate,		# sampling rate
			54e3,			# low cutoff
			60e3,			# high cutoff
			3e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
		self.connect(self.guts.fm_demod, self.rds_filter)

		# create 57kHz subcarrier from 19kHz pilot, downconvert RDS channel
		self.mixer = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.mixer, 0))
		self.connect(self.pilot_filter, (self.mixer, 1))
		self.connect(self.pilot_filter, (self.mixer, 2))
		self.connect(self.rds_filter, (self.mixer, 3))

		# low-pass the baseband RDS signal at 1.5kHz
		rds_bb_filter_coeffs = gr.firdes.low_pass(
			1,				# gain
			demod_rate,		# sampling rate
			1.5e3,			# passband cutoff
			2e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_bb_filter = gr.fir_filter_fff(1, rds_bb_filter_coeffs)
		self.connect(self.mixer, self.rds_bb_filter)

		# 1187.5bps = 19kHz/16
		self.rds_clock = rds.freq_divider(16)
		clock_taps = gr.firdes.low_pass(
			1,				# gain
			demod_rate,		# sampling rate
			1.2e3,			# passband cutoff
			1.5e3,			# transition width
			gr.firdes.WIN_HANN)
		self.clock_filter = gr.fir_filter_fff(1, clock_taps)
		self.connect(self.pilot_filter, self.rds_clock, self.clock_filter)

		# bpsk_demod, diff_decoder, rds_decoder
		self.bpsk_demod = rds.bpsk_demod(demod_rate)
		self.differential_decoder = gr.diff_decoder_bb(2)
		self.msgq = gr.msg_queue()
		self.rds_decoder = rds.data_decoder(self.msgq)
		self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
		self.connect(self.clock_filter, (self.bpsk_demod, 1))
		self.connect(self.bpsk_demod, self.differential_decoder)
		self.connect(self.differential_decoder, self.rds_decoder)

		# set initial values
		self.subdev.set_gain(self.gain)
		self.set_vol(self.vol)
		self.set_freq(self.freq)
Example #36
0
def multiply_ff(N):
    op = gr.multiply_ff()
    tb = helper(N, op, gr.sizeof_float, gr.sizeof_float, 2, 1)
    return tb
Example #37
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        self.frame = frame
        self.panel = panel

        self.offset = 0.0  # Channel frequency offset

        parser = OptionParser(option_class=eng_option)

        parser.add_option(
            "-p",
            "--protocol",
            type="int",
            default=1,
            help="set protocol: 0 = RDLAP 19.2kbps; 1 = APCO25 (default)")
        parser.add_option("-g",
                          "--gain",
                          type="eng_float",
                          default=1.0,
                          help="set linear input gain (default: %default)")
        parser.add_option("-x",
                          "--freq-translation",
                          type="eng_float",
                          default=0.0,
                          help="initial channel frequency translation")

        parser.add_option(
            "-n",
            "--frame-decim",
            type="int",
            default=1,
            help="set oscope frame decimation factor to n [default=1]")
        parser.add_option(
            "-v",
            "--v-scale",
            type="eng_float",
            default=5000,
            help="set oscope initial V/div to SCALE [default=%default]")
        parser.add_option(
            "-t",
            "--t-scale",
            type="eng_float",
            default=49e-6,
            help="set oscope initial s/div to SCALE [default=50us]")

        parser.add_option(
            "-I",
            "--audio-input",
            type="string",
            default="",
            help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_option("-r",
                          "--sample-rate",
                          type="eng_float",
                          default=48000,
                          help="set sample rate to RATE (default: %default)")

        parser.add_option(
            "-d",
            "--channel-decim",
            type="int",
            default=None,
            help=
            "set channel decimation factor to n [default depends on protocol]")

        parser.add_option("-w",
                          "--wav-file",
                          type="string",
                          default=None,
                          help="WAV input path")
        parser.add_option("-f",
                          "--data-file",
                          type="string",
                          default=None,
                          help="Data input path")
        parser.add_option("-B",
                          "--base-band",
                          action="store_true",
                          default=False)
        parser.add_option("-R", "--repeat", action="store_true", default=False)

        parser.add_option("-o",
                          "--wav-out",
                          type="string",
                          default=None,
                          help="WAV output path")
        parser.add_option("-G",
                          "--wav-out-gain",
                          type="eng_float",
                          default=0.05,
                          help="set WAV output gain (default: %default)")

        parser.add_option("-F",
                          "--data-out",
                          type="string",
                          default=None,
                          help="Data output path")

        parser.add_option("-C",
                          "--carrier-freq",
                          type="eng_float",
                          default=None,
                          help="set data output carrier frequency to FREQ",
                          metavar="FREQ")

        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        self.options = options

        if options.wav_file is not None:
            #try:
            self.input_file = gr.wavfile_source(options.wav_file,
                                                options.repeat)
            #except:
            #    print "WAV file not found or not a WAV file"
            #    sys.exit(1)

            print "WAV input: %i Hz, %i bits, %i channels" % (
                self.input_file.sample_rate(),
                self.input_file.bits_per_sample(), self.input_file.channels())

            self.sample_rate = self.input_file.sample_rate()
            self.input_stream = gr.throttle(gr.sizeof_float, self.sample_rate)
            self.connect(self.input_file, self.input_stream)
            self.src = gr.multiply_const_ff(options.gain)
        elif options.data_file is not None:
            if options.base_band:
                sample_size = gr.sizeof_float
                print "Data file is baseband (float)"
                self.src = gr.multiply_const_ff(options.gain)
            else:
                sample_size = gr.sizeof_gr_complex
                print "Data file is IF (complex)"
                self.src = gr.multiply_const_cc(options.gain)

            self.input_file = gr.file_source(sample_size, options.data_file,
                                             options.repeat)
            self.sample_rate = options.sample_rate  # E.g. 250000

            print "Data file sampling rate = " + str(self.sample_rate)

            self.input_stream = gr.throttle(sample_size, self.sample_rate)
            self.connect(self.input_file, self.input_stream)
        else:
            self.sample_rate = options.sample_rate
            print "Soundcard sampling rate = " + str(self.sample_rate)
            self.input_stream = audio.source(
                self.sample_rate, options.audio_input)  # float samples
            self.src = gr.multiply_const_ff(options.gain)

        print "Fixed input gain = " + str(options.gain)
        self.connect(self.input_stream, self.src)

        if options.wav_out is not None:
            output_rate = int(self.sample_rate)
            if options.channel_decim is not None:
                output_rate /= options.channel_decim
            self.wav_out = gr.wavfile_sink(options.wav_out, 1, output_rate, 16)
            print "Opened WAV output file: " + options.wav_out + " at rate: " + str(
                output_rate)
        else:
            self.wav_out = None

        if options.data_out is not None:
            if options.carrier_freq is None:
                self.data_out = gr.file_sink(gr.sizeof_float, options.data_out)
                print "Opened float data output file: " + options.data_out
            else:
                self.data_out = gr.file_sink(gr.sizeof_gr_complex,
                                             options.data_out)
                print "Opened complex data output file: " + options.data_out
        else:
            self.data_out = None

        self.num_inputs = 1

        input_rate = self.sample_rate
        #title='IF',
        #size=(1024,800),
        if (options.data_file is not None) and (options.base_band == False):
            self.scope = scopesink2.scope_sink_c(
                panel,
                sample_rate=input_rate,
                frame_decim=options.frame_decim,
                v_scale=options.v_scale,
                t_scale=options.t_scale,
                num_inputs=self.num_inputs)
        else:
            self.scope = scopesink2.scope_sink_f(
                panel,
                sample_rate=input_rate,
                frame_decim=options.frame_decim,
                v_scale=options.v_scale,
                t_scale=options.t_scale,
                num_inputs=self.num_inputs)

        #self.di = gr.deinterleave(gr.sizeof_float)
        #self.di = gr.complex_to_float(1)
        #self.di = gr.complex_to_imag()
        #self.dr = gr.complex_to_real()
        #self.connect(self.src,self.dr)
        #self.connect(self.src,self.di)
        #self.null = gr.null_sink(gr.sizeof_double)
        #self.connect(self.src,self.di)
        #self.connect((self.di,0),(self.scope,0))
        #self.connect((self.di,1),(self.scope,1))
        #self.connect(self.dr,(self.scope,0))
        #self.connect(self.di,(self.scope,1))

        self.msgq = gr.msg_queue(2)  # queue that holds a maximum of 2 messages
        self.queue_watcher = queue_watcher(self.msgq, self.adjust_freq_norm)

        #-------------------------------------------------------------------------------

        if options.protocol == 0:
            # ---------- RD-LAP 19.2 kbps (9600 ksps), 25kHz channel,
            print "RD-LAP selected"
            self.symbol_rate = 9600  # symbol rate; at 2 bits/symbol this corresponds to 19.2kbps

            if options.channel_decim is None:
                self.channel_decimation = 10  # decimation (final rate should be at least several symbol rate)
            else:
                self.channel_decimation = options.channel_decim

            self.max_frequency_offset = 12000.0  # coarse carrier tracker leash, ~ half a channel either way
            self.symbol_deviation = 1200.0  # this is frequency offset from center of channel to +1 / -1 symbols

            self.input_sample_rate = self.sample_rate

            self.protocol_processing = fsk4.rdlap_f(
                self.msgq,
                0)  # desired protocol processing block selected here

            self.channel_rate = self.input_sample_rate / self.channel_decimation

            # channel selection filter characteristics
            channel_taps = optfir.low_pass(
                1.0,  # Filter gain
                self.input_sample_rate,  # Sample rate
                10000,  # One-sided modulation bandwidth
                12000,  # One-sided channel bandwidth
                0.1,  # Passband ripple
                60)  # Stopband attenuation

            # symbol shaping filter characteristics
            symbol_coeffs = gr.firdes.root_raised_cosine(
                1.0,  # gain
                self.channel_rate,  # sampling rate
                self.symbol_rate,  # symbol rate
                0.2,  # alpha
                500)  # taps

        if options.protocol == 1:
            # ---------- APCO-25 C4FM Test Data
            print "APCO selected"
            self.symbol_rate = 4800  # symbol rate

            if options.channel_decim is None:
                self.channel_decimation = 20  # decimation
            else:
                self.channel_decimation = options.channel_decim

            self.max_frequency_offset = 6000.0  # coarse carrier tracker leash
            self.symbol_deviation = 600.0  # this is frequency offset from center of channel to +1 / -1 symbols

            self.input_sample_rate = self.sample_rate

            self.protocol_processing = fsk4.apco25_f(self.msgq, 0)
            self.channel_rate = self.input_sample_rate / self.channel_decimation

            # channel selection filter
            if (options.data_file is not None) and (options.base_band
                                                    == False):
                channel_taps = optfir.low_pass(
                    1.0,  # Filter gain
                    self.input_sample_rate,  # Sample rate
                    5000,  # One-sided modulation bandwidth
                    6500,  # One-sided channel bandwidth
                    0.2,  # Passband ripple (was 0.1)
                    60)  # Stopband attenuation
            else:
                channel_taps = None

            # symbol shaping filter
            symbol_coeffs = gr.firdes.root_raised_cosine(
                1.0,  # gain
                self.channel_rate,  # sampling rate
                self.symbol_rate,  # symbol rate
                0.2,  # alpha
                500)  # taps

        # ----------------- End of setup block

        print "Input rate = " + str(self.input_sample_rate)
        print "Channel decimation = " + str(self.channel_decimation)
        print "Channel rate = " + str(self.channel_rate)

        if channel_taps is not None:
            self.chan = gr.freq_xlating_fir_filter_ccf(
                self.channel_decimation,  # Decimation rate
                channel_taps,  # Filter taps
                0.0,  # Offset frequency
                self.input_sample_rate)  # Sample rate
            if (options.freq_translation != 0):
                print "Channel center frequency = " + str(
                    options.freq_translation)
                self.chan.set_center_freq(options.freq_translation)
        else:
            self.chan = None

        if options.carrier_freq is not None:
            print "Carrier frequency = " + str(options.carrier_freq)
            self.sig_carrier = gr.sig_source_c(self.channel_rate,
                                               gr.GR_COS_WAVE,
                                               options.carrier_freq, 1, 0)
            self.carrier_mul = gr.multiply_vcc(1)  # cc(gr.sizeof_gr_complex)

            self.connect(self.sig_carrier, (self.carrier_mul, 0))
            self.connect(self.chan, (self.carrier_mul, 1))

            self.sig_i_carrier = gr.sig_source_f(self.channel_rate,
                                                 gr.GR_COS_WAVE,
                                                 options.carrier_freq, 1, 0)
            self.sig_q_carrier = gr.sig_source_f(self.channel_rate,
                                                 gr.GR_COS_WAVE,
                                                 options.carrier_freq, 1,
                                                 (pi / 2.0))
            self.carrier_i_mul = gr.multiply_ff(1)
            self.carrier_q_mul = gr.multiply_ff(1)
            self.iq_to_float = gr.complex_to_float(1)
            self.carrier_iq_add = gr.add_ff(1)

            self.connect(self.carrier_mul, self.iq_to_float)
            self.connect((self.iq_to_float, 0), (self.carrier_i_mul, 0))
            self.connect((self.iq_to_float, 1), (self.carrier_q_mul, 0))
            self.connect(self.sig_i_carrier, (self.carrier_i_mul, 1))
            self.connect(self.sig_q_carrier, (self.carrier_q_mul, 1))
            self.connect(self.carrier_i_mul, (self.carrier_iq_add, 0))
            self.connect(self.carrier_q_mul, (self.carrier_iq_add, 1))
        else:
            self.sig_carrier = None
            self.carrier_mul = None

        #lf_channel_taps = optfir.low_pass(1.0,   # Filter gain
        #            self.input_sample_rate, # Sample rate
        #            2500, # One-sided modulation bandwidth
        #            3250, # One-sided channel bandwidth
        #            0.1,   # Passband ripple (0.1)
        #            60,    # Stopband attenuation
        #            9)     # Extra taps (default 2, which doesn't work at 48kHz)
        #self.lf = gr.fir_filter_fff(self.channel_decimation, lf_channel_taps)

        self.scope2 = scopesink2.scope_sink_f(panel,
                                              sample_rate=self.symbol_rate,
                                              frame_decim=1,
                                              v_scale=2,
                                              t_scale=0.025,
                                              num_inputs=self.num_inputs)

        # also note: this specifies the nominal frequency deviation for the 4-level fsk signal
        self.fm_demod_gain = self.channel_rate / (2.0 * pi *
                                                  self.symbol_deviation)
        self.fm_demod = gr.quadrature_demod_cf(self.fm_demod_gain)

        symbol_decim = 1
        self.symbol_filter = gr.fir_filter_fff(symbol_decim, symbol_coeffs)

        # eventually specify: sample rate, symbol rate
        self.demod_fsk4 = fsk4.demod_ff(self.msgq, self.channel_rate,
                                        self.symbol_rate)

        if (self.chan is not None):
            self.connect(self.src, self.chan, self.fm_demod,
                         self.symbol_filter, self.demod_fsk4,
                         self.protocol_processing)

            if options.wav_out is not None:
                print "WAV output gain = " + str(options.wav_out_gain)
                self.scaled_wav_data = gr.multiply_const_ff(
                    float(options.wav_out_gain))
                self.connect(self.scaled_wav_data, self.wav_out)

                if self.carrier_mul is None:
                    self.connect(self.fm_demod, self.scaled_wav_data)
                else:
                    self.connect(self.carrier_iq_add, self.scaled_wav_data)

            if self.data_out is not None:
                if self.carrier_mul is None:
                    self.connect(self.fm_demod, self.data_out)
                else:
                    self.connect(self.carrier_mul, self.data_out)

            # During signal, -4..4
            #self.connect(self.fm_demod, self.scope2)
        else:
            self.connect(self.src, self.symbol_filter, self.demod_fsk4,
                         self.protocol_processing)

        self.connect(self.src, self.scope)
        #self.connect(self.lf, self.scope)

        self.connect(self.demod_fsk4, self.scope2)
        #self.connect(self.symbol_filter, self.scope2)

        # --------------- End of most of the 4L-FSK hack & slash

        self._build_gui(vbox)

        # set initial values

        if options.gain is None:
            options.gain = 0

        self.set_gain(options.gain)
Example #38
0
    def __init__(self, subc, vlen, ss):
        gr.hier_block2.__init__(
            self, "new_snr_estimator",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * vlen),
            gr.io_signature(1, 1, gr.sizeof_float))

        print "Created Milan's SNR estimator"

        trigger = [0] * vlen
        trigger[0] = 1

        u = range(vlen / ss * (ss - 1))
        zeros_ind = map(lambda z: z + 1 + z / (ss - 1), u)

        skip1 = skip(gr.sizeof_gr_complex, vlen)
        for x in zeros_ind:
            skip1.skip(x)

        #print "skipped zeros",zeros_ind

        v = range(vlen / ss)
        ones_ind = map(lambda z: z * ss, v)

        skip2 = skip(gr.sizeof_gr_complex, vlen)
        for x in ones_ind:
            skip2.skip(x)

        #print "skipped ones",ones_ind

        v2s = gr.vector_to_stream(gr.sizeof_gr_complex, vlen)
        s2v1 = gr.stream_to_vector(gr.sizeof_gr_complex, vlen / ss)
        trigger_src_1 = gr.vector_source_b(trigger, True)

        s2v2 = gr.stream_to_vector(gr.sizeof_gr_complex, vlen / ss * (ss - 1))
        trigger_src_2 = gr.vector_source_b(trigger, True)

        mag_sq_ones = gr.complex_to_mag_squared(vlen / ss)
        mag_sq_zeros = gr.complex_to_mag_squared(vlen / ss * (ss - 1))

        filt_ones = gr.single_pole_iir_filter_ff(0.1, vlen / ss)
        filt_zeros = gr.single_pole_iir_filter_ff(0.1, vlen / ss * (ss - 1))

        sum_ones = vector_sum_vff(vlen / ss)
        sum_zeros = vector_sum_vff(vlen / ss * (ss - 1))

        D = gr.divide_ff()
        P = gr.multiply_ff()
        mult1 = gr.multiply_const_ff(ss - 1.0)
        add1 = gr.add_const_ff(-1.0)
        mult2 = gr.multiply_const_ff(1. / ss)
        scsnrdb = gr.nlog10_ff(10, 1, 0)
        filt_end = gr.single_pole_iir_filter_ff(0.1)

        self.connect(self, v2s, skip1, s2v1, mag_sq_ones, filt_ones, sum_ones)
        self.connect(trigger_src_1, (skip1, 1))

        self.connect(v2s, skip2, s2v2, mag_sq_zeros, filt_zeros, sum_zeros)
        self.connect(trigger_src_2, (skip2, 1))

        self.connect(sum_ones, D)
        self.connect(sum_zeros, (D, 1))
        self.connect(D, mult1, add1, mult2)

        self.connect(mult2, scsnrdb, filt_end, self)
    def __init__(self, fft_length, cp_length, kstime, threshold, threshold_type, threshold_gap, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()
        movingsum2_taps = [1.0 for i in range(fft_length//2)]
	#movingsum2_taps = [0.5 for i in range(fft_length*4)]		#apurv - implementing Veljo's suggestion, when pause b/w packets

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)	#apurv - implementing Veljo's suggestion, when pause b/w packets

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))


        self.connect(self.corr, self.moving_sum_filter)
        #self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))		# apurv--
	#self.connect(self.angle, gr.delay(gr.sizeof_float, offset), (self.sample_and_hold, 0))	#apurv++

	cross_correlate = 1
	if cross_correlate==1:
	   # cross-correlate with the known symbol
	   kstime = [k.conjugate() for k in kstime]
           kstime.reverse()
           self.crosscorr_filter = gr.fir_filter_ccc(1, kstime)

	   # get the magnitude #
	   self.corrmag = gr.complex_to_mag_squared()

	   self.f2b = gr.float_to_char()
	   self.threshold_factor = threshold #0.0012 #0.012   #0.0015
	   if 0:
	      self.slice = gr.threshold_ff(self.threshold_factor, self.threshold_factor, 0, fft_length)
	   else:
	      #thresholds = [self.threshold_factor, 9e-5]
	      self.slice = gr.threshold_ff(threshold, threshold, 0, fft_length, threshold_type, threshold_gap)

	   self.connect(self.input, self.crosscorr_filter, self.corrmag, self.slice, self.f2b)

	   # some debug dump #
	   self.connect(self.corrmag, gr.file_sink(gr.sizeof_float, "ofdm_corrmag.dat"))
	   #self.connect(self.f2b, gr.file_sink(gr.sizeof_char, "ofdm_f2b.dat"))
	   

	self.connect(self.f2b, (self.sample_and_hold,1))
	
        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
	#self.connect(self.pk_detect, (self,1))									#removed
	#self.connect(self.f2b, gr.delay(gr.sizeof_char, 1), (self, 1))
	self.connect(self.f2b, (self, 1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #40
0
	def __init__(self,frame,panel,vbox,argv):
		stdgui2.std_top_block.__init__ (self,frame,panel,vbox,argv)

		parser=OptionParser(option_class=eng_option)
		parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
						  help="select USRP Rx side A or B (default=A)")
		parser.add_option("-f", "--freq", type="eng_float", default=91.2e6,
						  help="set frequency to FREQ", metavar="FREQ")
		parser.add_option("-g", "--gain", type="eng_float", default=None,
						  help="set gain in dB")
# FIXME add squelch
		parser.add_option("-s", "--squelch", type="eng_float", default=0,
						  help="set squelch level (default is 0)")
		parser.add_option("-V", "--volume", type="eng_float", default=None,
						  help="set volume (default is midpoint)")
		parser.add_option("-O", "--audio-output", type="string", default="plughw:0,0",
						  help="pcm device name (default is plughw:0,0)")

		# print help when called with wrong arguments
		(options, args) = parser.parse_args()
		if len(args) != 0:
			parser.print_help()
			sys.exit(1)

		# connect to USRP
		usrp_decim = 250
		self.u = usrp.source_c(0, usrp_decim)
		print "USRP Serial:", self.u.serial_number()
		usrp_rate = self.u.adc_rate() / usrp_decim		# 256 kS/s
		print "usrp_rate =", usrp_rate
		audio_decim = 8
		audio_rate = usrp_rate / audio_decim			# 32 kS/s
		print "audio_rate =", audio_rate
		#if options.rx_subdev_spec is None:
		#	options.rx_subdev_spec = usrp.pick_subdev(self.u, dblist)

		self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
		self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
		print "Using d'board", self.subdev.side_and_name()

		# gain, volume, frequency
		self.gain = options.gain
		if options.gain is None:
			g = self.subdev.gain_range()
			self.gain = float(g[0]+g[1])/2
		self.vol = options.volume
		if self.vol is None:
			g = self.volume_range()
			self.vol = float(g[0]+g[1])/2
		self.freq = options.freq
		print "Volume:%r, Gain:%r, Freq:%3.1f MHz" % (self.vol, self.gain, self.freq/1e6)

		# channel filter
		chan_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			80e3,			# passband cutoff
			35e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.chan_filter = gr.fir_filter_ccf(1, chan_filter_coeffs)
		print "# channel filter:", len(chan_filter_coeffs), "taps"

		# PLL-based WFM demod
		fm_alpha = 0.25 * 250e3 * math.pi / usrp_rate		# 0.767
		fm_beta = fm_alpha * fm_alpha / 4.0					# 0.147
		fm_max_freq = 2.0 * math.pi * 90e3 / usrp_rate		# 2.209
		self.fm_demod = gr.pll_freqdet_cf(
			#fm_alpha,			# phase gain
			#fm_beta,			# freq gain
			1.0,				# Loop BW
			fm_max_freq,		# in radians/sample
			-fm_max_freq)
		self.fm_demod.set_alpha(fm_alpha)
		self.fm_demod.set_beta(fm_beta)
		self.connect(self.u, self.chan_filter, self.fm_demod)

		# L+R, pilot, L-R, RDS filters
		lpr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lpr_filter = gr.fir_filter_fff(audio_decim, lpr_filter_coeffs)
		pilot_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			19e3-500,		# low cutoff
			19e3+500,		# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
		dsbsc_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			38e3-15e3/2,	# low cutoff
			38e3+15e3/2,	# high cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.dsbsc_filter = gr.fir_filter_fff(1, dsbsc_filter_coeffs)
		rds_filter_coeffs = gr.firdes.band_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			57e3-3e3,		# low cutoff
			57e3+3e3,		# high cutoff
			3e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
		print "# lpr filter:", len(lpr_filter_coeffs), "taps"
		print "# pilot filter:", len(pilot_filter_coeffs), "taps"
		print "# dsbsc filter:", len(dsbsc_filter_coeffs), "taps"
		print "# rds filter:", len(rds_filter_coeffs), "taps"
		self.connect(self.fm_demod, self.lpr_filter)
		self.connect(self.fm_demod, self.pilot_filter)
		self.connect(self.fm_demod, self.dsbsc_filter)
		self.connect(self.fm_demod, self.rds_filter)

		# down-convert L-R, RDS
		self.stereo_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.stereo_baseband, 0))
		self.connect(self.pilot_filter, (self.stereo_baseband, 1))
		self.connect(self.dsbsc_filter, (self.stereo_baseband, 2))
		self.rds_baseband = gr.multiply_ff()
		self.connect(self.pilot_filter, (self.rds_baseband, 0))
		self.connect(self.pilot_filter, (self.rds_baseband, 1))
		self.connect(self.pilot_filter, (self.rds_baseband, 2))
		self.connect(self.rds_filter, (self.rds_baseband, 3))

		# low-pass and downsample L-R
		lmr_filter_coeffs = gr.firdes.low_pass(
			1.0,			# gain
			usrp_rate,		# sampling rate
			15e3,			# passband cutoff
			1e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.lmr_filter = gr.fir_filter_fff(audio_decim, lmr_filter_coeffs)
		self.connect(self.stereo_baseband, self.lmr_filter)

		# create L, R from L-R, L+R
		self.left = gr.add_ff()
		self.right = gr.sub_ff()
		self.connect(self.lpr_filter, (self.left, 0))
		self.connect(self.lmr_filter, (self.left, 1))
		self.connect(self.lpr_filter, (self.right, 0))
		self.connect(self.lmr_filter, (self.right, 1))

		# volume control, complex2flot, audio sink
		self.volume_control_l = gr.multiply_const_ff(self.vol)
		self.volume_control_r = gr.multiply_const_ff(self.vol)
		output_audio_rate = 48000
		self.audio_sink = audio.sink(int(output_audio_rate),
							options.audio_output, False)
		#self.connect(self.left, self.volume_control_l, (self.audio_sink, 0))
		#self.connect(self.right, self.volume_control_r, (self.audio_sink, 1))
		self.resamp_L = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.resamp_R = blks2.rational_resampler_fff(interpolation=output_audio_rate,decimation=audio_rate,taps=None,fractional_bw=None,)
		self.connect(self.left,  self.volume_control_l, self.resamp_L, (self.audio_sink, 0))
		self.connect(self.right, self.volume_control_r, self.resamp_R, (self.audio_sink, 1))

		# low-pass the baseband RDS signal at 1.5kHz
		rds_bb_filter_coeffs = gr.firdes.low_pass(
			1,				# gain
			usrp_rate,		# sampling rate
			1.5e3,			# passband cutoff
			2e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_bb_filter = gr.fir_filter_fff(audio_decim, rds_bb_filter_coeffs)
		print "# rds bb filter:", len(rds_bb_filter_coeffs), "taps"
		self.connect(self.rds_baseband, self.rds_bb_filter)

		# 1187.5bps = 19kHz/16
		self.clock_divider = rds.freq_divider(16)
		rds_clock_taps = gr.firdes.low_pass(
			1,				# gain
			usrp_rate,		# sampling rate
			1.2e3,			# passband cutoff
			1.5e3,			# transition width
			gr.firdes.WIN_HAMMING)
		self.rds_clock = gr.fir_filter_fff(audio_decim, rds_clock_taps)
		print "# rds clock filter:", len(rds_clock_taps), "taps"
		self.connect(self.pilot_filter, self.clock_divider, self.rds_clock)

		# bpsk_demod, diff_decoder, rds_decoder
		self.bpsk_demod = rds.bpsk_demod(audio_rate)
		self.differential_decoder = gr.diff_decoder_bb(2)
		self.msgq = gr.msg_queue()
		self.rds_decoder = rds.data_decoder(self.msgq)
		self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
		self.connect(self.rds_clock, (self.bpsk_demod, 1))
		self.connect(self.bpsk_demod, self.differential_decoder)
		self.connect(self.differential_decoder, self.rds_decoder)


		self.frame = frame
		self.panel = panel
		self._build_gui(vbox, usrp_rate, audio_rate)
		self.set_gain(self.gain)
		self.set_vol(self.vol)
		if not(self.set_freq(self.freq)):
			self._set_status_msg("Failed to set initial frequency")	
Example #41
0
    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)
Example #42
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B")
        parser.add_option(
            "-f",
            "--freq",
            type="eng_float",
            default=107.2e6,
            help="set Tx frequency to FREQ [required]",
            metavar="FREQ",
        )
        parser.add_option("--wavfile", type="string", default=None, help="open .wav audio file FILE")
        parser.add_option("--xml", type="string", default="rds_data.xml", help="open .xml RDS data FILE")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        usrp_interp = 500
        self.u = usrp.sink_c(0, usrp_interp)
        print "USRP Serial: ", self.u.serial_number()
        usrp_rate = self.u.dac_rate() / usrp_interp  # 256 kS/s

        # determine the daughterboard subdevice we're using
        if options.tx_subdev_spec is None:
            options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
        self.u.set_mux(usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec))
        self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec)
        print "Using d'board", self.subdev.side_and_name()

        # set max Tx gain, tune frequency and enable transmitter
        gain = self.subdev.gain_range()[1]
        self.subdev.set_gain(gain)
        print "Gain set to", gain
        if self.u.tune(self.subdev.which(), self.subdev, options.freq):
            print "Tuned to", options.freq / 1e6, "MHz"
        else:
            sys.exit(1)
        self.subdev.set_enable(True)

        # open wav file containing floats in the [-1, 1] range, repeat
        if options.wavfile is None:
            print "Please provide a wavfile to transmit! Exiting\n"
            sys.exit(1)
        self.src = gr.wavfile_source(options.wavfile, True)
        nchans = self.src.channels()
        sample_rate = self.src.sample_rate()
        bits_per_sample = self.src.bits_per_sample()
        print nchans, "channels,", sample_rate, "samples/sec,", bits_per_sample, "bits/sample"

        # resample to usrp rate
        self.resample_left = blks2.rational_resampler_fff(usrp_rate, sample_rate)
        self.resample_right = blks2.rational_resampler_fff(usrp_rate, sample_rate)
        self.connect((self.src, 0), self.resample_left)
        self.connect((self.src, 1), self.resample_right)

        # create L+R (mono) and L-R (stereo)
        self.audio_lpr = gr.add_ff()
        self.audio_lmr = gr.sub_ff()
        self.connect(self.resample_left, (self.audio_lpr, 0))
        self.connect(self.resample_left, (self.audio_lmr, 0))
        self.connect(self.resample_right, (self.audio_lpr, 1))
        self.connect(self.resample_right, (self.audio_lmr, 1))

        # low-pass filter for L+R
        audio_lpr_taps = gr.firdes.low_pass(
            0.5,  # gain
            usrp_rate,  # sampling rate
            15e3,  # passband cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING,
        )
        self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps)
        self.connect(self.audio_lpr, self.audio_lpr_filter)

        # create pilot tone at 19 kHz
        self.pilot = gr.sig_source_f(
            usrp_rate, gr.GR_SIN_WAVE, 19e3, 5e-2  # sampling rate  # waveform  # frequency
        )  # amplitude

        # upconvert L-R to 38 kHz and band-pass
        self.mix_stereo = gr.multiply_ff()
        audio_lmr_taps = gr.firdes.band_pass(
            80,  # gain
            usrp_rate,  # sampling rate
            38e3 - 15e3,  # low cutoff
            38e3 + 15e3,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING,
        )
        self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps)
        self.connect(self.audio_lmr, (self.mix_stereo, 0))
        self.connect(self.pilot, (self.mix_stereo, 1))
        self.connect(self.pilot, (self.mix_stereo, 2))
        self.connect(self.mix_stereo, self.audio_lmr_filter)

        # create RDS bitstream
        # diff-encode, manchester-emcode, NRZ
        # enforce the 1187.5bps rate
        # pulse shaping filter (matched with receiver)
        # mix with 57kHz carrier (equivalent to BPSK)
        self.rds_enc = rds.data_encoder("rds_data.xml")
        self.diff_enc = gr.diff_encoder_bb(2)
        self.manchester1 = gr.map_bb([1, 2])
        self.manchester2 = gr.unpack_k_bits_bb(2)
        self.nrz = gr.map_bb([-1, 1])
        self.c2f = gr.char_to_float()
        self.rate_enforcer = rds.rate_enforcer(usrp_rate)
        pulse_shaping_taps = gr.firdes.low_pass(
            1,  # gain
            usrp_rate,  # sampling rate
            1.5e3,  # passband cutoff
            2e3,  # transition width
            gr.firdes.WIN_HAMMING,
        )
        self.pulse_shaping = gr.fir_filter_fff(1, pulse_shaping_taps)
        self.bpsk_mod = gr.multiply_ff()
        self.connect(self.rds_enc, self.diff_enc, self.manchester1, self.manchester2, self.nrz, self.c2f)
        self.connect(self.c2f, (self.rate_enforcer, 0))
        self.connect(self.pilot, (self.rate_enforcer, 1))
        self.connect(self.rate_enforcer, (self.bpsk_mod, 0))
        self.connect(self.pilot, (self.bpsk_mod, 1))
        self.connect(self.pilot, (self.bpsk_mod, 2))
        self.connect(self.pilot, (self.bpsk_mod, 3))

        # RDS band-pass filter
        rds_filter_taps = gr.firdes.band_pass(
            50,  # gain
            usrp_rate,  # sampling rate
            57e3 - 3e3,  # low cutoff
            57e3 + 3e3,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING,
        )
        self.rds_filter = gr.fir_filter_fff(1, rds_filter_taps)
        self.connect(self.bpsk_mod, self.rds_filter)

        # mix L+R, pilot, L-R and RDS
        self.mixer = gr.add_ff()
        self.connect(self.audio_lpr_filter, (self.mixer, 0))
        self.connect(self.pilot, (self.mixer, 1))
        self.connect(self.audio_lmr_filter, (self.mixer, 2))
        self.connect(self.rds_filter, (self.mixer, 3))

        # fm modulation, gain & TX
        max_dev = 75e3
        k = 2 * math.pi * max_dev / usrp_rate  # modulator sensitivity
        self.modulator = gr.frequency_modulator_fc(k)
        self.gain = gr.multiply_const_cc(5e3)
        self.connect(self.mixer, self.modulator, self.gain, self.u)

        # plot an FFT to verify we are sending what we want
        if 1:
            self.fft = fftsink2.fft_sink_f(
                panel, title="Pre FM modulation", fft_size=512 * 4, sample_rate=usrp_rate, y_per_div=20, ref_level=-20
            )
            self.connect(self.mixer, self.fft)
            vbox.Add(self.fft.win, 1, wx.EXPAND)
        if 0:
            self.scope = scopesink2.scope_sink_f(panel, title="RDS encoder output", sample_rate=usrp_rate)
            self.connect(self.rds_enc, self.scope)
            vbox.Add(self.scope.win, 1, wx.EXPAND)
Example #43
0
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        # PN Sync

        # Create a delay line
        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        # Correlation from ML Sync
        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        # Create a moving sum filter for the corr output
        if 1:
            moving_sum_taps = [1.0 for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        else:
            moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)]
            self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps)

        # Create a moving sum filter for the input
        self.inputmag2 = gr.complex_to_mag_squared()

        # Modified by Yong (12.06.27)
        #movingsum2_taps = [1.0 for i in range(fft_length//2)]
        movingsum2_taps = [0.5 for i in range(fft_length)]

        if 1:
            self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        else:
            self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps)

        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        # Get magnitude (peaks) and angle (phase/freq error)
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = gr.sample_and_hold_ff()

        #ML measurements input to sampler block and detect
        self.sub1 = gr.add_const_ff(-1)
        self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Calculate the frequency offset from the correlation of the preamble
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))

        # Get the power of the input signal to normalize the output of the correlation
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
        self.connect(self.c2mag, (self.normalize,0))

        # Create a moving sum filter for the corr output
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
        
        self.connect(self.matched_filter, self.sub1, self.pk_detect)
        #self.connect(self.matched_filter, self.pk_detect)
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-nominator_f.dat"))
            self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-denominator_f.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #44
0
    def __init__(self, frame, panel, vbox, argv):
        stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-T",
                          "--tx-subdev-spec",
                          type="subdev",
                          default=None,
                          help="select USRP Tx side A or B")
        parser.add_option("-f",
                          "--freq",
                          type="eng_float",
                          default=107.2e6,
                          help="set Tx frequency to FREQ [required]",
                          metavar="FREQ")
        parser.add_option("--wavfile",
                          type="string",
                          default=None,
                          help="open .wav audio file FILE")
        parser.add_option("--xml",
                          type="string",
                          default="rds_data.xml",
                          help="open .xml RDS data FILE")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        usrp_interp = 500
        self.u = usrp.sink_c(0, usrp_interp)
        print "USRP Serial: ", self.u.serial_number()
        usrp_rate = self.u.dac_rate() / usrp_interp  # 256 kS/s

        # determine the daughterboard subdevice we're using
        if options.tx_subdev_spec is None:
            options.tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
        self.u.set_mux(
            usrp.determine_tx_mux_value(self.u, options.tx_subdev_spec))
        self.subdev = usrp.selected_subdev(self.u, options.tx_subdev_spec)
        print "Using d'board", self.subdev.side_and_name()

        # set max Tx gain, tune frequency and enable transmitter
        gain = self.subdev.gain_range()[1]
        self.subdev.set_gain(gain)
        print "Gain set to", gain
        if self.u.tune(self.subdev.which(), self.subdev, options.freq):
            print "Tuned to", options.freq / 1e6, "MHz"
        else:
            sys.exit(1)
        self.subdev.set_enable(True)

        # open wav file containing floats in the [-1, 1] range, repeat
        if options.wavfile is None:
            print "Please provide a wavfile to transmit! Exiting\n"
            sys.exit(1)
        self.src = gr.wavfile_source(options.wavfile, True)
        nchans = self.src.channels()
        sample_rate = self.src.sample_rate()
        bits_per_sample = self.src.bits_per_sample()
        print nchans, "channels,", sample_rate, "samples/sec,", \
         bits_per_sample, "bits/sample"

        # resample to usrp rate
        self.resample_left = blks2.rational_resampler_fff(
            usrp_rate, sample_rate)
        self.resample_right = blks2.rational_resampler_fff(
            usrp_rate, sample_rate)
        self.connect((self.src, 0), self.resample_left)
        self.connect((self.src, 1), self.resample_right)

        # create L+R (mono) and L-R (stereo)
        self.audio_lpr = gr.add_ff()
        self.audio_lmr = gr.sub_ff()
        self.connect(self.resample_left, (self.audio_lpr, 0))
        self.connect(self.resample_left, (self.audio_lmr, 0))
        self.connect(self.resample_right, (self.audio_lpr, 1))
        self.connect(self.resample_right, (self.audio_lmr, 1))

        # low-pass filter for L+R
        audio_lpr_taps = gr.firdes.low_pass(
            0.5,  # gain
            usrp_rate,  # sampling rate
            15e3,  # passband cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.audio_lpr_filter = gr.fir_filter_fff(1, audio_lpr_taps)
        self.connect(self.audio_lpr, self.audio_lpr_filter)

        # create pilot tone at 19 kHz
        self.pilot = gr.sig_source_f(
            usrp_rate,  # sampling rate
            gr.GR_SIN_WAVE,  # waveform
            19e3,  # frequency
            5e-2)  # amplitude

        # upconvert L-R to 38 kHz and band-pass
        self.mix_stereo = gr.multiply_ff()
        audio_lmr_taps = gr.firdes.band_pass(
            80,  # gain
            usrp_rate,  # sampling rate
            38e3 - 15e3,  # low cutoff
            38e3 + 15e3,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.audio_lmr_filter = gr.fir_filter_fff(1, audio_lmr_taps)
        self.connect(self.audio_lmr, (self.mix_stereo, 0))
        self.connect(self.pilot, (self.mix_stereo, 1))
        self.connect(self.pilot, (self.mix_stereo, 2))
        self.connect(self.mix_stereo, self.audio_lmr_filter)

        # create RDS bitstream
        # diff-encode, manchester-emcode, NRZ
        # enforce the 1187.5bps rate
        # pulse shaping filter (matched with receiver)
        # mix with 57kHz carrier (equivalent to BPSK)
        self.rds_enc = rds.data_encoder('rds_data.xml')
        self.diff_enc = gr.diff_encoder_bb(2)
        self.manchester1 = gr.map_bb([1, 2])
        self.manchester2 = gr.unpack_k_bits_bb(2)
        self.nrz = gr.map_bb([-1, 1])
        self.c2f = gr.char_to_float()
        self.rate_enforcer = rds.rate_enforcer(usrp_rate)
        pulse_shaping_taps = gr.firdes.low_pass(
            1,  # gain
            usrp_rate,  # sampling rate
            1.5e3,  # passband cutoff
            2e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.pulse_shaping = gr.fir_filter_fff(1, pulse_shaping_taps)
        self.bpsk_mod = gr.multiply_ff()
        self.connect (self.rds_enc, self.diff_enc, self.manchester1, \
         self.manchester2, self.nrz, self.c2f)
        self.connect(self.c2f, (self.rate_enforcer, 0))
        self.connect(self.pilot, (self.rate_enforcer, 1))
        self.connect(self.rate_enforcer, (self.bpsk_mod, 0))
        self.connect(self.pilot, (self.bpsk_mod, 1))
        self.connect(self.pilot, (self.bpsk_mod, 2))
        self.connect(self.pilot, (self.bpsk_mod, 3))

        # RDS band-pass filter
        rds_filter_taps = gr.firdes.band_pass(
            50,  # gain
            usrp_rate,  # sampling rate
            57e3 - 3e3,  # low cutoff
            57e3 + 3e3,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_filter = gr.fir_filter_fff(1, rds_filter_taps)
        self.connect(self.bpsk_mod, self.rds_filter)

        # mix L+R, pilot, L-R and RDS
        self.mixer = gr.add_ff()
        self.connect(self.audio_lpr_filter, (self.mixer, 0))
        self.connect(self.pilot, (self.mixer, 1))
        self.connect(self.audio_lmr_filter, (self.mixer, 2))
        self.connect(self.rds_filter, (self.mixer, 3))

        # fm modulation, gain & TX
        max_dev = 75e3
        k = 2 * math.pi * max_dev / usrp_rate  # modulator sensitivity
        self.modulator = gr.frequency_modulator_fc(k)
        self.gain = gr.multiply_const_cc(5e3)
        self.connect(self.mixer, self.modulator, self.gain, self.u)

        # plot an FFT to verify we are sending what we want
        if 1:
            self.fft = fftsink2.fft_sink_f(panel,
                                           title="Pre FM modulation",
                                           fft_size=512 * 4,
                                           sample_rate=usrp_rate,
                                           y_per_div=20,
                                           ref_level=-20)
            self.connect(self.mixer, self.fft)
            vbox.Add(self.fft.win, 1, wx.EXPAND)
        if 0:
            self.scope = scopesink2.scope_sink_f(panel,
                                                 title="RDS encoder output",
                                                 sample_rate=usrp_rate)
            self.connect(self.rds_enc, self.scope)
            vbox.Add(self.scope.win, 1, wx.EXPAND)
Example #45
0
    def __init__(self, fft_length, cp_length, half_sync, logging=False):
        gr.hier_block2.__init__(
            self,
            "ofdm_sync_pn",
            gr.io_signature(1, 1, gr.sizeof_gr_complex),  # Input signature
            gr.io_signature3(
                3,
                3,  # Output signature
                gr.sizeof_gr_complex,  # delayed input
                gr.sizeof_float,  # fine frequency offset
                gr.sizeof_char  # timing indicator
            ))

        if half_sync:
            period = fft_length / 2
            window = fft_length / 2
        else:  # full symbol
            period = fft_length + cp_length
            window = fft_length  # makes the plateau cp_length long

        # Calculate the frequency offset from the correlation of the preamble
        x_corr = gr.multiply_cc()
        self.connect(self, gr.conjugate_cc(), (x_corr, 0))
        self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
        P_d = gr.moving_average_cc(window, 1.0)
        self.connect(x_corr, P_d)

        P_d_angle = gr.complex_to_arg()
        self.connect(P_d, P_d_angle)

        # Get the power of the input signal to normalize the output of the correlation
        R_d = gr.moving_average_ff(window, 1.0)
        self.connect(self, gr.complex_to_mag_squared(), R_d)
        R_d_squared = gr.multiply_ff()  # this is retarded
        self.connect(R_d, (R_d_squared, 0))
        self.connect(R_d, (R_d_squared, 1))
        M_d = gr.divide_ff()
        self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
        self.connect(R_d_squared, (M_d, 1))

        # Now we need to detect peak of M_d

        # NOTE: replaced fir_filter with moving_average for clarity
        # the peak is up to cp_length long, but noisy, so average it out
        #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
        matched_filter = gr.moving_average_ff(cp_length, 1.0 / cp_length)

        # NOTE: the look_ahead parameter doesn't do anything
        # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
        #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
        peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
        # NOTE: gr.peak_detector_fb is broken!
        #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
        #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

        # offset by -1
        self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

        # peak_detect indicates the time M_d is highest, which is the end of the symbol.
        # We should try to sample in the middle of the plateau!!
        # FIXME until we figure out how to do this, just offset by cp_length/2
        offset = 6  #cp_length/2

        # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
        # modulate input(t - fft_length) by nco(t)
        # signal to sample input(t) at t-offset
        #
        # We can't delay by < 0 so instead:
        # input is delayed by fft_length
        # P_d_angle is delayed by offset
        # signal to sample is delayed by fft_length - offset
        #
        phi = gr.sample_and_hold_ff()
        self.connect(peak_detect, (phi, 1))
        self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi, 0))
        #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

        # FIXME: we add fft_length delay so that the preamble is nco corrected too
        # BUT is this buffering worth it? consider implementing sync as a proper block

        # delay the input signal to follow the frequency offset signal
        self.connect(self, gr.delay(gr.sizeof_gr_complex,
                                    (fft_length + offset)), (self, 0))
        self.connect(phi, (self, 1))
        self.connect(peak_detect, (self, 2))

        if logging:
            self.connect(matched_filter,
                         gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
            self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
            self.connect(P_d_angle,
                         gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
            self.connect(peak_detect,
                         gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
            self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))
Example #46
0
    def __init__(self):
        gr.top_block.__init__(self)

        parser = OptionParser(option_class=eng_option)
        parser.add_option("-R",
                          "--rx-subdev-spec",
                          type="subdev",
                          default=None,
                          help="select USRP Rx side A or B (default=A)")
        parser.add_option("-f",
                          "--freq",
                          type="eng_float",
                          default=91.2e6,
                          help="set frequency to FREQ",
                          metavar="FREQ")
        parser.add_option("-g",
                          "--gain",
                          type="eng_float",
                          default=None,
                          help="set gain in dB")
        parser.add_option("-s",
                          "--squelch",
                          type="eng_float",
                          default=0,
                          help="set squelch level (default is 0)")
        parser.add_option("-V",
                          "--volume",
                          type="eng_float",
                          default=None,
                          help="set volume (default is midpoint)")
        parser.add_option("-O",
                          "--audio-output",
                          type="string",
                          default="plughw:0,0",
                          help="pcm device name (default is plughw:0,0)")
        (options, args) = parser.parse_args()
        if len(args) != 0:
            parser.print_help()
            sys.exit(1)

        # connect to USRP
        usrp_decim = 250
        self.u = usrp.source_c(0, usrp_decim)
        print "USRP Serial: ", self.u.serial_number()
        demod_rate = self.u.adc_rate() / usrp_decim  # 256 kS/s
        audio_decim = 8
        audio_rate = demod_rate / audio_decim  # 32 kS/s
        if options.rx_subdev_spec is None:
            options.rx_subdev_spec = usrp.pick_subdev(self.u, dblist)

        self.u.set_mux(
            usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
        self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
        print "Using d'board", self.subdev.side_and_name()

        # gain, volume, frequency
        self.gain = options.gain
        if options.gain is None:
            self.gain = self.subdev.gain_range()[1]

        self.vol = options.volume
        if self.vol is None:
            g = self.volume_range()
            self.vol = float(g[0] + g[1]) / 2

        self.freq = options.freq
        if abs(self.freq) < 1e6:
            self.freq *= 1e6

        print "Volume:%r, Gain:%r, Freq:%3.1f MHz" % (self.vol, self.gain,
                                                      self.freq / 1e6)

        # channel filter, wfm_rcv_pll
        chan_filt_coeffs = optfir.low_pass(
            1,  # gain
            demod_rate,  # rate
            80e3,  # passband cutoff
            115e3,  # stopband cutoff
            0.1,  # passband ripple
            60)  # stopband attenuation
        self.chan_filt = gr.fir_filter_ccf(1, chan_filt_coeffs)
        self.guts = blks2.wfm_rcv_pll(demod_rate, audio_decim)
        self.connect(self.u, self.chan_filt, self.guts)

        # volume control, audio sink
        self.volume_control_l = gr.multiply_const_ff(self.vol)
        self.volume_control_r = gr.multiply_const_ff(self.vol)
        self.audio_sink = audio.sink(int(audio_rate), options.audio_output,
                                     False)
        self.connect((self.guts, 0), self.volume_control_l,
                     (self.audio_sink, 0))
        self.connect((self.guts, 1), self.volume_control_r,
                     (self.audio_sink, 1))

        # pilot channel filter (band-pass, 18.5-19.5kHz)
        pilot_filter_coeffs = gr.firdes.band_pass(
            1,  # gain
            demod_rate,  # sampling rate
            18.5e3,  # low cutoff
            19.5e3,  # high cutoff
            1e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.pilot_filter = gr.fir_filter_fff(1, pilot_filter_coeffs)
        self.connect(self.guts.fm_demod, self.pilot_filter)

        # RDS channel filter (band-pass, 54-60kHz)
        rds_filter_coeffs = gr.firdes.band_pass(
            1,  # gain
            demod_rate,  # sampling rate
            54e3,  # low cutoff
            60e3,  # high cutoff
            3e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_filter = gr.fir_filter_fff(1, rds_filter_coeffs)
        self.connect(self.guts.fm_demod, self.rds_filter)

        # create 57kHz subcarrier from 19kHz pilot, downconvert RDS channel
        self.mixer = gr.multiply_ff()
        self.connect(self.pilot_filter, (self.mixer, 0))
        self.connect(self.pilot_filter, (self.mixer, 1))
        self.connect(self.pilot_filter, (self.mixer, 2))
        self.connect(self.rds_filter, (self.mixer, 3))

        # low-pass the baseband RDS signal at 1.5kHz
        rds_bb_filter_coeffs = gr.firdes.low_pass(
            1,  # gain
            demod_rate,  # sampling rate
            1.5e3,  # passband cutoff
            2e3,  # transition width
            gr.firdes.WIN_HAMMING)
        self.rds_bb_filter = gr.fir_filter_fff(1, rds_bb_filter_coeffs)
        self.connect(self.mixer, self.rds_bb_filter)

        # 1187.5bps = 19kHz/16
        self.rds_clock = rds.freq_divider(16)
        clock_taps = gr.firdes.low_pass(
            1,  # gain
            demod_rate,  # sampling rate
            1.2e3,  # passband cutoff
            1.5e3,  # transition width
            gr.firdes.WIN_HANN)
        self.clock_filter = gr.fir_filter_fff(1, clock_taps)
        self.connect(self.pilot_filter, self.rds_clock, self.clock_filter)

        # bpsk_demod, diff_decoder, rds_decoder
        self.bpsk_demod = rds.bpsk_demod(demod_rate)
        self.differential_decoder = gr.diff_decoder_bb(2)
        self.msgq = gr.msg_queue()
        self.rds_decoder = rds.data_decoder(self.msgq)
        self.connect(self.rds_bb_filter, (self.bpsk_demod, 0))
        self.connect(self.clock_filter, (self.bpsk_demod, 1))
        self.connect(self.bpsk_demod, self.differential_decoder)
        self.connect(self.differential_decoder, self.rds_decoder)

        # set initial values
        self.subdev.set_gain(self.gain)
        self.set_vol(self.vol)
        self.set_freq(self.freq)
    def __init__(self, fft_length, cp_length, logging=False):
        """
        OFDM synchronization using PN Correlation:
        T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing
        Synchonization for OFDM," IEEE Trans. Communications, vol. 45,
        no. 12, 1997. Improved with averaging over the whole FFT and 
        peak averaging over cp_length.
        """
        
	gr.hier_block2.__init__(self, "ofdm_sync_pn",
				gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
                                gr.io_signature2(2, 2, gr.sizeof_float, gr.sizeof_char)) # Output signature

        self.input = gr.add_const_cc(0)

        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2)

        self.conjg = gr.conjugate_cc();
        self.corr = gr.multiply_cc();

        moving_sum_taps = [1.0 for i in range(fft_length//2)]
        self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps)
        
        self.inputmag2 = gr.complex_to_mag_squared()
        
        #movingsum2_taps = [0.125 for i in range(fft_length*4)]
        movingsum2_taps = [0.5 for i in range(fft_length*4)]
        self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps)
        
        self.square = gr.multiply_ff()
        self.normalize = gr.divide_ff()
     
        self.c2mag = gr.complex_to_mag_squared()
        self.angle = gr.complex_to_arg()

        self.sample_and_hold = flex.sample_and_hold_ff()

        self.sub1 = gr.add_const_ff(-1)
        # linklab, change peak detector parameters: use higher threshold to detect rise/fall of peak
        #self.pk_detect = gr.peak_detector_fb(0.20, 0.20, 30, 0.001)
        self.pk_detect = flex.peak_detector_fb(0.7, 0.7, 30, 0.001) # linklab
        #self.pk_detect = gr.peak_detector2_fb(9)

        self.connect(self, self.input)
        
        # Lower branch:        
        self.connect(self.input, self.delay)
        self.connect(self.input, (self.corr,0))
        self.connect(self.delay, self.conjg)
        self.connect(self.conjg, (self.corr,1))
        self.connect(self.corr, self.moving_sum_filter)
        self.connect(self.moving_sum_filter, self.c2mag)
        self.connect(self.moving_sum_filter, self.angle)
        self.connect(self.angle, (self.sample_and_hold,0))
        self.connect(self.c2mag, (self.normalize,0))

        # Upper branch
        self.connect(self.input, self.inputmag2, self.inputmovingsum)
        self.connect(self.inputmovingsum, (self.square,0))
        self.connect(self.inputmovingsum, (self.square,1))
        self.connect(self.square, (self.normalize,1))
 
        matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
        self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps)
        self.connect(self.normalize, self.matched_filter)
       
        # linklab, provide the signal power into peak detector, linklab
        self.connect(self.square, (self.pk_detect,1))

        self.connect(self.matched_filter, self.sub1, (self.pk_detect, 0))
        self.connect(self.pk_detect, (self.sample_and_hold,1))

        # Set output signals
        #    Output 0: fine frequency correction value
        #    Output 1: timing signal
        self.connect(self.sample_and_hold, (self,0))
        self.connect(self.pk_detect, (self,1))

        if logging:
            self.connect(self.square, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-square.dat"))						
            self.connect(self.c2mag, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-c2mag.dat"))			
            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.sub1, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sub1.dat"))
            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Example #48
0
  def __init__(self, fft_length, cp_length, half_sync, logging=False):
    gr.hier_block2.__init__(self, "ofdm_sync_pn",
      gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
      gr.io_signature3(3, 3,    # Output signature
        gr.sizeof_gr_complex,   # delayed input
        gr.sizeof_float,        # fine frequency offset
        gr.sizeof_char          # timing indicator
      ))

    if half_sync:
      period = fft_length/2
      window = fft_length/2
    else: # full symbol
      period = fft_length + cp_length
      window = fft_length       # makes the plateau cp_length long

    # Calculate the frequency offset from the correlation of the preamble
    x_corr = gr.multiply_cc()
    self.connect(self, gr.conjugate_cc(), (x_corr, 0))
    self.connect(self, gr.delay(gr.sizeof_gr_complex, period), (x_corr, 1))
    P_d = gr.moving_average_cc(window, 1.0)
    self.connect(x_corr, P_d)

    P_d_angle = gr.complex_to_arg()
    self.connect(P_d, P_d_angle)

    # Get the power of the input signal to normalize the output of the correlation
    R_d = gr.moving_average_ff(window, 1.0)
    self.connect(self, gr.complex_to_mag_squared(), R_d)
    R_d_squared = gr.multiply_ff() # this is retarded
    self.connect(R_d, (R_d_squared, 0))
    self.connect(R_d, (R_d_squared, 1))
    M_d = gr.divide_ff()
    self.connect(P_d, gr.complex_to_mag_squared(), (M_d, 0))
    self.connect(R_d_squared, (M_d, 1))

    # Now we need to detect peak of M_d

    # NOTE: replaced fir_filter with moving_average for clarity
    # the peak is up to cp_length long, but noisy, so average it out
    #matched_filter_taps = [1.0/cp_length for i in range(cp_length)]
    #matched_filter = gr.fir_filter_fff(1, matched_filter_taps)
    matched_filter = gr.moving_average_ff(cp_length, 1.0/cp_length)

    # NOTE: the look_ahead parameter doesn't do anything
    # these parameters are kind of magic, increase 1 and 2 (==) to be more tolerant
    #peak_detect = raw.peak_detector_fb(0.55, 0.55, 30, 0.001)
    peak_detect = raw.peak_detector_fb(0.25, 0.25, 30, 0.001)
    # NOTE: gr.peak_detector_fb is broken!
    #peak_detect = gr.peak_detector_fb(0.55, 0.55, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.45, 0.45, 30, 0.001)
    #peak_detect = gr.peak_detector_fb(0.30, 0.30, 30, 0.001)

    # offset by -1
    self.connect(M_d, matched_filter, gr.add_const_ff(-1), peak_detect)

    # peak_detect indicates the time M_d is highest, which is the end of the symbol.
    # We should try to sample in the middle of the plateau!!
    # FIXME until we figure out how to do this, just offset by cp_length/2
    offset = 6 #cp_length/2

    # nco(t) = P_d_angle(t-offset) sampled at peak_detect(t)
    # modulate input(t - fft_length) by nco(t)
    # signal to sample input(t) at t-offset
    #
    # We can't delay by < 0 so instead:
    # input is delayed by fft_length
    # P_d_angle is delayed by offset
    # signal to sample is delayed by fft_length - offset
    #
    phi = gr.sample_and_hold_ff()
    self.connect(peak_detect, (phi,1))
    self.connect(P_d_angle, gr.delay(gr.sizeof_float, offset), (phi,0))
    #self.connect(P_d_angle, matched_filter2, (phi,0)) # why isn't this better?!?

    # FIXME: we add fft_length delay so that the preamble is nco corrected too
    # BUT is this buffering worth it? consider implementing sync as a proper block

    # delay the input signal to follow the frequency offset signal
    self.connect(self, gr.delay(gr.sizeof_gr_complex, (fft_length+offset)), (self,0))
    self.connect(phi, (self,1))
    self.connect(peak_detect, (self,2))

    if logging:
      self.connect(matched_filter, gr.file_sink(gr.sizeof_float, "sync-mf.dat"))
      self.connect(M_d, gr.file_sink(gr.sizeof_float, "sync-M.dat"))
      self.connect(P_d_angle, gr.file_sink(gr.sizeof_float, "sync-angle.dat"))
      self.connect(peak_detect, gr.file_sink(gr.sizeof_char, "sync-peaks.datb"))
      self.connect(phi, gr.file_sink(gr.sizeof_float, "sync-phi.dat"))