def __init__(self, alpha=0.0001, threshold_db=-10, gate=False):
        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

        #fixed coeffs, Chebyshev type 2 LPF=[0, 0.4, 0.7], HPF=[0.4, 0.7, 1]
        self.low_iir = iir_filter_ffd([
            0.12260106307699403, -0.22058023529806434, 0.22058023529806436,
            -0.12260106307699434
        ], [
            1.00000000000000000, 0.7589332900264623, 0.5162740252200005,
            0.07097813844342238
        ], False)
        self.low_square = blocks.multiply_ff()
        self.low_smooth = single_pole_iir_filter_ff(alpha)

        self.hi_iir = iir_filter_ffd([
            0.1913118666668073, 0.4406071020350289, 0.4406071020350288,
            0.19131186666680736
        ], [
            1.000000000000000000, -0.11503633296078866, 0.3769676347066441,
            0.0019066356578167866
        ], False)
        self.hi_square = blocks.multiply_ff()
        self.hi_smooth = single_pole_iir_filter_ff(alpha)

        #inverted thresholds because we reversed the division block inputs
        #to make the threshold output 1 when open and 0 when closed
        self.gate = blocks.threshold_ff(0, 0, 0)
        self.set_threshold(threshold_db)
        self.squelch_lpf = single_pole_iir_filter_ff(alpha)
        self.squelch_mult = blocks.multiply_ff()
        self.div = blocks.divide_ff()

        #This is horrible, but there's no better way to gate samples.
        #the block is fast, so realistically there's little overhead
        #TODO: implement a valve block that gates based on an input value
        self.valve = analog.pwr_squelch_ff(-100, 1, 0, gate)

        #sample path
        self.connect(self, (self.squelch_mult, 0))

        #filter path (LPF)
        self.connect(self, 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.div, 0))

        #filter path (HPF)
        self.connect(self, 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.div, 1))

        #control path
        self.connect(self.div, self.gate, self.squelch_lpf,
                     (self.squelch_mult, 1))
        self.connect(self.squelch_mult, self)
Exemple #2
0
    def __init__(self, audio_rate):
        gr.hier_block2.__init__(
            self,
            "standard_squelch",
            # Input signature
            gr.io_signature(1, 1, gr.sizeof_float),
            gr.io_signature(1, 1, gr.sizeof_float))  # Output signature

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

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

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

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

        self.div = blocks.divide_ff()
        self.squelch_mult = blocks.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, alpha=0.0001, threshold_db=-10, gate=False):
        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


        #fixed coeffs, Chebyshev type 2 LPF=[0, 0.4, 0.7], HPF=[0.4, 0.7, 1]
        self.low_iir = iir_filter_ffd([0.12260106307699403, -0.22058023529806434, 0.22058023529806436, -0.12260106307699434],
                                             [1.00000000000000000, 0.7589332900264623, 0.5162740252200005, 0.07097813844342238],
                                             False)
        self.low_square = blocks.multiply_ff()
        self.low_smooth = single_pole_iir_filter_ff(alpha)

        self.hi_iir = iir_filter_ffd([0.1913118666668073, 0.4406071020350289, 0.4406071020350288, 0.19131186666680736],
                                            [1.000000000000000000, -0.11503633296078866, 0.3769676347066441, 0.0019066356578167866], 
                                             False)
        self.hi_square = blocks.multiply_ff()
        self.hi_smooth = single_pole_iir_filter_ff(alpha)

        #inverted thresholds because we reversed the division block inputs
        #to make the threshold output 1 when open and 0 when closed
        self.gate = blocks.threshold_ff(0,0,0)
        self.set_threshold(threshold_db)
        self.squelch_lpf = single_pole_iir_filter_ff(alpha)
        self.squelch_mult = blocks.multiply_ff()
        self.div = blocks.divide_ff()

        #This is horrible, but there's no better way to gate samples.
        #the block is fast, so realistically there's little overhead
        #TODO: implement a valve block that gates based on an input value
        self.valve = analog.pwr_squelch_ff(-100, 1, 0, gate)

        #sample path
        self.connect(self, (self.squelch_mult, 0))

        #filter path (LPF)
        self.connect(self,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.div,0))

        #filter path (HPF)
        self.connect(self,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.div,1))

        #control path
        self.connect(self.div, self.gate, self.squelch_lpf, (self.squelch_mult,1))
        self.connect(self.squelch_mult, self)
    def test_multiply_vff_one(self):
	src1_data = (1.0,)
	src2_data = (2.0,)
	src3_data = (3.0,)
	expected_result = (6.0,)
	op = blocks.multiply_ff(1)
	self.help_ff(1, (src1_data, src2_data, src3_data), expected_result, op)
Exemple #5
0
    def connect_audio_stage(self, input_port):
        stereo_rate = self.demod_rate
        normalizer = TWO_PI / stereo_rate
        pilot_tone = 19000
        pilot_low = pilot_tone * 0.98
        pilot_high = pilot_tone * 1.02

        def make_audio_filter():
            return grfilter.fir_filter_fff(
                stereo_rate // self.__audio_int_rate,  # decimation
                firdes.low_pass(1.0, stereo_rate, 15000, 5000,
                                firdes.WIN_HAMMING))

        stereo_pilot_filter = grfilter.fir_filter_fcc(
            1,  # decimation
            firdes.complex_band_pass(1.0, stereo_rate, pilot_low, pilot_high,
                                     300))  # TODO magic number from gqrx
        stereo_pilot_pll = analog.pll_refout_cc(
            loop_bw=0.001,
            max_freq=normalizer * pilot_high,
            min_freq=normalizer * pilot_low)
        stereo_pilot_doubler = blocks.multiply_cc()
        stereo_pilot_out = blocks.complex_to_real()
        difference_channel_mixer = blocks.multiply_ff()
        difference_channel_filter = make_audio_filter()
        mono_channel_filter = make_audio_filter()
        mixL = blocks.add_ff(1)
        mixR = blocks.sub_ff(1)

        # connections
        self.connect(input_port, mono_channel_filter)
        if self.__decode_stereo:
            # stereo pilot tone tracker
            self.connect(input_port, stereo_pilot_filter, stereo_pilot_pll)
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 0))
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 1))
            self.connect(stereo_pilot_doubler, stereo_pilot_out)

            # pick out stereo left-right difference channel (at stereo_rate)
            self.connect(input_port, (difference_channel_mixer, 0))
            self.connect(stereo_pilot_out, (difference_channel_mixer, 1))
            self.connect(
                difference_channel_mixer,
                blocks.multiply_const_ff(
                    50
                ),  # TODO: Completely empirical fudge factor. This should not be necessary. We're losing signal somewhere?
                difference_channel_filter)

            # recover left/right channels (at self.__audio_int_rate)
            self.connect(difference_channel_filter, (mixL, 1))
            self.connect(difference_channel_filter, (mixR, 1))
            resamplerL = self._make_resampler((mixL, 0), self.__audio_int_rate)
            resamplerR = self._make_resampler((mixR, 0), self.__audio_int_rate)
            self.connect(mono_channel_filter, (mixL, 0))
            self.connect(mono_channel_filter, (mixR, 0))
            self.connect_audio_output(resamplerL, resamplerR)
        else:
            resampler = self._make_resampler(mono_channel_filter,
                                             self.__audio_int_rate)
            self.connect_audio_output(resampler, resampler)
    def test_multiply_vff_five(self):
	src1_data = (1.0, 2.0, 3.0, 4.0, 5.0)
	src2_data = (6.0, 7.0, 8.0, 9.0, 10.0)
	src3_data = (11.0, 12.0, 13.0, 14.0, 15.0)
	expected_result = (66.0, 168.0, 312.0, 504.0, 750.0)
	op = blocks.multiply_ff(5)
	self.help_ff(5, (src1_data, src2_data, src3_data), expected_result, op)
Exemple #7
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=81000)
        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 = analog.sig_source_f (sample_rate, analog.GR_SIN_WAVE, options.frequency, ampl)
        osc2 =  analog.sig_source_f (sample_rate, analog.GR_SIN_WAVE, 80000, .5)
        mixer = blocks.multiply_ff ()
        self.connect (osc, (mixer, 0))
        self.connect (osc2, (mixer, 1))
        dst = audio.sink (sample_rate, options.audio_output, True)
        self.connect (mixer, dst)
    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 = blocks.vector_source_f(vec1, True)
        multiply = blocks.multiply_ff()

        self.connect(src, (multiply, 0))
        self.connect(vsource, (multiply, 1))
        self.connect(multiply, dst)
 def test_multiply_ff(self):
     src1_data = [1,  2, 3, 4, 5]
     src2_data = [8, -3, 4, 8, 2]
     expected_result = [8, -6, 12, 32, 10]
     op = blocks.multiply_ff()
     self.help_ff((src1_data, src2_data),
                   expected_result, op)
 def test_multiply_ff(self):
     src1_data = (1,  2, 3, 4, 5)
     src2_data = (8, -3, 4, 8, 2)
     expected_result = (8, -6, 12, 32, 10)
     op = blocks.multiply_ff()
     self.help_ff((src1_data, src2_data),
                   expected_result, op)
    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")
        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=45000)
        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)
        if ampl > 1.0: ampl = 1.0

        osc = analog.sig_source_f (sample_rate, analog.GR_SIN_WAVE, options.frequency, ampl)
        src = audio.source (sample_rate, options.audio_input)
        mixer = blocks.multiply_ff ()
        self.connect (osc, (mixer, 0))
        self.connect (src, (mixer, 1))
        dst = audio.sink (sample_rate, options.audio_output, True)
        self.connect (mixer, dst)
Exemple #12
0
 def test_multiply_vff_five(self):
     src1_data = [1.0, 2.0, 3.0, 4.0, 5.0]
     src2_data = [6.0, 7.0, 8.0, 9.0, 10.0]
     src3_data = [11.0, 12.0, 13.0, 14.0, 15.0]
     expected_result = [66.0, 168.0, 312.0, 504.0, 750.0]
     op = blocks.multiply_ff(5)
     self.help_ff(5, (src1_data, src2_data, src3_data), expected_result, op)
 def test_multiply_ff(self):
     src1_data = (1,  2, 3, 4, 5)
     src2_data = (8, -3, 4, 8, 2)
     expected_result = (8, -6, 12, 32, 10)
     op = blocks.multiply_ff()
     self.help_ff((src1_data, src2_data),
                   expected_result, op)
Exemple #14
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 = blocks.vector_source_f(vec1, True)
	multiply = blocks.multiply_ff()

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

        parser = ArgumentParser()
        parser.add_argument(
            "-I",
            "--audio-input",
            default="",
            help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_argument(
            "-O",
            "--audio-output",
            default="",
            help="pcm output device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_argument("-r",
                            "--sample-rate",
                            type=eng_float,
                            default=8000,
                            help="set sample rate to RATE (%(default)r)")
        args = parser.parse_args()
        sample_rate = int(args.sample_rate)
        src = audio.source(sample_rate, args.audio_input)
        dst = audio.sink(sample_rate, args.audio_output)

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

        self.connect(src, (multiply, 0))
        self.connect(vsource, (multiply, 1))
        self.connect(multiply, dst)
 def test_multiply_vff_one(self):
     src1_data = (1.0, )
     src2_data = (2.0, )
     src3_data = (3.0, )
     expected_result = (6.0, )
     op = blocks.multiply_ff(1)
     self.help_ff(1, (src1_data, src2_data, src3_data), expected_result, op)
Exemple #17
0
 def __init__(self):
     analog_source.__init__(self, mod_name="am-ssb", audio_rate=44.1e3)
     self.interp = filter.fractional_resampler_ff(0.0,
                                                  self.audio_rate / 200e3)
     self.add = blocks.add_const_ff(1.0)
     self.mod = blocks.multiply_ff()
     self.filt = filter.hilbert_fc(401)
     self.connect(self.random_source, self.interp, self.add, self.filt,
                  self)
Exemple #18
0
def test_multiply_ff():
    top = gr.top_block()
    src = blocks.null_source(gr.sizeof_float)
    mul = blocks.multiply_ff()
    probe = blocks.probe_rate(gr.sizeof_float)
    top.connect((src, 0), (mul, 0))
    top.connect((src, 0), (mul, 1))
    top.connect(mul, probe)

    return top, probe
def test_multiply_ff():
    top = gr.top_block()
    src = blocks.null_source(gr.sizeof_float)
    mul = blocks.multiply_ff()
    probe = blocks.probe_rate(gr.sizeof_float)
    top.connect((src, 0), (mul, 0))
    top.connect((src, 0), (mul, 1))
    top.connect(mul, probe)

    return top, probe
Exemple #20
0
    def __init__(self, samp_rate, center_freq):
        gr.hier_block2.__init__(self, "Mixer for downconversion",
                                gr.io_signature(1,1,gr.sizeof_float),
                                gr.io_signature(2,2,gr.sizeof_float))

        cosine = analog.sig_source_f(samp_rate, analog.GR_COS_WAVE, center_freq, 1, 0)
        sine   = analog.sig_source_f(samp_rate, analog.GR_SIN_WAVE, center_freq, 1, 0)

        mixer_I = blocks.multiply_ff(1)
        mixer_Q = blocks.multiply_ff(1)

        self.connect(self,   (mixer_I,0))
        self.connect(cosine, (mixer_I,1))

        self.connect(self, (mixer_Q,0))
        self.connect(sine, (mixer_Q,1))

        self.connect(mixer_I, (self,0))
        self.connect(mixer_Q, (self,1))
Exemple #21
0
    def connect_audio_stage(self, input_port):
        stereo_rate = self.demod_rate
        normalizer = TWO_PI / stereo_rate
        pilot_tone = 19000
        pilot_low = pilot_tone * 0.9
        pilot_high = pilot_tone * 1.1

        def make_audio_filter():
            return grfilter.fir_filter_fff(
                stereo_rate // self.__audio_int_rate,  # decimation
                firdes.low_pass(1.0, stereo_rate, 15000, 5000,
                                firdes.WIN_HAMMING))

        stereo_pilot_filter = grfilter.fir_filter_fcc(
            1,  # decimation
            firdes.complex_band_pass(1.0, stereo_rate, pilot_low, pilot_high,
                                     300))  # TODO magic number from gqrx
        stereo_pilot_pll = analog.pll_refout_cc(
            0.001,  # TODO magic number from gqrx
            normalizer * pilot_high,
            normalizer * pilot_low)
        stereo_pilot_doubler = blocks.multiply_cc()
        stereo_pilot_out = blocks.complex_to_imag()
        difference_channel_mixer = blocks.multiply_ff()
        difference_channel_filter = make_audio_filter()
        mono_channel_filter = make_audio_filter()
        mixL = blocks.add_ff(1)
        mixR = blocks.sub_ff(1)

        # connections
        self.connect(input_port, mono_channel_filter)
        if self.stereo:
            # stereo pilot tone tracker
            self.connect(input_port, stereo_pilot_filter, stereo_pilot_pll)
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 0))
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 1))
            self.connect(stereo_pilot_doubler, stereo_pilot_out)

            # pick out stereo left-right difference channel (at stereo_rate)
            self.connect(input_port, (difference_channel_mixer, 0))
            self.connect(stereo_pilot_out, (difference_channel_mixer, 1))
            self.connect(difference_channel_mixer, difference_channel_filter)

            # recover left/right channels (at self.__audio_int_rate)
            self.connect(difference_channel_filter, (mixL, 1))
            self.connect(difference_channel_filter, (mixR, 1))
            resamplerL = self._make_resampler((mixL, 0), self.__audio_int_rate)
            resamplerR = self._make_resampler((mixR, 0), self.__audio_int_rate)
            self.connect(mono_channel_filter, (mixL, 0))
            self.connect(mono_channel_filter, (mixR, 0))
            self.connect_audio_output(resamplerL, resamplerR)
        else:
            resampler = self._make_resampler(mono_channel_filter,
                                             self.__audio_int_rate)
            self.connect_audio_output(resampler, resampler)
    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 = blocks.add_const_ff(0)          # FIXME kludge

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

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

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

        self.div = blocks.divide_ff()
        self.squelch_mult = blocks.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)
Exemple #23
0
    def __init__(self, samp_rate):
        gr.hier_block2.__init__(self, "BPM Signal from ADC",
                              gr.io_signature(0,0,0),#no input, this is a source
                              gr.io_signature(1,1,gr.sizeof_float))

        carrier = analog.sig_source_f(samp_rate,   analog.GR_COS_WAVE, 20e6, 1, 0)
        modulating = analog.sig_source_f(samp_rate, analog.GR_SIN_WAVE, 2e3,  0.05, 0.975)
        mixer = blocks.multiply_ff(1)

        self.connect(carrier, (mixer,0))
        self.connect(modulating, (mixer,1))
        self.connect(mixer,self)
Exemple #24
0
    def connect_audio_stage(self, input_port):
        stereo_rate = self.demod_rate
        normalizer = TWO_PI / stereo_rate
        pilot_tone = 19000
        pilot_low = pilot_tone * 0.9
        pilot_high = pilot_tone * 1.1

        def make_audio_filter():
            return grfilter.fir_filter_fff(
                stereo_rate // self.__audio_int_rate,  # decimation
                firdes.low_pass(1.0, stereo_rate, 15000, 5000, firdes.WIN_HAMMING),
            )

        stereo_pilot_filter = grfilter.fir_filter_fcc(
            1, firdes.complex_band_pass(1.0, stereo_rate, pilot_low, pilot_high, 300)  # decimation
        )  # TODO magic number from gqrx
        stereo_pilot_pll = analog.pll_refout_cc(
            0.001, normalizer * pilot_high, normalizer * pilot_low  # TODO magic number from gqrx
        )
        stereo_pilot_doubler = blocks.multiply_cc()
        stereo_pilot_out = blocks.complex_to_imag()
        difference_channel_mixer = blocks.multiply_ff()
        difference_channel_filter = make_audio_filter()
        mono_channel_filter = make_audio_filter()
        mixL = blocks.add_ff(1)
        mixR = blocks.sub_ff(1)

        # connections
        self.connect(input_port, mono_channel_filter)
        if self.stereo:
            # stereo pilot tone tracker
            self.connect(input_port, stereo_pilot_filter, stereo_pilot_pll)
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 0))
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 1))
            self.connect(stereo_pilot_doubler, stereo_pilot_out)

            # pick out stereo left-right difference channel (at stereo_rate)
            self.connect(input_port, (difference_channel_mixer, 0))
            self.connect(stereo_pilot_out, (difference_channel_mixer, 1))
            self.connect(difference_channel_mixer, difference_channel_filter)

            # recover left/right channels (at self.__audio_int_rate)
            self.connect(difference_channel_filter, (mixL, 1))
            self.connect(difference_channel_filter, (mixR, 1))
            resamplerL = self._make_resampler((mixL, 0), self.__audio_int_rate)
            resamplerR = self._make_resampler((mixR, 0), self.__audio_int_rate)
            self.connect(mono_channel_filter, (mixL, 0))
            self.connect(mono_channel_filter, (mixR, 0))
            self.connect_audio_output(resamplerL, resamplerR)
        else:
            resampler = self._make_resampler(mono_channel_filter, self.__audio_int_rate)
            self.connect_audio_output(resampler, resampler)
 def __init__(self):
     gr.hier_block2.__init__(self, "transmitter_amssb",
                             gr.io_signature(1, 1, gr.sizeof_float),
                             gr.io_signature(1, 1, gr.sizeof_gr_complex))
     self.rate = 44.1e3 / 200e3
     self.interp = filter.fractional_interpolator_ff(0.0, self.rate)
     self.mul = blocks.multiply_const_ff(1.0)
     self.add = blocks.add_const_ff(1.0)
     self.src = analog.sig_source_f(200e3, analog.GR_SIN_WAVE, 0e3, 1.0)
     self.mod = blocks.multiply_ff()
     self.filt = filter.hilbert_fc(401)
     self.connect(self, self.interp, self.mul, self.add, self.mod,
                  self.filt, self)
     self.connect(self.src, (self.mod, 1))
Exemple #26
0
 def test_multiply_vff_one(self):
     src1_data = [
         1.0,
     ]
     src2_data = [
         2.0,
     ]
     src3_data = [
         3.0,
     ]
     expected_result = [
         6.0,
     ]
     op = blocks.multiply_ff(1)
     self.help_ff(1, (src1_data, src2_data, src3_data), expected_result, op)
Exemple #27
0
    def __init__(self):
        gr.hier_block2.__init__(self, "transmitter_amssb",
        gr.io_signature(1, 1, gr.sizeof_float),
        gr.io_signature(1, 1, gr.sizeof_gr_complex))
        self.rate = 44.1e3/200e3
        #self.rate = 200e3/44.1e3
        self.interp = filter.fractional_interpolator_ff(0.0, self.rate)
#        self.cnv = blocks.float_to_complex()
        self.mul = blocks.multiply_const_ff(1.0)
        self.add = blocks.add_const_ff(1.0)
        self.src = analog.sig_source_f(200e3, analog.GR_SIN_WAVE, 0e3, 1.0)
        #self.src = analog.sig_source_c(200e3, analog.GR_SIN_WAVE, 50e3, 1.0)
        self.mod = blocks.multiply_ff()
        #self.filt = filter.fir_filter_ccf(1, firdes.band_pass(1.0, 200e3, 10e3, 60e3, 0.25e3, firdes.WIN_HAMMING, 6.76))
        self.filt = filter.hilbert_fc(401)
        self.connect( self, self.interp, self.mul, self.add, self.mod, self.filt, self )
        self.connect( self.src, (self.mod,1) )
Exemple #28
0
 def __init__(self):
     gr.hier_block2.__init__(self, "transmitter_am",
                             gr.io_signature(1, 1, gr.sizeof_float),
                             gr.io_signature(1, 1, gr.sizeof_gr_complex))
     samp_rate = 200e3
     self.rate = 44.1e3 / samp_rate
     # #self.rate = 200e3/44.1e3
     self.interp = filter.fractional_interpolator_ff(0.0, self.rate)
     self.mul = blocks.multiply_const_ff(1.0)
     self.add = blocks.add_const_ff(1.0)
     self.src = analog.sig_source_f(samp_rate, analog.GR_SIN_WAVE, 0e3, 1.0)
     #self.src = analog.sig_source_c(200e3, analog.GR_SIN_WAVE, 50e3, 1.0)
     self.mod = blocks.multiply_ff()
     self.cnv = blocks.float_to_complex()
     self.connect(self, self.interp, self.mul, self.add, self.mod, self.cnv,
                  self)
     self.connect(self.src, (self.mod, 1))
    def __init__(self, src_file):
        gr.top_block.__init__(self)

        sample_rate = 11025
	ampl = 0.1
        print src_file
        # Audio source (.wav file)
        # TODO : Make the filename a VARIABLE
        # src_file = input("Enter .wav File PSK31 : ")
        src = blocks.wavfile_source(src_file, False)

        # Raw float data output file.
        # TODO : To make the raw file also a variable, for psk31decoder2.py to run
        dst = blocks.file_sink(1, "./output.raw")

        # Delay line. This delays the signal by 32ms
        dl = blocks.delay(gr.sizeof_float, int(round(sample_rate/31.25)))

        # Multiplier
        # Multiplying the source and the delayed version will give us
        # a negative output if there was a phase reversal and a positive output
        # if there was no phase reversal
        mul = blocks.multiply_ff(1)

        # Low Pass Filter. This leaves us with the envelope of the signal
        lpf_taps = filter.firdes.low_pass(
            5.0,
            sample_rate,
            15,
            600,
            filter.firdes.WIN_HAMMING)
        lpf = filter.fir_filter_fff(1, lpf_taps)

        # Binary Slicer (comparator)
        slc = digital.binary_slicer_fb()

        # Connect the blocks.
        self.connect(src, dl)
        self.connect(src, (mul, 0))
        self.connect(dl,  (mul, 1))
        self.connect(mul, lpf)
        self.connect(lpf, slc)
        self.connect(slc, dst)
Exemple #30
0
    def __init__(self):
        gr.top_block.__init__(self)

        parser = ArgumentParser()
        parser.add_argument("-I", "--audio-input", default="",
                          help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_argument("-O", "--audio-output", default="",
                          help="pcm output device name.  E.g., hw:0,0 or /dev/dsp")
        parser.add_argument("-r", "--sample-rate", type=eng_float, default=8000,
                          help="set sample rate to RATE (%(default)r)")
        args = parser.parse_args()
        sample_rate = int(args.sample_rate)
        src = audio.source (sample_rate, args.audio_input)
        dst = audio.sink (sample_rate, args.audio_output)

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

        self.connect(src, (multiply, 0))
        self.connect(vsource, (multiply, 1))
        self.connect(multiply, dst)
Exemple #31
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 = blocks.multiply_const_ff( 1 )
        self.sqr   = blocks.multiply_ff( )
        self.int0  = filter.iir_filter_ffd( [.004, 0], [0, .999] )
        self.offs  = blocks.add_const_ff( -30 )
        self.gain  = blocks.multiply_const_ff( 70 )
        self.log   = blocks.nlog10_ff( 10, 1 )
        self.agc   = blocks.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)
    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 = blocks.multiply_const_ff(1)
        self.sqr = blocks.multiply_ff()
        self.int0 = filter.iir_filter_ffd([.004, 0], [0, .999])
        self.offs = blocks.add_const_ff(-30)
        self.gain = blocks.multiply_const_ff(70)
        self.log = blocks.nlog10_ff(10, 1)
        self.agc = blocks.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)
Exemple #33
0
    def __init__(self, options):
	grc_wxgui.top_block_gui.__init__(self, title="DSSDR")

	self.initialized = False
	self.stopped = False

	self.options = copy.copy(options)
	self._constellation = digital.constellation_bpsk()
	self._excess_bw = options.excess_bw
	self._phase_bw = options.phase_bw
	self._freq_bw = options.freq_bw
	self._timing_bw = options.timing_bw
	self._if_freq = options.if_freq
	self._timing_max_dev= 1.5
	self._demod_class = digital.bpsk_demod  # the demodulator_class we're using
	self._chbw_factor = options.chbw_factor # channel filter bandwidth factor
	self._samples_per_second = 2e6
	self._nav_samples_per_second = 16e6
	self._down_decim = 1
	self._down_samples_per_second = self._scope_sample_rate = self._samples_per_second/self._down_decim
	self._up_samples_per_second = 1e6
	self._asm_threshold = 0
	self._access_code = None
	self._tm_packet_id = 4
	self._timestamp_id = 5
	self._down_bitrate = options.bitrate
	self._up_bitrate = options.up_bitrate
	self._up_samples_per_symbol = self._up_samples_per_second/self._up_bitrate
	self._samples_per_symbol = self._samples_per_second/self._down_decim/self._down_bitrate
	self._down_sub_freq = options.down_sub_freq
	self._up_sub_freq = 25e3
	self._tm_len = 8920
	self._up_tm_len = 8920
	self._coding_method = options.coding_method
	self._up_coding_method = 'None'
	self._up_subcarrier = 'Square'
	self._rs_i = 1
	self._ccsds_channel = 38
	self._uhd_carrier_offset = 10e3
	self._turn_div = 749
	self._turn_mult = 880
	self._modulation_index = 'pi/3'
	self._up_modulation_index = 1.047
	self._max_carrier_offset = 0.1
	self._dssdr_mixer_freq = options.rf_freq
	self._up_coding_rate = '1'
	self._down_coding_rate = '1'
	self._down_conv_en = "False"
	self._down_randomizer_en = options.down_randomizer_en
	self._down_manchester_en = options.down_manchester_en
	self._up_conv_en = "False"
	self._up_idle_sequence = "\\x55"
	self._down_default_gain = 64
	self._up_default_gain = 44
	self._up_en = True

        if self._access_code is None:
            self._access_code = packet_utils.default_access_code

	#Construct the lookup table for parameter-setting functions
	self.param_setters = {
		"DSSDR_CHANNEL": self.setChannel,
		"DSSDR_LO_FREQ": self.setLOFreq,
		"DSSDR_REF_FREQ": self.setRefFreq,
		"DSSDR_TURN_MULT": self.setTurnMult,
		"DSSDR_TURN_DIV": self.setTurnDiv,
		"DSSDR_UP_GAIN": self.setUpGain,
		"DSSDR_DOWN_GAIN": self.setDownGain,
		"DSSDR_UP_BITRATE": self.setUpBitrate,
		"DSSDR_DOWN_BITRATE": self.setDownBitrate,
		"DSSDR_DOWN_SAMPLE_RATE": self.setSampRate,
		"DSSDR_UP_SUB_FREQ": self.setUpSubFreq,
		"DSSDR_DOWN_SUB_FREQ": self.setDownSubFreq,
		"DSSDR_DOPPLER_REPORT": self.dopplerReport,
		"DSSDR_PN_RANGE": self.rangePN,
		"DSSDR_SEQUENTIAL_RANGE": self.rangeSequential,
		"DSSDR_DOWN_CODING_METHOD": self.setDownCodingMethod,
		"DSSDR_UP_CODING_METHOD": self.setUpCodingMethod,
		"DSSDR_DOWN_TM_LEN": self.setTMLen,
		"DSSDR_UP_TM_LEN": self.setUpTMLen,
		"DSSDR_DOWN_MOD_IDX": self.setDownModulationIndex,
		"DSSDR_UP_MOD_IDX": self.setUpModulationIndex,
		"DSSDR_DOWN_CONV_EN": self.setDownConvEn,
		"DSSDR_UP_CONV_EN": self.setUpConvEn,
		"DSSDR_ASM_TOL": self.setASMThreshold,
		"DSSDR_UP_SWEEP": self.freqSweep,
		"DSSDR_UP_IDLE": self.setUpIdleSequence,
		"DSSDR_UP_EN": self.setUpEn,
		"DSSDR_SYNC_TIME": self.syncSDRTime,
		"DSSDR_UP_SWEEP": self.freqSweep,
		"DSSDR_DOWN_ACQUIRE": self.acquireCarrier,
		"DSSDR_INPUT_SELECT": self.setPanelSelect,
		"DSSDR_REF_SELECT": self.setRefSelect,
		"DSSDR_PPS_SELECT": self.setPPSSelect
	}

	#TODO:Add status fields for things like DSSDR_REF_LOCK

	self._dssdr_channels = {
		3: [7149597994, 8400061729],
		4: [7150753857, 8401419752],
		5: [7151909723, 8402777779],
		6: [7153065586, 8404135802],
		7: [7154221449, 8405493825],
		8: [7155377316, 8406851853],
		9: [7156533179, 8408209877],
		10: [7157689045, 8409567903],
		11: [7158844908, 8410925927],
		12: [7160000771, 8412283950],
		13: [7161156637, 8413641977],
		14: [7162312500, 8415000000],
		15: [7163468363, 8416358023],
		16: [7164624229, 8417716050],
		17: [7165780092, 8419074073],
		18: [7166935955, 8420432097],
		19: [7168091821, 8421790123],
		20: [7169247684, 8423148147],
		21: [7170403551, 8424506175],
		22: [7171559414, 8425864198],
		23: [7172715277, 8427222221],
		24: [7173871143, 8428580248],
		25: [7175027006, 8429938271],
		26: [7176182869, 8431296295],
		27: [7177338735, 8432654321],
		28: [7178494598, 8434012345],
		29: [7179650464, 8435370372],
		30: [7180806327, 8436728395],
		31: [7181962190, 8438086418],
		32: [7183118057, 8439444446],
		33: [7184273920, 8440802469],
		34: [7185429783, 8442160493],
		35: [7186585649, 8443518520],
		36: [7187741512, 8444876543],
		37: [7188897378, 8446234570],
		38: [7190000000, 8450000000],
	}

	#FLOWGRAPH STUFF
	if options.test == True:
		self.u = blks2.tcp_source(
			itemsize=gr.sizeof_gr_complex*1,
			addr="",
			port=12905,
			server=True
		)
	elif options.fromfile == True:
		self.u2 = blocks.file_meta_source("iq_in.dat")
		self.u = blocks.throttle(gr.sizeof_gr_complex*1, self._samples_per_second)
	elif options.frombitlog == True:
		self.u3 = blocks.file_source(gr.sizeof_char, "bitstream_recording.in", True)
		self.u2 = blocks.uchar_to_float()
		self.u1 = blocks.throttle(gr.sizeof_float*1, self._down_bitrate)
		self.u = blocks.add_const_ff(-0.5)
	else:
		self.u = uhd.usrp_source(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
		self.u.set_clock_source("external")
		self.u.set_time_source("external")
		self.u.set_samp_rate(self._samples_per_second)
		self.u.set_antenna("RX2")
		self.u.set_gain(self._down_default_gain)

		self.frontend = dfi.dssdrFrontendInterface(self.u)

	if options.debug_pps == True:
		self.debug_pps = blocks.tag_debug(gr.sizeof_gr_complex, "debug-pps", "rx_time")

	if options.tofile == True:
		self.u_tx = blocks.file_meta_sink(gr.sizeof_gr_complex, "iq_out.dat", self._up_samples_per_second)
	elif options.tonull == True:
		self.u_tx = blocks.null_sink(gr.sizeof_gr_complex)
	else:
		self.u_tx = uhd.usrp_sink(device_addr=options.args, stream_args=uhd.stream_args('fc32'))
		self.u_tx.set_clock_source("external")
		self.u_tx.set_time_source("external")
		self.u_tx.set_samp_rate(self._up_samples_per_second)
		self.u_tx.set_antenna("TX/RX")
		self.u_tx.set_gain(self._up_default_gain)

	#GUI STUFF
	if options.graphics == True:
		self.nb0 = wx.Notebook(self.GetWin(), style=wx.NB_TOP)
		self.nb0.AddPage(grc_wxgui.Panel(self.nb0), "RX")
		self.nb0.AddPage(grc_wxgui.Panel(self.nb0), "TX")
		self.nb0.AddPage(grc_wxgui.Panel(self.nb0), "Nav")
		self.Add(self.nb0)
		self.constellation_scope = scopesink2.scope_sink_c(
			self.nb0.GetPage(0).GetWin(),
			title="Scope Plot",
			sample_rate=self._scope_sample_rate,
			v_scale=0,
			v_offset=0,
			t_scale=0,
			ac_couple=False,
			xy_mode=True,
			num_inputs=1,
			trig_mode=wxgui.TRIG_MODE_AUTO,
			y_axis_label="Counts",
		)
	        self.nb0.GetPage(0).Add(self.constellation_scope.win)
		#self.constellation_scope.win.set_marker('plus')
		self._scope_is_fft = False
		self.time_scope = scopesink2.scope_sink_f(
			self.nb0.GetPage(0).GetWin(),
			title="Scope Plot",
			sample_rate=self._scope_sample_rate,
			v_scale=0,
			v_offset=0,
			t_scale=.005,
			ac_couple=False,
			xy_mode=False,
			num_inputs=1,
			trig_mode=wxgui.TRIG_MODE_AUTO,
			y_axis_label="Counts",
		)
		self.nb0.GetPage(0).Add(self.time_scope.win)
		self.nb0.GetPage(0).GetWin()._box.Hide(self.time_scope.win)
		self.fft_scope = fftsink2.fft_sink_c(
			self.nb0.GetPage(0).GetWin(),
			baseband_freq=0,
			y_per_div=10,
			y_divs=10,
			ref_level=0,
			ref_scale=2.0,
			sample_rate=self._scope_sample_rate,
			fft_size=1024,
		 	fft_rate=15,
			average=False,
			avg_alpha=None,
			title="FFT Plot",
			peak_hold=False,
		)
		self.nb0.GetPage(0).Add(self.fft_scope.win)
		self.nb0.GetPage(0).GetWin()._box.Hide(self.fft_scope.win)
	
		self.row1_sizer = wx.BoxSizer(wx.HORIZONTAL)
		self.recording_onoff_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='Off',
			callback=self.setRecording,
			label="IQ Recording",
			choices=['Off','On'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.front_panel_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='RF',
			callback=self.setPanelSelect,
			label="Input Select",
			choices=['RF','IF'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.ref_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='Internal',
			callback=self.setRefSelect,
			label="Ref Select",
			choices=['Internal','External'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.pps_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='Internal',
			callback=self.setPPSSelect,
			label="PPS Select",
			choices=['Internal','External'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)

		self.sync_button = forms.button(
			parent=self.nb0.GetPage(0).GetWin(),
			value='Sync to PPS',
			callback=self.syncSDRTime,
			choices=['Sync to PPS'],
			style=wx.RA_HORIZONTAL,
		)
		self.ref_locked_text = forms.static_text(
			parent=self.nb0.GetPage(0).GetWin(),
			value="",
			callback=self.setRefLocked,
			label="",
			converter=forms.str_converter(),
		)
		self.row1_sizer.Add(self.recording_onoff_chooser, flag=wx.ALIGN_CENTER)
		self.row1_sizer.Add(self.front_panel_chooser, flag=wx.ALIGN_CENTER)
		self.row1_sizer.Add(self.ref_chooser, flag=wx.ALIGN_CENTER)
		self.row1_sizer.Add(self.pps_chooser, flag=wx.ALIGN_CENTER)
		self.row1_sizer.Add(self.sync_button, flag=wx.ALIGN_CENTER)
		self.row1_sizer.Add(self.ref_locked_text, flag=wx.ALIGN_CENTER)
		self.nb0.GetPage(0).Add(self.row1_sizer)
		self.complex_scope_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='Constellation',
			callback=self.setComplexScopeStyle,
			label="Complex Scope",
			choices=['Constellation','FFT'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(0).Add(self.complex_scope_chooser)
		self.scope_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value='USRP',
			callback=self.setScopePoint,
			label="Scope Probe Point",
			choices=['USRP','Carrier Tracking','Sub-Carrier Costas','Sub-Carrier Sync','Data Sync'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(0).Add(self.scope_chooser)
		self._bitrate_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._down_bitrate,
			callback=self.setDownBitrate,
			label="Symbol Rate",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(0).Add(self._bitrate_text_box)
		self._samprate_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._samples_per_second,
			callback=self.setSampRate,
			label="Sampling Rate",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(0).Add(self._samprate_text_box)
		self._subcfreq_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._down_sub_freq,
			callback=self.setDownSubFreq,
			label="Downlink Subcarrier Frequency",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(0).Add(self._subcfreq_text_box)
		self._mod_index_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._modulation_index,
			callback=self.setDownModulationIndex,
			label="Modulation Index",
			choices=['pi/2', 'pi/3'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(0).Add(self._mod_index_chooser)
		self._pktlen_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._tm_len,
			callback=self.setTMLen,
			label="Downlink Packet Length (bits)",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(0).Add(self._pktlen_text_box)
		self._coding_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._coding_method,
			callback=self.setDownCodingMethod,
			label="Coding",
			choices=['None', 'RS', 'Turbo 1/2', 'Turbo 1/3', 'Turbo 1/4', 'Turbo 1/6'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(0).Add(self._coding_chooser)
		self._down_conv_check_box = forms.check_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._down_conv_en,
			callback=self.setDownConvEn,
			label="Convolutional Decode",
			true="True",
			false="False",
		)
		self.nb0.GetPage(0).Add(self._down_conv_check_box)
		self._down_randomizer_check_box = forms.check_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._down_randomizer_en,
			callback=self.setDownRandomizerEn,
			label="De-randomizer",
			true=True,
			false=False,
		)
		self.nb0.GetPage(0).Add(self._down_randomizer_check_box)
		self._down_manchester_check_box = forms.check_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._down_manchester_en,
			callback=self.setDownManchesterEn,
			label="Manchester Decode",
			true=True,
			false=False,
		)
		self.nb0.GetPage(0).Add(self._down_manchester_check_box)
		self._pktlen_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._asm_threshold,
			callback=self.setASMThreshold,
			label="ASM Error Tolerance (bits)",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(0).Add(self._pktlen_text_box)
		self._coding_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._rs_i,
			callback=self.setRSI,
			label="Reed-Solomon Interleaving Depth",
			choices=[1,5],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(0).Add(self._coding_chooser)
		self._ccsds_chan_text_box = forms.text_box(
			parent=self.nb0.GetPage(0).GetWin(),
			value=self._ccsds_channel,
			callback=self.setChannel,
			label="CCSDS Channel",
			converter=forms.int_converter(),
		)
		self.nb0.GetPage(0).Add(self._ccsds_chan_text_box)
		self.setChannel(self._ccsds_channel)
	
		if options.test == True or options.fromfile == True or options.frombitlog == True:
			glow = 0.0
			ghigh = 1.0
			cur_g = 0.5
		else:
			g = self.u.get_gain_range()
			cur_g = self._down_default_gain
		
			# some configurations don't have gain control
			if g.stop() <= g.start():
				glow = 0.0
				ghigh = 1.0
		
			else:
				glow = g.start()
				ghigh = g.stop()
		
		self._uhd_gain_slider = wx.BoxSizer(wx.HORIZONTAL)
		form.slider_field(
			parent=self.nb0.GetPage(0).GetWin(),
			sizer=self._uhd_gain_slider,
			label="USRP RX Gain",
			weight=3,
			min=int(glow), 
			max=int(ghigh),
			value=cur_g,
			callback=self.setDownGain
		)
		self.nb0.GetPage(0).Add(self._uhd_gain_slider)

		#TX chain GUI components
		if options.test == True or options.tofile == True or options.tonull == True:
			gtxlow = 0.0
			gtxhigh = 1.0
			cur_gtx = 0.5
		else:
			gtx = self.u_tx.get_gain_range()
			cur_gtx = self._up_default_gain
		
			# some configurations don't have gain control
			if gtx.stop() <= gtx.start():
				gtxlow = 0.0
				gtxhigh = 1.0
		
			else:
				gtxlow = gtx.start()
				gtxhigh = gtx.stop()

		self._up_en_chooser = forms.check_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value='True',
			callback=self.setUpEn,
			label="TX Enable",
			true='True',
			false='False',
		)
		self.nb0.GetPage(1).Add(self._up_en_chooser)

		self._uhd_tx_gain_slider = wx.BoxSizer(wx.HORIZONTAL)
		form.slider_field(
			parent=self.nb0.GetPage(1).GetWin(),
			sizer=self._uhd_tx_gain_slider,
			label="USRP TX Gain",
			weight=3,
			min=int(gtxlow), 
			max=int(gtxhigh),
			value=cur_gtx,
			callback=self.setUpGain
		)
		self.nb0.GetPage(1).Add(self._uhd_tx_gain_slider)
		self._subcfreq_up_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_sub_freq,
			callback=self.setUpSubFreq,
			label="Uplink Subcarrier Frequency",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(1).Add(self._subcfreq_up_text_box)
		self._up_bitrate_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_bitrate,
			callback=self.setUpBitrate,
			label="Uplink Bitrate",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(1).Add(self._up_bitrate_text_box)
		self._up_data_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value="1234ABCD",
			callback=self.txData,
			label="TX Data",
			converter=forms.str_converter(),
		)
		self.nb0.GetPage(1).Add(self._up_data_text_box)
		self._up_mod_index_chooser = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_modulation_index,
			callback=self.setUpModulationIndex,
			label="Uplink Modulation Index",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(1).Add(self._up_mod_index_chooser)
		self._up_coding_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_coding_method,
			callback=self.setUpCodingMethod,
			label="Coding",
			choices=['None', 'RS'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(1).Add(self._up_coding_chooser)
		self._subcarrier_chooser = forms.radio_buttons(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_subcarrier,
			callback=self.setUpSubcarrier,
			label="Subcarrier Type",
			choices=['Square','Sine'],
			labels=[],
			style=wx.RA_HORIZONTAL,
		)
		self.nb0.GetPage(1).Add(self._subcarrier_chooser)
		self._up_conv_check_box = forms.check_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_conv_en,
			callback=self.setUpConvEn,
			label="Convolutional Encode",
			true="True",
			false="False",
		)
		self.nb0.GetPage(1).Add(self._up_conv_check_box)
		self._up_pktlen_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_tm_len,
			callback=self.setUpTMLen,
			label="Uplink Packet Length (bits)",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(1).Add(self._up_pktlen_text_box)
		self._uhd_offset_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._uhd_carrier_offset,
			callback=self.setUHDCarrierOffset,
			label="USRP Offset Frequency (Hz)",
			converter=forms.float_converter(),
		)
		self.nb0.GetPage(1).Add(self._uhd_offset_text_box)
		self._sweep_gen_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value="rf2_1",
			callback=self.freqSweep,
			label="Frequency Sweep Profile",
			converter=forms.str_converter(),
		)
		self.nb0.GetPage(1).Add(self._sweep_gen_text_box)
		self._idle_sequence_text_box = forms.text_box(
			parent=self.nb0.GetPage(1).GetWin(),
			value=self._up_idle_sequence,
			callback=self.setUpIdleSequence,
			label="Uplink Idle Sequence",
			converter=forms.str_converter(),
		)
		self.nb0.GetPage(1).Add(self._idle_sequence_text_box)
		self._pn_ranging_text_box = forms.text_box(
			parent=self.nb0.GetPage(2).GetWin(),
			value="",
			callback=self.rangePN,
			label="Queue PN Ranging",
			converter=forms.str_converter(),
		)
		self.nb0.GetPage(2).Add(self._pn_ranging_text_box)
		self._sequential_ranging_text_box = forms.text_box(
			parent=self.nb0.GetPage(2).GetWin(),
			value="",
			callback=self.rangeSequential,
			label="Queue Sequential Ranging",
			converter=forms.str_converter(),
		)
		self.nb0.GetPage(2).Add(self._sequential_ranging_text_box)
		self.row2_sizer = wx.BoxSizer(wx.HORIZONTAL)
		self.freq_acq_button = forms.button(
			parent=self.nb0.GetPage(2).GetWin(),
			value='Acquire Carrier Offset',
			callback=self.acquireCarrier,
			choices=['Acquire Carrier Offset'],
			style=wx.RA_HORIZONTAL,
		)
		self.carrier_offset_text = forms.static_text(
			parent=self.nb0.GetPage(2).GetWin(),
			value="",
			label="",
			converter=forms.str_converter(),
		)
		self.row2_sizer.Add(self.freq_acq_button, flag=wx.ALIGN_CENTER)
		self.row2_sizer.Add(self.carrier_offset_text, flag=wx.ALIGN_CENTER)
		self.nb0.GetPage(2).Add(self.row2_sizer)


	self.file_sink = blocks.file_meta_sink(gr.sizeof_gr_complex, "iq_recording.dat", self._samples_per_second)
	self.file_sink.close()
	self.iq_recording_ctr = 0

	# Selection logic to switch between recording and normal flowgraph routes
	# NOTE: u_valve logic is implemented backwards in GNURadio....
	#self.u_valve = blks2.valve(
	#	item_size=gr.sizeof_gr_complex,
	#	open=False
	#)

	# Temporary code used to verify coherent turnaround
	self.turnaround_mixer = blocks.multiply_cc()
	self.turnaround_mixer_source = analog.sig_source_c(self._down_samples_per_second, analog.GR_SIN_WAVE, -25e3, 1.0)
	self.turnaround_iir = filter.single_pole_iir_filter_cc(0.0001)
	self.turnaround_null = blocks.null_sink(gr.sizeof_float)

	# PLL and associated carrier for tracking carrier frequency if residual carrier is used
	self.carrier_tracking = sdrp.pll_freq_acq_cc(math.pi/2000, math.pi, -math.pi, int(options.acq_samples))
	self.imag_to_float = blocks.complex_to_imag()

	#Suppressed carrier requires costas after subcarrier mixer
	self.subcarrier_costas = digital.costas_loop_cc(0.001, 2)
	self.real_to_float = blocks.complex_to_real()

	#Square wave subcarrier sync
	self.subcarrier_sync = sdrp.square_sub_tracker_ff(0.001, 2*self._down_sub_freq/self._down_samples_per_second*1.0001, 2*self._down_sub_freq/self._down_samples_per_second*0.9999)

	#Data sync
	self.data_sync = sdrp.square_data_tracker_ff(0.001, self._down_bitrate/self._down_samples_per_second*1.001, self._down_bitrate/self._down_samples_per_second*0.999)

	#Data framing
	self.soft_correlator = sdrp.correlate_soft_access_tag_ff(conv_packed_binary_string_to_1_0_string('\x1A\xCF\xFC\x1D'), self._asm_threshold, "asm_corr")
	self.conv_decoder = sdrp.ccsds_tm_conv_decoder("asm_corr")
	self.de_randomizer = sdrp.ccsds_tm_derandomizer("asm_corr")
	self.tm_framer = sdrp.ccsds_tm_framer(self._tm_packet_id, self._timestamp_id, "asm_corr", "rx_time", self._down_bitrate)
	self.tm_framer.setFrameLength(self._tm_len)

	self._current_scope_block = None
	self._current_scoped_block = self.u
	self._current_scoped_block_port = 0

	self._recording = 'Off'

	#TX path in flowgraph
	self.pkt_gen_msgq = gr.msg_queue(10)
        self.pkt_gen = sdrp.ccsds_tm_tx(self._tm_packet_id, self._timestamp_id, 1.0, 16, self.pkt_gen_msgq)
	self.conj = blocks.conjugate_cc()

	#Sweep generator for transponder lock
	self.sweep_gen = sdrp.sweep_generator_cc(self._up_samples_per_second)

	# DSSDR subcarrier mixer (either 25 kHz or 0 kHz depending on baud rate)
	self.up_subcarrier_mixer = blocks.multiply_ff()
	self.subcarrier_mixer_source_tx = analog.sig_source_f(self._up_samples_per_second, analog.GR_SQR_WAVE, 25e3, 2.0, -1.0)
	self.phase_mod_tx = analog.phase_modulator_fc(self._up_modulation_index)
	self.tx_attenuator = blocks.multiply_const_cc((0.1+0.0j))

	#Add in bit recorder if needed
	if self.options.bitlog:
		self.bit_slicer = digital.binary_slicer_fb()
		self.bit_recorder = blocks.file_sink(1, "bitstream_recording.out")


	self.setDownCodingMethod(self._coding_method)
	self.setUpCodingMethod("None")
	self.setUpSubcarrier(self._up_subcarrier)
	self.setDownBitrate(self._down_bitrate)
	self.setUpBitrate(self._up_bitrate)
	self.setDownModulationIndex(self._modulation_index)
	self.setUpModulationIndex(self._up_modulation_index)
	self.setDownConvEn(self._down_conv_en)
	self.setUpConvEn(self._up_conv_en)
	self.setUpIdleSequence(self._up_idle_sequence)
	self.setDownRandomizerEn(self._down_randomizer_en)
	self.setDownManchesterEn(self._down_manchester_en)

	#Connection to outside world
	self.socket_pdu = blocks.socket_pdu("TCP_SERVER", "127.0.0.1", "12902", 10000)
	self.sdrp_interpreter = sdrp.sdrp_packet_interpreter()
	self.msg_connect(self.tm_framer, "tm_frame_out", self.sdrp_interpreter, "sdrp_pdu_in")
	self.msg_connect(self.sdrp_interpreter, "socket_pdu_out", self.socket_pdu, "pdus")
	self.msg_connect(self.socket_pdu, "pdus", self.sdrp_interpreter, "socket_pdu_in")
	self.msg_connect(self.sdrp_interpreter,"sdrp_pdu_out", self.pkt_gen, "ccsds_tx_msg_in")

	if options.test == False and options.fromfile == False and options.frombitlog == False:
		_threading.Thread(target=self.watchRef).start()

	self.initialized = True
	print "DS-SDR Initialized"
    def __init__(self, fft_length, cp_length, kstime, overrate, logging=True):
        """
        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 = blocks.add_const_cc(0)

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

        # PN Sync
        self.corrmag = blocks.complex_to_mag_squared()
        self.delay = blocks.delay(gr.sizeof_gr_complex,
                                  fft_length * overrate / 2)

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

        #self.sub = blocks.add_const_ff(-1)
        self.pk_detect = blocks.peak_detector_fb(0.40, 0.25,
                                                 fft_length * overrate,
                                                 0.00000000000)

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

        #self.inputmag = blocks.complex_to_mag_squared()
        #self.normalize = blocks.divide_ff()
        #self.inputmovingsum = filter.fir_filter_fff(1, [1.0] * (fft_length//2))
        self.square = blocks.multiply_ff()

        #self.connect(self.input,self.inputmag,self.inputmovingsum)
        self.connect(self.corrmag, (self.square, 0))
        self.connect(self.corrmag, (self.square, 1))
        self.dsquare = blocks.multiply_ff()
        self.connect(self.square, (self.dsquare, 0))
        self.connect(self.square, (self.dsquare, 1))
        self.connect(self.dsquare, self.pk_detect)

        # Create a moving sum filter for the corr output
        self.moving_sum_filter = filter.fir_filter_ccf(
            1, [1.0] * (fft_length * overrate // 2))

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

        self.sample_and_hold = blocks.sample_and_hold_ff()

        # 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.angle)
        self.connect(self.angle, (self.sample_and_hold, 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.dsquare,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-dsquare.dat"))
            self.connect(
                self.corrmag,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-corrmag.dat"))
            self.connect(
                self.angle,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                blocks.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_pn-input_c.dat"))
Exemple #35
0
    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 = blocks.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 = blocks.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

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

        moving_sum_taps = [rho / 2 for i in range(cp_length)]
        self.moving_sum_filter = filter.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 = blocks.conjugate_cc();
        self.mixer = blocks.multiply_cc();

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = filter.fir_filter_ccf(1,movingsum2_taps)

        # Correlator data handler
        self.c2mag = blocks.complex_to_mag()
        self.angle = blocks.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 = blocks.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 = blocks.float_to_complex()
        self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005)
        self.sample_and_hold = blocks.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 = filter.fir_filter_ccc(1, kstime)
        self.corrmag = blocks.complex_to_mag_squared()
        self.div = blocks.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 = blocks.threshold_ff(self.threshold_factor, self.threshold_factor, 0)
        self.f2b = blocks.float_to_char()
        self.b2f = blocks.char_to_float()
        self.mul = blocks.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, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat"))
            self.connect(self.diff, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
            self.connect(self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
            self.connect(self.corrmag, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-corrmag_f.dat"))
            self.connect(self.kscorr, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-kscorr_c.dat"))
            self.connect(self.div, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat"))
            self.connect(self.mul, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat"))
            self.connect(self.slice, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat"))
            self.connect(self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
            if use_dpll:
                self.connect(self.dpll, blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))

            self.connect(self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
Exemple #36
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 = blocks.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 = blocks.stream_to_streams(gr.sizeof_short, 2)
            s2f1 = blocks.short_to_float()
            s2f2 = blocks.short_to_float()
            src_f2c = blocks.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 = blocks.file_sink(gr.sizeof_short, options.radio_file)
            self.tb.connect(self.src, radio_file)

        # 2nd DDC
        xlate_taps = filter.firdes.low_pass(1.0, input_rate, 16e3, 4e3, filter.firdes.WIN_HAMMING)
        self.xlate = filter.freq_xlating_fir_filter_ccf(fir_decim, xlate_taps, self.tune_offset, input_rate)

        # Complex Audio filter
        audio_coeffs = filter.firdes.complex_band_pass(
            1.0,  # gain
            self.af_sample_rate,  # sample rate
            -3000,  # low cutoff
            0,  # high cutoff
            100,  # transition
            filter.firdes.WIN_HAMMING,
        )  # window
        self.slider_fcutoff_hi.SetValue(0)
        self.slider_fcutoff_lo.SetValue(-3000)

        self.audio_filter = filter.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 = blocks.complex_to_float()

        # AM branch
        self.sel_am = blocks.multiply_const_cc(0)
        # the following frequencies turn out to be in radians/sample
        # analog.pll_refout_cc(alpha,beta,min_freq,max_freq)
        # suggested alpha = X, beta = .25 * X * X
        pll = analog.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 = blocks.multiply_const_cc(complex(10, 0))
        am_det = blocks.multiply_cc()
        # these are for converting +7.5kHz to -7.5kHz
        # for some reason blocks.conjugate_cc() adds noise ??
        c2f2 = blocks.complex_to_float()
        c2f3 = blocks.complex_to_float()
        f2c = blocks.float_to_complex()
        phaser1 = blocks.multiply_const_ff(1)
        phaser2 = blocks.multiply_const_ff(-1)

        # filter for pll generated carrier
        pll_carrier_coeffs = filter.firdes.complex_band_pass(
            2.0,  # gain
            self.af_sample_rate,  # sample rate
            7400,  # low cutoff
            7600,  # high cutoff
            100,  # transition
            filter.firdes.WIN_HAMMING,
        )  # window

        self.pll_carrier_filter = filter.fir_filter_ccc(1, pll_carrier_coeffs)

        self.sel_sb = blocks.multiply_const_ff(1)
        combine = blocks.add_ff()

        # AGC
        sqr1 = blocks.multiply_ff()
        intr = filter.iir_filter_ffd([0.004, 0], [0, 0.999])
        offset = blocks.add_const_ff(1)
        agc = blocks.divide_ff()

        self.scale = blocks.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 = blocks.file_sink(gr.sizeof_short, options.audio_file)
            sc1 = blocks.multiply_const_ff(64000)
            f2s1 = blocks.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)
Exemple #37
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.panel_10 = wx.Panel(self, -1)
        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("",
                          "--args",
                          type="string",
                          default="addr=''",
                          help="Arguments for UHD device, [default=%default]")
        parser.add_option("",
                          "--spec",
                          type="string",
                          default="A:0",
                          help="UHD device subdev spec, [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=256000,
            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")
        parser.add_option("",
                          "--audio-rate",
                          type="int",
                          default=32000,
                          help="audio output sample rate [default=%default]")

        (options, args) = parser.parse_args()

        self.usrp_center = options.ddc_freq
        self.input_rate = 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 = options.audio_rate
        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 / 250
        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(options.args,
                                       stream_args=uhd.stream_args('fc32'))
            self.src.set_samp_rate(input_rate)
            self.src.set_subdev_spec(options.spec)
            self.input_rate = input_rate = self.src.get_samp_rate()

            self.src.set_center_freq(self.usrp_center, 0)
            self.tune_offset = 0

            fir_decim = long(self.input_rate / self.af_sample_rate)
            rrate = self.af_sample_rate / (self.input_rate / float(fir_decim))

            print "Actual Input Rate: ", self.input_rate
            print "FIR DECIM: ", fir_decim
            print "Remaining resampling: ", rrate
            print "Sampling Rate at Audio Sink: ", (self.input_rate /
                                                    fir_decim) * rrate
            print "Request Rate at Audio Sink: ", self.af_sample_rate

        else:
            self.src = blocks.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 = blocks.stream_to_streams(gr.sizeof_short, 2)
            s2f1 = blocks.short_to_float()
            s2f2 = blocks.short_to_float()
            src_f2c = blocks.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))

            fir_decim = long(self.input_rate / self.af_sample_rate)
            rrate = self.af_sample_rate / (self.input_rate / float(fir_decim))

            print "FIR DECIM: ", fir_decim
            print "Remaining resampling: ", rrate
            print "Sampling Rate at Audio Sink: ", (self.input_rate /
                                                    fir_decim) * rrate
            print "Request Rate at Audio Sink: ", self.af_sample_rate

        # save radio data to a file
        if SAVE_RADIO_TO_FILE:
            radio_file = blocks.file_sink(gr.sizeof_short, options.radio_file)
            self.tb.connect(self.src, radio_file)

        # 2nd DDC
        xlate_taps = filter.firdes.low_pass ( \
           1.0, input_rate, 16e3, 4e3, filter.firdes.WIN_HAMMING )
        self.xlate = filter.freq_xlating_fir_filter_ccf ( \
           fir_decim, xlate_taps, self.tune_offset, input_rate )

        nflts = 32
        audio_coeffs = filter.firdes.complex_band_pass(
            nflts,  # gain
            self.input_rate * nflts,  # sample rate
            -3000.0,  # low cutoff
            0.0,  # high cutoff
            100.0,  # transition
            filter.firdes.WIN_KAISER,
            7.0)  # window
        self.slider_fcutoff_hi.SetValue(0)
        self.slider_fcutoff_lo.SetValue(-3000)

        # Filter and resample based on actual radio's sample rate
        self.audio_filter = filter.pfb.arb_resampler_ccc(rrate, 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),
                                       baseband_freq=self.usrp_center)
        c2f = blocks.complex_to_float()

        # AM branch
        self.sel_am = blocks.multiply_const_cc(0)
        # the following frequencies turn out to be in radians/sample
        # analog.pll_refout_cc(alpha,beta,min_freq,max_freq)
        # suggested alpha = X, beta = .25 * X * X
        pll = analog.pll_refout_cc(
            .05, (2. * math.pi * 7.5e3 / self.af_sample_rate),
            (2. * math.pi * 6.5e3 / self.af_sample_rate))
        self.pll_carrier_scale = blocks.multiply_const_cc(complex(10, 0))
        am_det = blocks.multiply_cc()
        # these are for converting +7.5kHz to -7.5kHz
        # for some reason blocks.conjugate_cc() adds noise ??
        c2f2 = blocks.complex_to_float()
        c2f3 = blocks.complex_to_float()
        f2c = blocks.float_to_complex()
        phaser1 = blocks.multiply_const_ff(1)
        phaser2 = blocks.multiply_const_ff(-1)

        # filter for pll generated carrier
        pll_carrier_coeffs = filter.firdes.complex_band_pass(
            2.0,  # gain
            self.af_sample_rate,  # sample rate
            7400,  # low cutoff
            7600,  # high cutoff
            100,  # transition
            filter.firdes.WIN_HAMMING)  # window

        self.pll_carrier_filter = filter.fir_filter_ccc(1, pll_carrier_coeffs)

        self.sel_sb = blocks.multiply_const_ff(1)
        combine = blocks.add_ff()

        #AGC
        sqr1 = blocks.multiply_ff()
        intr = filter.iir_filter_ffd([.004, 0], [0, .999])
        offset = blocks.add_const_ff(1)
        agc = blocks.divide_ff()

        self.scale = blocks.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))

        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, blocks.null_sink(gr.sizeof_float))
        self.tb.connect(c2f3, dst)

        if SAVE_AUDIO_TO_FILE:
            f_out = blocks.file_sink(gr.sizeof_short, options.audio_file)
            sc1 = blocks.multiply_const_ff(64000)
            f2s1 = blocks.float_to_short()
            self.tb.connect(agc, sc1, f2s1, f_out)

        self.tb.start()

        # left click to re-tune
        self.fft.win.plotter.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_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_SPINCTRL(self, ID_SPIN_1, self.spin_tune)

        wx.EVT_MENU(self, ID_EXIT, self.TimeToQuit)
Exemple #38
0
def multiply_ff(N):
    op = blocks.multiply_ff()
    tb = helper(N, op, gr.sizeof_float, gr.sizeof_float, 2, 1)
    return tb
Exemple #39
0
    def __init__(self, demod_rate, audio_decimation, deemph_tau):
        """
        Hierarchical block for demodulating a broadcast FM signal.

        The input is the downconverted complex baseband signal (gr_complex).
        The output is two streams of the demodulated audio (float) 0=Left, 1=Right.

        Args:
            demod_rate: input sample rate of complex baseband input. (float)
            audio_decimation: how much to decimate demod_rate to get to audio. (integer)
            deemph_tau: deemphasis ime constant in seconds (75us in US, 50us in EUR). (float)
        """
        gr.hier_block2.__init__(self, "wfm_rcv_pll",
                                # Input signature
                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
                                gr.io_signature(2, 2, gr.sizeof_float))      # Output signature

        if audio_decimation != int(audio_decimation):
            raise ValueError("audio_decimation needs to be an integer")
        audio_decimation = int(audio_decimation)

        ##################################################
        # Variables
        ##################################################
        self.demod_rate = demod_rate
        self.deemph_tau = deemph_tau
        self.stereo_carrier_filter_coeffs = stereo_carrier_filter_coeffs = firdes.band_pass(
            -2.0, demod_rate, 37600, 38400, 400, fft.window.WIN_HAMMING, 6.76)
        self.pilot_carrier_filter_coeffs = pilot_carrier_filter_coeffs = firdes.complex_band_pass(
            1.0, demod_rate, 18980, 19020, 1500, fft.window.WIN_HAMMING, 6.76)
        self.deviation = deviation = 75000
        self.audio_filter_coeffs = audio_filter_coeffs = firdes.low_pass(
            1, demod_rate, 15000, 1500, fft.window.WIN_HAMMING, 6.76)
        self.audio_decim = audio_decim = audio_decimation
        self.audio_rate = audio_rate = demod_rate / audio_decim
        self.samp_delay = samp_delay = (len(
            pilot_carrier_filter_coeffs) - 1) // 2 + (len(stereo_carrier_filter_coeffs) - 1) // 2

        ##################################################
        # Blocks
        ##################################################
        self.pilot_carrier_bpf = filter.fir_filter_fcc(
            1, pilot_carrier_filter_coeffs)
        self.pilot_carrier_bpf.declare_sample_delay(0)
        self.stereo_carrier_bpf = filter.fft_filter_fff(
            1, stereo_carrier_filter_coeffs, 1)
        self.stereo_carrier_bpf.declare_sample_delay(0)
        self.stereo_audio_lpf = filter.fft_filter_fff(
            audio_decim, audio_filter_coeffs, 1)
        self.stereo_audio_lpf.declare_sample_delay(0)
        self.mono_audio_lpf = filter.fft_filter_fff(
            audio_decim, audio_filter_coeffs, 1)
        self.mono_audio_lpf.declare_sample_delay(0)
        self.blocks_stereo_multiply = blocks.multiply_ff(1)
        self.blocks_pilot_multiply = blocks.multiply_cc(1)
        self.blocks_complex_to_imag = blocks.complex_to_imag(1)
        self.blocks_right_sub = blocks.sub_ff(1)
        self.blocks_left_add = blocks.add_ff(1)
        self.analog_quadrature_demod_cf = analog.quadrature_demod_cf(
            demod_rate / (2 * math.pi * deviation))
        self.analog_pll_refout_cc = analog.pll_refout_cc(
            0.001, 2 * math.pi * 19200 / demod_rate, 2 * math.pi * 18800 / demod_rate)
        self.analog_right_fm_deemph = analog.fm_deemph(
            fs=audio_rate, tau=deemph_tau)
        self.analog_left_fm_deemph = analog.fm_deemph(
            fs=audio_rate, tau=deemph_tau)
        self.blocks_delay_0 = blocks.delay(gr.sizeof_float * 1, samp_delay)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.analog_left_fm_deemph, 0), (self, 0))
        self.connect((self.analog_right_fm_deemph, 0), (self, 1))
        self.connect((self.analog_pll_refout_cc, 0),
                     (self.blocks_pilot_multiply, 1))
        self.connect((self.analog_pll_refout_cc, 0),
                     (self.blocks_pilot_multiply, 0))
        self.connect((self.analog_quadrature_demod_cf, 0),
                     (self.blocks_delay_0, 0))
        self.connect((self.blocks_delay_0, 0),
                     (self.blocks_stereo_multiply, 0))
        self.connect((self.blocks_delay_0, 0), (self.mono_audio_lpf, 0))
        self.connect((self.analog_quadrature_demod_cf, 0),
                     (self.pilot_carrier_bpf, 0))
        self.connect((self.blocks_left_add, 0),
                     (self.analog_left_fm_deemph, 0))
        self.connect((self.blocks_right_sub, 0),
                     (self.analog_right_fm_deemph, 0))
        self.connect((self.blocks_complex_to_imag, 0),
                     (self.stereo_carrier_bpf, 0))
        self.connect((self.blocks_pilot_multiply, 0),
                     (self.blocks_complex_to_imag, 0))
        self.connect((self.blocks_stereo_multiply, 0),
                     (self.stereo_audio_lpf, 0))  # L - R path
        self.connect((self.mono_audio_lpf, 0), (self.blocks_left_add, 1))
        self.connect((self.mono_audio_lpf, 0), (self.blocks_right_sub, 0))
        self.connect((self.stereo_audio_lpf, 0), (self.blocks_left_add, 0))
        self.connect((self.stereo_audio_lpf, 0), (self.blocks_right_sub, 1))
        self.connect((self.stereo_carrier_bpf, 0),
                     (self.blocks_stereo_multiply, 1))
        self.connect((self.pilot_carrier_bpf, 0),
                     (self.analog_pll_refout_cc, 0))
        self.connect((self, 0), (self.analog_quadrature_demod_cf, 0))
Exemple #40
0
    def __init__(self, dab_params, rx_params, verbose=False, debug=False):
        """
		Hierarchical block for OFDM demodulation

		@param dab_params DAB parameter object (grdab.parameters.dab_parameters)
		@param rx_params RX parameter object (grdab.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_signature(1, 1, gr.sizeof_float * self.dp.num_carriers *
                                2))  # output signature
        else:
            gr.hier_block2.__init__(
                self,
                "ofdm_demod",
                gr.io_signature(1, 1, gr.sizeof_gr_complex),  # input signature
                gr.io_signature(1, 1, gr.sizeof_char * self.dp.num_carriers /
                                4))  # 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.input = blocks.multiply_const_cc(1.0)  # FIXME
        self.connect(self, self.input)

        # input filtering
        if self.rp.input_fft_filter:
            if verbose: print("--> RX filter enabled")
            lowpass_taps = filter.firdes_low_pass(
                1.0,  # gain
                dp.sample_rate,  # sampling rate
                rp.filt_bw,  # cutoff frequency
                rp.filt_tb,  # width of transition band
                filter.firdes.WIN_HAMMING)  # Hamming window
            self.fft_filter = filter.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 = grdab.detect_null(dp.ns_length, False)
            self.rate_estimator = grdab.estimate_sample_rate_bf(
                dp.sample_rate, dp.frame_length)
            self.rate_prober = blocks.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 = grdab.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 or self.rp.always_include_resample:
                if verbose: print("--> static sample rate correction enabled")
                self.resample = filter.mmse_resampler_cc(
                    0, self.rp.sample_rate_correction_factor)

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

        # ofdm symbol sampler
        self.sampler = grdab.ofdm_sampler(dp.fft_length, dp.cp_length,
                                          dp.symbols_per_frame, rp.cp_gap)

        # fft for symbol vectors
        self.fft = fft.fft_vcc(dp.fft_length, True, [], True)

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

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

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

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

        # frequency deinterleaving
        self.deinterleave = grdab.frequency_interleaver_vcc(
            dp.frequency_deinterleaving_sequence_array)

        # symbol demapping
        self.demapper = grdab.qpsk_demapper_vcb(dp.num_carriers)

        #
        # connect everything
        #

        if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1 or self.rp.always_include_resample:
            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, self.sampler, self.fft, self.cfs,
                     self.phase_diff, self.remove_pilot)
        if self.rp.equalize_magnitude:
            self.connect(self.remove_pilot, self.equalizer, self.deinterleave)
        else:
            self.connect(self.remove_pilot, self.deinterleave)
        if self.rp.softbits:
            if verbose: print("--> using soft bits")
            self.softbit_interleaver = grdab.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))

        # calculate an estimate of the SNR
        self.phase_var_decim = blocks.keep_one_in_n(
            gr.sizeof_gr_complex * self.dp.num_carriers,
            self.rp.phase_var_estimate_downsample)
        self.phase_var_arg = blocks.complex_to_arg(dp.num_carriers)
        self.phase_var_v2s = blocks.vector_to_stream(gr.sizeof_float,
                                                     dp.num_carriers)
        self.phase_var_mod = grdab.modulo_ff(pi / 2)
        self.phase_var_avg_mod = filter.iir_filter_ffd(
            [rp.phase_var_estimate_alpha],
            [0, 1 - rp.phase_var_estimate_alpha])
        self.phase_var_sub_avg = blocks.sub_ff()
        self.phase_var_sqr = blocks.multiply_ff()
        self.phase_var_avg = filter.iir_filter_ffd(
            [rp.phase_var_estimate_alpha],
            [0, 1 - rp.phase_var_estimate_alpha])
        self.probe_phase_var = blocks.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 = grdab.measure_processing_rate(
            gr.sizeof_gr_complex, 2000000)
        self.connect(self.input, self.measure_rate)

        # debugging
        if debug:
            self.connect(
                self.fft,
                blocks.file_sink(gr.sizeof_gr_complex * dp.fft_length,
                                 "debug/ofdm_after_fft.dat"))
            self.connect(
                (self.cfs, 0),
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/ofdm_after_cfs.dat"))
            self.connect(
                self.phase_diff,
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/ofdm_diff_phasor.dat"))
            self.connect(
                (self.remove_pilot, 0),
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/ofdm_pilot_removed.dat"))
            self.connect((self.remove_pilot, 1),
                         blocks.file_sink(gr.sizeof_char,
                                          "debug/ofdm_after_cfs_trigger.dat"))
            self.connect(
                self.deinterleave,
                blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                 "debug/ofdm_deinterleaved.dat"))
            if self.rp.equalize_magnitude:
                self.connect(
                    self.equalizer,
                    blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers,
                                     "debug/ofdm_equalizer.dat"))
            if self.rp.softbits:
                self.connect(
                    self.softbit_interleaver,
                    blocks.file_sink(gr.sizeof_float * dp.num_carriers * 2,
                                     "debug/softbits.dat"))
Exemple #41
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
        Synchronization 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 = blocks.add_const_cc(0)

        # PN Sync

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

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

        # Create a moving sum filter for the corr output
        self.moving_sum_filter = filter.fir_filter_ccf(1, [1.0] * (fft_length//2))

        # Create a moving sum filter for the input
        self.inputmag2 = blocks.complex_to_mag_squared()
        self.inputmovingsum = filter.fir_filter_fff(1, [1.0] * (fft_length//2))

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

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

        self.sample_and_hold = blocks.sample_and_hold_ff()

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

        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 = filter.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, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(self.normalize, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(self.angle, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(self.pk_detect, blocks.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(self.sample_and_hold, blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(self.input, blocks.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
Exemple #42
0
    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 = blocks.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 = blocks.delay(gr.sizeof_gr_complex, fft_length)
        self.connect(self.input, self.delay)

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

        moving_sum_taps = [rho / 2 for i in range(cp_length)]
        self.moving_sum_filter = filter.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 = blocks.conjugate_cc()
        self.mixer = blocks.multiply_cc()

        movingsum2_taps = [1.0 for i in range(cp_length)]
        self.movingsum2 = filter.fir_filter_ccf(1, movingsum2_taps)

        # Correlator data handler
        self.c2mag = blocks.complex_to_mag()
        self.angle = blocks.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 = blocks.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 = blocks.float_to_complex()
        self.pk_detect = blocks.peak_detector_fb(0.2, 0.25, 30, 0.0005)
        self.sample_and_hold = blocks.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 = filter.fir_filter_ccc(1, kstime)
        self.corrmag = blocks.complex_to_mag_squared()
        self.div = blocks.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 = blocks.threshold_ff(self.threshold_factor,
                                         self.threshold_factor, 0)
        self.f2b = blocks.float_to_char()
        self.b2f = blocks.char_to_float()
        self.mul = blocks.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,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-energy_f.dat"))
            self.connect(
                self.diff,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
            self.connect(
                self.angle,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_ml-epsilon_f.dat"))
            self.connect(
                self.corrmag,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_ml-corrmag_f.dat"))
            self.connect(
                self.kscorr,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_ml-kscorr_c.dat"))
            self.connect(
                self.div,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-div_f.dat"))
            self.connect(
                self.mul,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-mul_f.dat"))
            self.connect(
                self.slice,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_ml-slice_f.dat"))
            self.connect(
                self.pk_detect,
                blocks.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
            if use_dpll:
                self.connect(
                    self.dpll,
                    blocks.file_sink(gr.sizeof_char,
                                     "ofdm_sync_ml-dpll_b.dat"))

            self.connect(
                self.sample_and_hold,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_ml-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_ml-input_c.dat"))
Exemple #43
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.input = blocks.multiply_const_cc(1.0) # FIXME
		self.connect(self, self.input)
		
		# input filtering
		if self.rp.input_fft_filter: 
			if verbose: print "--> RX filter enabled"
			lowpass_taps = filter.firdes_low_pass(1.0,                     # gain
							  dp.sample_rate,          # sampling rate
							  rp.filt_bw,              # cutoff frequency
							  rp.filt_tb,              # width of transition band
							  filter.firdes.WIN_HAMMING)   # Hamming window
			self.fft_filter = filter.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 = dab.detect_null(dp.ns_length, False)
			self.rate_estimator = dab.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length)
			self.rate_prober = blocks.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.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 = dab.ofdm_sync_dab2(self.dp, self.rp, debug)

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

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

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

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

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

		# frequency deinterleaving
		self.deinterleave = dab.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array)
		
		# symbol demapping
		self.demapper = dab.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.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   = blocks.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample)
		self.phase_var_arg     = blocks.complex_to_arg(dp.num_carriers)
		self.phase_var_v2s     = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers)
		self.phase_var_mod     = dab.modulo_ff(pi/2)
		self.phase_var_avg_mod = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.phase_var_sub_avg = blocks.sub_ff()
		self.phase_var_sqr     = blocks.multiply_ff()
		self.phase_var_avg     = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) 
		self.probe_phase_var   = blocks.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.measure_processing_rate(gr.sizeof_gr_complex, 2000000) 
		self.connect(self.input, self.measure_rate)

		# debugging
		if debug:
			self.connect(self.fft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat"))
			self.connect((self.cfs,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat"))
			self.connect(self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat"))
			self.connect((self.remove_pilot,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat"))
			self.connect((self.remove_pilot,1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat"))
			self.connect(self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat"))
			if self.rp.equalize_magnitude:
				self.connect(self.equalizer, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat"))
			if self.rp.softbits:
				self.connect(self.softbit_interleaver, blocks.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
Exemple #44
0
    def connect_audio_stage(self, input_port):
        stereo_rate = self.demod_rate
        normalizer = TWO_PI / stereo_rate
        pilot_tone = 19000
        pilot_low = pilot_tone * 0.98
        pilot_high = pilot_tone * 1.02

        def make_audio_filter():
            return grfilter.fir_filter_fff(
                stereo_rate // self.__audio_int_rate,  # decimation
                firdes.low_pass(
                    1.0,
                    stereo_rate,
                    15000,
                    5000,
                    firdes.WIN_HAMMING))

        stereo_pilot_filter = grfilter.fir_filter_fcc(
            1,  # decimation
            firdes.complex_band_pass(
                1.0,
                stereo_rate,
                pilot_low,
                pilot_high,
                300))  # TODO magic number from gqrx
        stereo_pilot_pll = analog.pll_refout_cc(
            loop_bw=0.001,
            max_freq=normalizer * pilot_high,
            min_freq=normalizer * pilot_low)
        stereo_pilot_doubler = blocks.multiply_cc()
        stereo_pilot_out = blocks.complex_to_real()
        difference_channel_mixer = blocks.multiply_ff()
        difference_channel_filter = make_audio_filter()
        mono_channel_filter = make_audio_filter()
        mixL = blocks.add_ff(1)
        mixR = blocks.sub_ff(1)
        
        # connections
        self.connect(input_port, mono_channel_filter)
        if self.__decode_stereo:
            # stereo pilot tone tracker
            self.connect(
                input_port,
                stereo_pilot_filter,
                stereo_pilot_pll)
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 0))
            self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 1))
            self.connect(stereo_pilot_doubler, stereo_pilot_out)
        
            # pick out stereo left-right difference channel (at stereo_rate)
            self.connect(input_port, (difference_channel_mixer, 0))
            self.connect(stereo_pilot_out, (difference_channel_mixer, 1))
            self.connect(
                difference_channel_mixer,
                blocks.multiply_const_ff(6),  # TODO: Completely empirical fudge factor. This should not be necessary. I believe this is at least partly due to phase error in the pilot signal.
                difference_channel_filter)
        
            # recover left/right channels (at self.__audio_int_rate)
            self.connect(difference_channel_filter, (mixL, 1))
            self.connect(difference_channel_filter, (mixR, 1))
            self.connect(mono_channel_filter, (mixL, 0))
            self.connect(mono_channel_filter, (mixR, 0))
            resamplerL = self._make_resampler((mixL, 0), self.__audio_int_rate)
            resamplerR = self._make_resampler((mixR, 0), self.__audio_int_rate)
            deemphL = fm_emph.fm_deemph(self.__audio_int_rate, 75e-6)
            deemphR = fm_emph.fm_deemph(self.__audio_int_rate, 75e-6)
            self.connect(resamplerL, deemphL)
            self.connect(resamplerR, deemphR)
            self.connect_audio_output(deemphL, deemphR)
        else:
            resampler = self._make_resampler(mono_channel_filter, self.__audio_int_rate)
            deemph = fm_emph.fm_deemph(self.__audio_int_rate, 75e-6)
            self.connect(resampler, deemph)
            self.connect_audio_output(deemph, deemph)
Exemple #45
0
def multiply_ff(N):
    op = blocks.multiply_ff()
    tb = helper(N, op, gr.sizeof_float, gr.sizeof_float, 2, 1)
    return tb
Exemple #46
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
        Synchronization 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 = blocks.add_const_cc(0)

        # PN Sync

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

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

        # Create a moving sum filter for the corr output
        self.moving_sum_filter = filter.fir_filter_ccf(1, [1.0] *
                                                       (fft_length // 2))

        # Create a moving sum filter for the input
        self.inputmag2 = blocks.complex_to_mag_squared()
        self.inputmovingsum = filter.fir_filter_fff(1,
                                                    [1.0] * (fft_length // 2))

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

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

        self.sample_and_hold = blocks.sample_and_hold_ff()

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

        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 = filter.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,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
            self.connect(
                self.normalize,
                blocks.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
            self.connect(
                self.angle,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-epsilon_f.dat"))
            self.connect(
                self.pk_detect,
                blocks.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
            self.connect(
                self.sample_and_hold,
                blocks.file_sink(gr.sizeof_float,
                                 "ofdm_sync_pn-sample_and_hold_f.dat"))
            self.connect(
                self.input,
                blocks.file_sink(gr.sizeof_gr_complex,
                                 "ofdm_sync_pn-input_c.dat"))
Exemple #47
0
	def connect_audio_stage(self):
		demod_rate = self.demod_rate
		stereo_rate = self.post_demod_rate
		audio_rate = self.audio_rate
		normalizer = 2 * math.pi / stereo_rate
		pilot_tone = 19000
		pilot_low = pilot_tone * 0.9
		pilot_high = pilot_tone * 1.1

		def make_audio_filter():
			return grfilter.fir_filter_fff(
				1,  # decimation
				firdes.low_pass(
					1.0,
					stereo_rate,
					15000,
					5000,
					firdes.WIN_HAMMING))

		stereo_pilot_filter = grfilter.fir_filter_fcc(
			1,  # decimation
			firdes.complex_band_pass(
				1.0,
				stereo_rate,
				pilot_low,
				pilot_high,
				300))  # TODO magic number from gqrx
		stereo_pilot_pll = analog.pll_refout_cc(
			0.001,  # TODO magic number from gqrx
			normalizer * pilot_high,
			normalizer * pilot_low)
		stereo_pilot_doubler = blocks.multiply_cc()
		stereo_pilot_out = blocks.complex_to_imag()
		difference_channel_mixer = blocks.multiply_ff()
		difference_channel_filter = make_audio_filter()
		difference_real = blocks.complex_to_real(1)
		mono_channel_filter = make_audio_filter()
		resamplerL = self._make_resampler()
		resamplerR = self._make_resampler()
		mixL = blocks.add_ff(1)
		mixR = blocks.sub_ff(1)
		
		# connections
		if self.audio_filter:
			self.connect(self.demod_block, mono_channel_filter)
			mono = mono_channel_filter
		else:
			mono = self.demod_block

		if self.stereo:
			# stereo pilot tone tracker
			self.connect(
				self.demod_block,
				stereo_pilot_filter,
				stereo_pilot_pll)
			self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 0))
			self.connect(stereo_pilot_pll, (stereo_pilot_doubler, 1))
			self.connect(stereo_pilot_doubler, stereo_pilot_out)
		
			# pick out stereo left-right difference channel
			self.connect(self.demod_block, (difference_channel_mixer, 0))
			self.connect(stereo_pilot_out, (difference_channel_mixer, 1))
			self.connect(difference_channel_mixer, difference_channel_filter)
		
			# recover left/right channels
			self.connect(difference_channel_filter, (mixL, 1))
			self.connect(difference_channel_filter, (mixR, 1))
			self.connect(mono, (mixL, 0), resamplerL)
			self.connect(mono, (mixR, 0), resamplerR)
			self.connect_audio_output(resamplerL, resamplerR)
		else:
			self.connect(mono, resamplerL)
			self.connect_audio_output(resamplerL, resamplerL)
    def __init__(self,
                 fft_length,
                 cp_length,
                 preambles,
                 mode='RAW',
                 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
            ))

        period = fft_length / 2
        window = fft_length / 2

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

        P_d_angle = blocks.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 = blocks.moving_average_ff(window, 1.0)
        self.connect(self, blocks.complex_to_mag_squared(), R_d)
        R_d_squared = blocks.multiply_ff()  # this is retarded
        self.connect(R_d, (R_d_squared, 0))
        self.connect(R_d, (R_d_squared, 1))
        M_d = blocks.divide_ff()
        self.connect(P_d, blocks.complex_to_mag_squared(), (M_d, 0))
        self.connect(R_d_squared, (M_d, 1))

        # Now we need to detect peak of M_d
        # the peak is up to cp_length long, but noisy, so average it out
        matched_filter = blocks.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.25, 0.55, 30, 0.001)

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

        # peak_detect indicates the time M_d is highest, which is the end of the symbol.
        # 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
        #
        ##########################################################
        # IMPORTANT NOTES:
        # We can't delay by < 0 so instead:
        # input is delayed by some_length
        # signal to sample is delayed by some_length - offset
        ##########################################################
        # peak_delay and offset are for cutting CP
        # FIXME: until we figure out how to do this, just offset by 6 or cp_length/2
        symbol_length = fft_length + cp_length
        peak_delay = cp_length
        offset = 6  #cp_length/2
        self.offset = offset

        # regenerate peak using cross-correlation
        # * RAW mode: use raw_generate_peak2 block to filter peaks
        # * PNC mode: use raw_generate_peak3 block to identify the proper peak for two users
        # PNC mode delays all input peak_delay samples
        # * cp_length: delay for cross-correlation since auto-correlation is not so accurate
        # * 3 symbol_length: delay for identifying mode for PNC
        # * -offset: for cp cut
        if mode == 'PNC':
            # The block structure is
            # signal -> 3*symbol_length+cp_length-offset     -> (self,0) [signal]
            # signal -> cp_length delay -> auto  -> (peak,0) -> (self,2) [peak]
            # signal -> cp_length delay          -> (peak,1) -> (self,1) [cfo]
            # cfo    -> cp_length delay          -> (peak,2)
            #
            # we let cross's signal go faster to identify the beginning
            # we use cross's peak output to find cfo, so the delay of cfo should = cross delay
            # we use raw_regenerate_peak to do cross-corr, and symbols energy after STS to identify mode
            # so the signal is further delayed by three symbols more
            self.signal_cross_delay = blocks.delay(gr.sizeof_gr_complex,
                                                   peak_delay)
            self.cfo_cross_delay = blocks.delay(gr.sizeof_float, peak_delay)

            LOOK_AHEAD_NSYM = 3
            self.connect(self, self.signal_cross_delay)
            self.connect(P_d_angle, self.cfo_cross_delay)

            peak = raw.regenerate_peak3(fft_length, fft_length + cp_length,
                                        LOOK_AHEAD_NSYM, peak_delay, preambles,
                                        False)
            self.connect(peak_detect, (peak, 0))
            self.connect(self.signal_cross_delay, (peak, 1))
            self.connect(self.cfo_cross_delay, (peak, 2))

            self.signal_delay = blocks.delay(
                gr.sizeof_gr_complex,
                LOOK_AHEAD_NSYM * symbol_length + peak_delay - offset)
            self.connect(self, self.signal_delay, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # peak output

            if logging:
                self.connect(
                    self.cfo_cross_delay,
                    blocks.file_sink(gr.sizeof_float, 'logs/input-cfo.dat'))
                #self.connect(cross, blocks.file_sink(gr.sizeof_float, 'logs/cross.dat'))
                self.connect(
                    self.signal_cross_delay,
                    blocks.file_sink(gr.sizeof_gr_complex,
                                     'logs/cross-signal.dat'))

        if mode == 'RAW':
            LOOK_AHEAD_NSYM = 0
            peak = raw.regenerate_peak2(fft_length, fft_length + cp_length,
                                        LOOK_AHEAD_NSYM, preambles)
            self.signal_delay1 = blocks.delay(gr.sizeof_gr_complex,
                                              peak_delay - offset)
            self.signal_delay2 = blocks.delay(gr.sizeof_gr_complex, offset)
            self.cfo_delay = blocks.delay(
                gr.sizeof_float,
                peak_delay)  # we generate the same delay with signal
            self.connect(peak_detect, (peak, 0))
            self.connect(P_d_angle, self.cfo_delay, (peak, 1))
            self.connect(self, self.signal_delay1, self.signal_delay2,
                         (peak, 2))

            self.connect(self.signal_delay1, (self, 0))  # signal output
            self.connect((peak, 1), (self, 1))  # cfo output
            self.connect((peak, 0), (self, 2))  # raw peak output

            if logging:
                self.connect(
                    self.signal_delay1,
                    blocks.file_sink(gr.sizeof_gr_complex,
                                     'logs/test-out-signal.dat'))
                self.connect((peak, 0),
                             blocks.file_sink(gr.sizeof_char,
                                              'logs/test-out-peak.datb'))
                self.connect(
                    self.cfo_delay,
                    blocks.file_sink(gr.sizeof_float, 'logs/test-cfo.dat'))
                self.connect(
                    peak_detect,
                    blocks.file_sink(gr.sizeof_char,
                                     'logs/test-out-auto-peak.datb'))

        if logging:
            #self.connect(self.signal_delay1, blocks.file_sink(gr.sizeof_gr_complex, 'logs/test-signal.dat'))
            self.connect((peak, 0),
                         blocks.file_sink(gr.sizeof_char, 'logs/peak.datb'))
            self.connect((peak, 1),
                         blocks.file_sink(gr.sizeof_float,
                                          'logs/peak-cfo.dat'))
            self.connect(matched_filter,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-mf.dat'))
            self.connect(M_d,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-M.dat'))
            self.connect(
                P_d, blocks.file_sink(gr.sizeof_gr_complex,
                                      'logs/sync-pd.dat'))
            self.connect(R_d,
                         blocks.file_sink(gr.sizeof_float, 'logs/sync-rd.dat'))
            self.connect(
                R_d_squared,
                blocks.file_sink(gr.sizeof_float, 'logs/sync-rd-squared.dat'))
            self.connect(
                P_d_angle,
                blocks.file_sink(gr.sizeof_float, 'logs/sync-angle.dat'))
            self.connect(
                peak_detect,
                blocks.file_sink(gr.sizeof_char, 'logs/sync-peaks.datb'))