def test_001_instantiate(self):
        # data
        src_data = (1 + 1j, 2 + 2j, 3 + 3j)

        # blocks
        src = blocks.vector_source_c(src_data)
        self.debug = blocks.message_debug()
        dut = fhss_utils.tagged_burst_to_pdu(1, [1], 0.001, 0.5, 915e6,
                                             30.72e6, 30.72e6, 30.72e6, 3)

        self.tb.connect(src, dut)
        self.tb.msg_connect((dut, 'cpdus'), (self.debug, 'store'))

        self.tb.start()
        time.sleep(.1)
        self.tb.stop()
        self.tb.wait()
  def __init__(self, burst_width=int(500e3), center_freq=915e6, decimation=32,
               fft_size=256, hist_time=0.004, lookahead_time=0.0005,
               max_burst_time=0.5, min_burst_time=0.001,
               output_attenuation=40, output_cutoff=0.25,
               output_trans_width=0.1, post_burst_time=0.00008,
               pre_burst_time=0.00008, samp_rate=int(16e6),
               threshold=10,
               cf_method = RMS, channel_freqs = [],
               n_threads = 3):
      gr.hier_block2.__init__(
          self, "FSK Burst Extractor Hier",
          gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
          gr.io_signature(0, 0, 0),
      )
      '''
      Constructor
      
      @param burst_width - max burst bandwidth, Hz
      @param center_freq - 
      @param decimation - 
      @param fft_size - 
      @param hist_time - 
      @param lookahead_time - 
      @param max_burst_time - 
      @param min_burst_time - 
      @param output_attenuation - 
      @param output_cutoff -
      @param output_trans_width - 
      @param post_burst_time - 
      @param pre_burst_time - 
      @param samp_rate - 
      @param threshold - 
      @param cf_method - Center Frequency estimation method
      @param channel_freqs - CF Coerce freq list
      @param n_threads - 
      '''
      
      
      self.message_port_register_hier_out("pdu_out")

      ##################################################
      # Parameters
      ##################################################
      self.burst_width = burst_width
      self.center_freq = center_freq
      self.decimation = decimation
      self.fft_size = fft_size
      self.hist_time = hist_time
      self.lookahead_time = lookahead_time
      self.max_burst_time = max_burst_time
      self.min_burst_time = min_burst_time
      self.output_attenuation = output_attenuation
      self.output_cutoff = output_cutoff
      self.output_trans_width = output_trans_width
      self.post_burst_time = post_burst_time
      self.pre_burst_time = pre_burst_time
      self.samp_rate = samp_rate
      self.threshold = threshold
      self.channel_freqs = channel_freqs
      self.cf_method = cf_method
      self.n_threads = n_threads

      ##################################################
      # Blocks
      ##################################################
      # Low pass filter cutoff to half band.
      sig_taps = firdes.low_pass_2(1, 1, output_cutoff, output_trans_width, output_attenuation)
      self.pdu_utils_pdu_fir_filter_1 = pdu_utils.pdu_fir_filter(1, sig_taps)

      # This is a coarse filter,  Allow for transition band to alias onto itself.
      taps = firdes.low_pass_2(1, 1, .45 / decimation, .1 / decimation, output_attenuation)
      self.fhss_utils_tagged_burst_to_pdu_0 = fhss_utils.tagged_burst_to_pdu(decimation, taps, min_burst_time, max_burst_time, 0.0, 1.0, 1.0, samp_rate, n_threads)
      self.fhss_utils_fft_burst_tagger_0 = fhss_utils.fft_burst_tagger(center_freq, fft_size, samp_rate, int(round((float(samp_rate)/fft_size)*pre_burst_time)), int(round((float(samp_rate)/fft_size)*post_burst_time)), burst_width, 0, 0, threshold, int(round((float(samp_rate)/fft_size)*hist_time)), int(round((float(samp_rate)/fft_size)*lookahead_time)), False)
      #(self.fhss_utils_fft_burst_tagger_0).set_min_output_buffer(102400)
      self.cf_estimate = fhss_utils.cf_estimate(self.cf_method, self.channel_freqs)

      self.fine_time_measure = pdu_utils.pdu_fine_time_measure(pre_burst_time, post_burst_time, 10, 15)

      ##################################################
      # Connections
      ##################################################
      #self.msg_connect((self.pdu_utils_pdu_fir_filter_1, 'pdu_out'), (self, 'pdu_out'))
      self.msg_connect((self.fine_time_measure, 'pdu_out'), (self, 'pdu_out'))
      self.msg_connect((self.pdu_utils_pdu_fir_filter_1, 'pdu_out'), (self.fine_time_measure, 'pdu_in'))
      self.msg_connect((self.cf_estimate, 'out'), (self.pdu_utils_pdu_fir_filter_1, 'pdu_in'))
      self.msg_connect((self.fhss_utils_tagged_burst_to_pdu_0, 'cpdus'), (self.cf_estimate, 'in'))
      self.connect((self.fhss_utils_fft_burst_tagger_0, 0), (self.fhss_utils_tagged_burst_to_pdu_0, 0))
      self.connect((self, 0), (self.fhss_utils_fft_burst_tagger_0, 0))
    def test_002_simple(self):
        # This test processes a single burst and confirms that the resulting metadata is as expected

        # data
        min_data_size = 32 * 1024  # arbitrary constant in tagged_burst_to_pdu_impl.h
        src_data = (1, ) * min_data_size * 8

        new_burst_offset = 64
        new_burst_dict = pmt.make_dict()
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(1234))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(1e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__center_frequency(),
            pmt.from_float(915e6))  # of the whole signal, not the burst
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__magnitude(),
                                      pmt.from_float(40))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__sample_rate(),
                                      pmt.from_float(30.72e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__noise_density(),
                                      pmt.from_float(-100))  # in dBFS/Hz
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__bandwidth(),
                                      pmt.from_float(0.1e6))
        nb_tag = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        duration = 1024
        gone_burst_offset = new_burst_offset + duration
        gone_burst_dict = pmt.make_dict()
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(1234))
        gb_tag = gr.tag_utils.python_to_tag([
            gone_burst_offset,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])

        # blocks
        src = blocks.vector_source_c(src_data, False, 1, [nb_tag, gb_tag])
        #src.set_min_output_buffer(min_data_size*2) # not necessary, block calls set_output_multiple
        debug = blocks.message_debug()

        dec = 16
        taps = [1]
        min_time = 10e-6  # 1024/30.72e6 is about 33 usec
        max_time = 1.0
        nthreads = 3
        samp_rate = 30.72e6
        rel_span = 1
        rel_samp_rate = 1
        rel_cf = 0
        dut = fhss_utils.tagged_burst_to_pdu(dec, taps, min_time, max_time,
                                             rel_cf, rel_span, rel_samp_rate,
                                             samp_rate, nthreads)

        self.tb.connect(src, dut)
        self.tb.msg_connect((dut, 'cpdus'), (debug, 'store'))

        #self.tb.run() # blocking, vector_source will end flowgraph
        self.tb.start()
        time.sleep(0.1)
        self.tb.stop()
        time.sleep(0.1)
        self.tb.wait()
        time.sleep(0.1)

        print("test simple:")
        #print(f"how many msg? {debug.num_messages()}")
        self.assertEqual(debug.num_messages(), 1)
        #print(f"received: {pmt.car(debug.get_message(0))}")
        #print(f"received: {pmt.cdr(debug.get_message(0))}")
        rcv_meta = pmt.car(debug.get_message(0))
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("duration"), pmt.PMT_NIL)),
            duration / samp_rate, 6)
        self.assertEqual(
            pmt.to_uint64(
                pmt.dict_ref(rcv_meta, pmt.intern("start_offset"),
                             pmt.PMT_NIL)), new_burst_offset)
        self.assertEqual(
            pmt.to_uint64(
                pmt.dict_ref(rcv_meta, pmt.intern("end_offset"), pmt.PMT_NIL)),
            gone_burst_offset)
        self.assertEqual(
            pmt.to_uint64(
                pmt.dict_ref(rcv_meta, pmt.intern("burst_id"), pmt.PMT_NIL)),
            1234)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("start_time"), pmt.PMT_NIL)),
            new_burst_offset / samp_rate, 6)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("sample_rate"),
                             pmt.PMT_NIL)), samp_rate / dec, 6)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("bandwidth"), pmt.PMT_NIL)),
            0.1e6, 1)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("noise_density"),
                             pmt.PMT_NIL)), -100, 1)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("magnitude"), pmt.PMT_NIL)),
            40, 1)
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("center_frequency"),
                             pmt.PMT_NIL)), 916e6, 0)  # center of burst
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("relative_frequency"),
                             pmt.PMT_NIL)), 1e6, 0)  # in Hz
    def test_005_short_burst(self):
        # This test processes two bursts of which the first should be dropped for being too short

        # data
        min_data_size = 32 * 1024  # arbitrary constant in tagged_burst_to_pdu_impl.h
        src_data = (1, ) * min_data_size * 8

        new_burst_offset = 64
        new_burst_dict = pmt.make_dict()
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__center_frequency(),
            pmt.from_float(915e6))  # of the whole signal, not the burst
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__magnitude(),
                                      pmt.from_float(40))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__sample_rate(),
                                      pmt.from_float(30.72e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__noise_density(),
                                      pmt.from_float(-100))  # in dBFS/Hz
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__bandwidth(),
                                      pmt.from_float(0.1e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(111))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(1e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        nb_tag_short = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(222))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(2e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        nb_tag_normal = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        short_duration = 128
        normal_duration = 1024
        gone_burst_dict = pmt.make_dict()
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(111))
        gone_burst_offset = new_burst_offset + short_duration
        gb_tag_short = gr.tag_utils.python_to_tag([
            gone_burst_offset,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])

        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(222))
        gone_burst_offset = new_burst_offset + normal_duration
        gb_tag_normal = gr.tag_utils.python_to_tag([
            gone_burst_offset,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])

        # blocks
        src = blocks.vector_source_c(
            src_data, False, 1,
            [nb_tag_short, nb_tag_normal, gb_tag_short, gb_tag_normal])
        #src.set_min_output_buffer(min_data_size*2) # not necessary, block calls set_output_multiple
        debug = blocks.message_debug()

        dec = 16
        taps = [1]
        min_time = 5e-6  # 153-ish samples
        max_time = 1e-3
        nthreads = 3
        samp_rate = 30.72e6
        rel_span = 1
        rel_samp_rate = 1
        rel_cf = 0
        dut = fhss_utils.tagged_burst_to_pdu(dec, taps, min_time, max_time,
                                             rel_cf, rel_span, rel_samp_rate,
                                             samp_rate, nthreads)

        self.tb.connect(src, dut)
        self.tb.msg_connect((dut, 'cpdus'), (debug, 'store'))

        #self.tb.run() # blocking, vector_source will end flowgraph
        self.tb.start()
        time.sleep(0.1)
        self.tb.stop()
        time.sleep(0.1)
        self.tb.wait()
        time.sleep(0.1)

        print("test short burst:")
        print(f"how many msg? {debug.num_messages()}")
        self.assertEqual(debug.num_messages(), 1)  # first message dropped
        #print(f"received: {pmt.car(debug.get_message(0))}")
        #print(f"received: {pmt.cdr(debug.get_message(0))}")
        rcv_meta = pmt.car(debug.get_message(0))

        # we expect to not receive burst 111, but to receive burst 222
        self.assertEqual(
            pmt.to_uint64(
                pmt.dict_ref(rcv_meta, pmt.intern("burst_id"), pmt.PMT_NIL)),
            222)
    def test_004_long_burst(self):
        # This test processes a single burst that exceeds the maximum burst size that will be truncated

        # data
        min_data_size = 32 * 1024  # arbitrary constant in tagged_burst_to_pdu_impl.h
        src_data = (1, ) * min_data_size * 8

        new_burst_offset = 64
        new_burst_dict = pmt.make_dict()
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(505))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(1e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__center_frequency(),
            pmt.from_float(915e6))  # of the whole signal, not the burst
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__magnitude(),
                                      pmt.from_float(40))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__sample_rate(),
                                      pmt.from_float(30.72e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__noise_density(),
                                      pmt.from_float(-100))  # in dBFS/Hz
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__bandwidth(),
                                      pmt.from_float(0.1e6))
        nb_tag = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        duration = 1024
        gone_burst_offset = new_burst_offset + duration
        gone_burst_dict = pmt.make_dict()
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(505))
        gb_tag = gr.tag_utils.python_to_tag([
            gone_burst_offset,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])

        # blocks
        src = blocks.vector_source_c(src_data, False, 1, [nb_tag, gb_tag])
        #src.set_min_output_buffer(min_data_size*2) # not necessary, block calls set_output_multiple
        debug = blocks.message_debug()

        dec = 16
        taps = [1]
        min_time = 1e-6
        max_time = 10e-6
        nthreads = 3
        samp_rate = 30.72e6
        rel_span = 1
        rel_samp_rate = 1
        rel_cf = 0
        dut = fhss_utils.tagged_burst_to_pdu(dec, taps, min_time, max_time,
                                             rel_cf, rel_span, rel_samp_rate,
                                             samp_rate, nthreads)

        self.tb.connect(src, dut)
        self.tb.msg_connect((dut, 'cpdus'), (debug, 'store'))

        #self.tb.run() # blocking, vector_source will end flowgraph
        self.tb.start()
        time.sleep(0.1)
        self.tb.stop()
        time.sleep(0.1)
        self.tb.wait()
        time.sleep(0.1)

        print("test long burst:")
        #print(f"how many msg? {debug.num_messages()}")
        self.assertEqual(debug.num_messages(), 1)
        #print(f"received: {pmt.car(debug.get_message(0))}")
        #print(f"received: {pmt.cdr(debug.get_message(0))}")
        #print(f"received len: {pmt.length(pmt.cdr(debug.get_message(0)))}")
        rcv_meta = pmt.car(debug.get_message(0))

        # we expect a duration equal to `max_time` and a vector of length that corrseponds to `max_time` samples
        self.assertAlmostEqual(
            pmt.to_double(
                pmt.dict_ref(rcv_meta, pmt.intern("duration"), pmt.PMT_NIL)),
            max_time, 6)
        self.assertEqual(pmt.length(pmt.cdr(debug.get_message(0))),
                         (max_time * samp_rate) // dec)
        self.assertEqual(
            pmt.to_uint64(
                pmt.dict_ref(rcv_meta, pmt.intern("burst_id"), pmt.PMT_NIL)),
            505)
    def test_003_simul_bursts(self):
        # This test forces (as much as we can) three threads to process three simultaneous bursts. We check that
        # the resulting vectors are appropriately rotated to baseband.

        # data
        min_data_size = 32 * 1024  # arbitrary constant in tagged_burst_to_pdu_impl.h
        src_data = (1, ) * min_data_size * 8

        new_burst_offset = 64
        new_burst_dict = pmt.make_dict()
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__center_frequency(),
            pmt.from_float(915e6))  # of the whole signal, not the burst
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__magnitude(),
                                      pmt.from_float(40))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__sample_rate(),
                                      pmt.from_float(30.72e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__noise_density(),
                                      pmt.from_float(-100))  # in dBFS/Hz
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__bandwidth(),
                                      pmt.from_float(0.1e6))
        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(1001))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(0e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        nb_tag1 = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(1002))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(1e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        nb_tag2 = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        new_burst_dict = pmt.dict_add(new_burst_dict,
                                      fhss_utils.PMTCONSTSTR__burst_id(),
                                      pmt.from_uint64(1003))
        new_burst_dict = pmt.dict_add(
            new_burst_dict, fhss_utils.PMTCONSTSTR__relative_frequency(),
            pmt.from_float(-1e6 / 30.72e6))  # in [-1.0,1.0], not Hz
        nb_tag3 = gr.tag_utils.python_to_tag([
            new_burst_offset,
            fhss_utils.PMTCONSTSTR__new_burst(), new_burst_dict,
            pmt.intern("qa_test")
        ])

        duration = 1024
        gone_burst_offset = new_burst_offset + duration
        gone_burst_dict = pmt.make_dict()
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(1001))
        gb_tag1 = gr.tag_utils.python_to_tag([
            gone_burst_offset,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(1002))
        gb_tag2 = gr.tag_utils.python_to_tag([
            gone_burst_offset + 1,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])
        gone_burst_dict = pmt.dict_add(gone_burst_dict,
                                       fhss_utils.PMTCONSTSTR__burst_id(),
                                       pmt.from_uint64(1003))
        gb_tag3 = gr.tag_utils.python_to_tag([
            gone_burst_offset + 2,
            fhss_utils.PMTCONSTSTR__gone_burst(), gone_burst_dict,
            pmt.intern("qa_test")
        ])

        # blocks
        src = blocks.vector_source_c(
            src_data, False, 1,
            [nb_tag1, nb_tag2, nb_tag3, gb_tag1, gb_tag2, gb_tag3])
        #src.set_min_output_buffer(min_data_size*2) # not necessary, block calls set_output_multiple
        debug = blocks.message_debug()

        dec = 256
        taps = [1]
        min_time = 10e-6  # 1024/30.72e6 is about 33 usec
        max_time = 1.0
        nthreads = 3
        samp_rate = 30.72e6
        rel_span = 1
        rel_samp_rate = 1
        rel_cf = 0
        dut = fhss_utils.tagged_burst_to_pdu(dec, taps, min_time, max_time,
                                             rel_cf, rel_span, rel_samp_rate,
                                             samp_rate, nthreads)

        self.tb.connect(src, dut)
        self.tb.msg_connect((dut, 'cpdus'), (debug, 'store'))

        #self.tb.run() # blocking, vector_source will end flowgraph
        self.tb.start()
        time.sleep(0.5)
        self.tb.stop()
        time.sleep(0.1)
        self.tb.wait()
        time.sleep(0.1)

        print("test simultaneous:")
        print(f"how many msg? {debug.num_messages()}")
        self.assertEqual(debug.num_messages(), 3)
        #print(f"received: {pmt.car(debug.get_message(0))}")
        #print(f"received: {pmt.car(debug.get_message(1))}")
        #print(f"received: {pmt.car(debug.get_message(2))}")
        #print(f"received: {pmt.cdr(debug.get_message(0))}")
        #print(f"received: {pmt.cdr(debug.get_message(1))}")
        #print(f"received: {pmt.cdr(debug.get_message(2))}")

        r1 = pmt.c32vector_elements(pmt.cdr(debug.get_message(0)))
        r2 = pmt.c32vector_elements(pmt.cdr(debug.get_message(1)))
        r3 = pmt.c32vector_elements(pmt.cdr(debug.get_message(2)))

        #### Expected Results
        # what do we expect these vectors to be if they are filtered and rotated correctly?
        # - taps are [1], so no filtering should be noticeable in the data
        # - rotation is by 0, -1MHz, 1MHz for PDUs 0,1,2 respectively
        # - decimation of 256 means only every 256 samples is kept
        # First and last elements are trivial since the decimation (256) evenly divides the number of samples (1024).

        # example: get_messages(2) is shifted +1MHz to reach baseband
        #  >>> cmath.exp(0 + 1j * 1e6/30.72e6 * 2*math.pi* 256) # second element
        #  (-0.5000000000000023+0.8660254037844373j)
        #  >>> cmath.exp(0 + 1j * 1e6/30.72e6 * 2*math.pi* 512) # third element
        #  (-0.49999999999999534-0.8660254037844414j)
        #  >>> cmath.exp(0 + 1j * 1e6/30.72e6 * 2*math.pi* 768) # fourth element
        #  (1+9.82193361864236e-16j)

        # similar math can be done for get_messages(1), resulting in similar results with different signs

        cp6 = math.cos(
            math.pi /
            6)  # expected samples are 30 degrees off of the real-axis
        self.assertComplexTuplesAlmostEqual(r1, ((1 + 0j), (1 + 0j), (1 + 0j),
                                                 (1 + 0j)), 3)
        self.assertComplexTuplesAlmostEqual(r2, ((1 + 0j), (-.5 - cp6 * 1j),
                                                 (-.5 + cp6 * 1j), (1 + 0j)),
                                            3)
        self.assertComplexTuplesAlmostEqual(r3, ((1 + 0j), (-.5 + cp6 * 1j),
                                                 (-.5 - cp6 * 1j), (1 + 0j)),
                                            3)
示例#7
0
    def __init__(self, burst_width=int(500e3), cfo_start_offset=0, cfo_threshold=0.5, cfo_time_to_average=0.0005, decimation=32, fft_size=256, hist_time=0.004, lookahead_time=0.0005, max_burst_time=0.5, min_burst_time=0.001, output_attenuation=40, output_cutoff=0.5, output_trans_width=0.05, post_burst_time=0.00008, pre_burst_time=0.00008, samp_rate=int(30.72e6)):
        gr.top_block.__init__(self, "Burst Detector Reference")
        Qt.QWidget.__init__(self)
        self.setWindowTitle("Burst Detector Reference")
        qtgui.util.check_set_qss()
        try:
            self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
        except:
            pass
        self.top_scroll_layout = Qt.QVBoxLayout()
        self.setLayout(self.top_scroll_layout)
        self.top_scroll = Qt.QScrollArea()
        self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
        self.top_scroll_layout.addWidget(self.top_scroll)
        self.top_scroll.setWidgetResizable(True)
        self.top_widget = Qt.QWidget()
        self.top_scroll.setWidget(self.top_widget)
        self.top_layout = Qt.QVBoxLayout(self.top_widget)
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)

        self.settings = Qt.QSettings("GNU Radio", "fhss_detector_reference")
        self.restoreGeometry(self.settings.value("geometry").toByteArray())


        ##################################################
        # Parameters
        ##################################################
        self.burst_width = burst_width
        self.cfo_start_offset = cfo_start_offset
        self.cfo_threshold = cfo_threshold
        self.cfo_time_to_average = cfo_time_to_average
        self.decimation = decimation
        self.fft_size = fft_size
        self.hist_time = hist_time
        self.lookahead_time = lookahead_time
        self.max_burst_time = max_burst_time
        self.min_burst_time = min_burst_time
        self.output_attenuation = output_attenuation
        self.output_cutoff = output_cutoff
        self.output_trans_width = output_trans_width
        self.post_burst_time = post_burst_time
        self.pre_burst_time = pre_burst_time
        self.samp_rate = samp_rate

        ##################################################
        # Variables
        ##################################################
        self.threshold = threshold = 10
        self.gain = gain = 40
        self.fir_taps = fir_taps = firdes.low_pass_2(1, 1, 0.5*output_cutoff, 0.5*output_trans_width, output_attenuation)
        self.decim_taps = decim_taps = firdes.low_pass_2(1, 1, output_cutoff/decimation, output_trans_width/decimation, output_attenuation)
        self.center_freq = center_freq = 915e6

        ##################################################
        # Blocks
        ##################################################
        self._threshold_range = Range(6, 25, 1, 10, 200)
        self._threshold_win = RangeWidget(self._threshold_range, self.set_threshold, 'Threshold', "counter_slider", float)
        self.top_grid_layout.addWidget(self._threshold_win, 2, 2, 1, 1)
        for r in range(2, 3):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(2, 3):
            self.top_grid_layout.setColumnStretch(c, 1)
        self._gain_range = Range(0, 70, 1, 40, 200)
        self._gain_win = RangeWidget(self._gain_range, self.set_gain, 'Gain', "counter_slider", float)
        self.top_grid_layout.addWidget(self._gain_win, 2, 1, 1, 1)
        for r in range(2, 3):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(1, 2):
            self.top_grid_layout.setColumnStretch(c, 1)
        self._center_freq_range = Range(100e6, 2000e6, 1e6, 915e6, 200)
        self._center_freq_win = RangeWidget(self._center_freq_range, self.set_center_freq, 'Center Frequency', "counter_slider", float)
        self.top_grid_layout.addWidget(self._center_freq_win, 2, 0, 1, 1)
        for r in range(2, 3):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(0, 1):
            self.top_grid_layout.setColumnStretch(c, 1)
        self.uhd_usrp_source_1 = uhd.usrp_source(
        	",".join(("", "")),
        	uhd.stream_args(
        		cpu_format="fc32",
        		channels=range(1),
        	),
        )
        self.uhd_usrp_source_1.set_samp_rate(samp_rate)
        self.uhd_usrp_source_1.set_center_freq(center_freq, 0)
        self.uhd_usrp_source_1.set_gain(gain, 0)
        self.uhd_usrp_source_1.set_antenna('TX/RX', 0)
        self.uhd_usrp_source_1.set_auto_dc_offset(True, 0)
        self.uhd_usrp_source_1.set_auto_iq_balance(True, 0)
        (self.uhd_usrp_source_1).set_min_output_buffer(2048000)
        self.qtgui_waterfall_sink_x_0_0 = qtgui.waterfall_sink_c(
        	1024, #size
        	firdes.WIN_BLACKMAN_hARRIS, #wintype
        	0, #fc
        	samp_rate, #bw
        	"Input Spectrogram", #name
                1 #number of inputs
        )
        self.qtgui_waterfall_sink_x_0_0.set_update_time(0.01)
        self.qtgui_waterfall_sink_x_0_0.enable_grid(False)
        self.qtgui_waterfall_sink_x_0_0.enable_axis_labels(True)

        if not True:
          self.qtgui_waterfall_sink_x_0_0.disable_legend()

        if "complex" == "float" or "complex" == "msg_float":
          self.qtgui_waterfall_sink_x_0_0.set_plot_pos_half(not True)

        labels = ['', '', '', '', '',
                  '', '', '', '', '']
        colors = [0, 0, 0, 0, 0,
                  0, 0, 0, 0, 0]
        alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
                  1.0, 1.0, 1.0, 1.0, 1.0]
        for i in xrange(1):
            if len(labels[i]) == 0:
                self.qtgui_waterfall_sink_x_0_0.set_line_label(i, "Data {0}".format(i))
            else:
                self.qtgui_waterfall_sink_x_0_0.set_line_label(i, labels[i])
            self.qtgui_waterfall_sink_x_0_0.set_color_map(i, colors[i])
            self.qtgui_waterfall_sink_x_0_0.set_line_alpha(i, alphas[i])

        self.qtgui_waterfall_sink_x_0_0.set_intensity_range(-120, 0)

        self._qtgui_waterfall_sink_x_0_0_win = sip.wrapinstance(self.qtgui_waterfall_sink_x_0_0.pyqwidget(), Qt.QWidget)
        self.top_grid_layout.addWidget(self._qtgui_waterfall_sink_x_0_0_win, 0, 0, 1, 3)
        for r in range(0, 1):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(0, 3):
            self.top_grid_layout.setColumnStretch(c, 1)
        self.qtgui_waterfall_sink_x_0 = qtgui.waterfall_sink_c(
        	128, #size
        	firdes.WIN_BLACKMAN_hARRIS, #wintype
        	0, #fc
        	samp_rate/decimation/2, #bw
        	"Burst Spectrogram", #name
                0 #number of inputs
        )
        self.qtgui_waterfall_sink_x_0.set_update_time(0.005)
        self.qtgui_waterfall_sink_x_0.enable_grid(False)
        self.qtgui_waterfall_sink_x_0.enable_axis_labels(True)

        if not True:
          self.qtgui_waterfall_sink_x_0.disable_legend()

        if "msg_complex" == "float" or "msg_complex" == "msg_float":
          self.qtgui_waterfall_sink_x_0.set_plot_pos_half(not True)

        labels = ['', '', '', '', '',
                  '', '', '', '', '']
        colors = [0, 0, 0, 0, 0,
                  0, 0, 0, 0, 0]
        alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
                  1.0, 1.0, 1.0, 1.0, 1.0]
        for i in xrange(1):
            if len(labels[i]) == 0:
                self.qtgui_waterfall_sink_x_0.set_line_label(i, "Data {0}".format(i))
            else:
                self.qtgui_waterfall_sink_x_0.set_line_label(i, labels[i])
            self.qtgui_waterfall_sink_x_0.set_color_map(i, colors[i])
            self.qtgui_waterfall_sink_x_0.set_line_alpha(i, alphas[i])

        self.qtgui_waterfall_sink_x_0.set_intensity_range(-140, 10)

        self._qtgui_waterfall_sink_x_0_win = sip.wrapinstance(self.qtgui_waterfall_sink_x_0.pyqwidget(), Qt.QWidget)
        self.top_grid_layout.addWidget(self._qtgui_waterfall_sink_x_0_win, 1, 0, 1, 1)
        for r in range(1, 2):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(0, 1):
            self.top_grid_layout.setColumnStretch(c, 1)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0 = qtgui.time_sink_f(
        	102400, #size
        	1, #samp_rate
        	"Soft Symbols", #name
        	0 #number of inputs
        )
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_update_time(0.01)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_y_axis(-1.5, 1.5)

        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_y_label('Amplitude', "")

        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_tags(-1, True)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.000001, .001, 0, "")
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_autoscale(False)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_grid(True)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_axis_labels(True)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_control_panel(False)
        self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.enable_stem_plot(False)

        if not True:
          self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.disable_legend()

        labels = ['', '', '', '', '',
                  '', '', '', '', '']
        widths = [1, 1, 1, 1, 1,
                  1, 1, 1, 1, 1]
        colors = ["black", "red", "green", "black", "cyan",
                  "magenta", "yellow", "dark red", "dark green", "blue"]
        styles = [0, 1, 1, 1, 1,
                  1, 1, 1, 1, 1]
        markers = [0, -1, -1, -1, -1,
                   -1, -1, -1, -1, -1]
        alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
                  1.0, 1.0, 1.0, 1.0, 1.0]

        for i in xrange(1):
            if len(labels[i]) == 0:
                self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_label(i, "Data {0}".format(i))
            else:
                self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_label(i, labels[i])
            self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_width(i, widths[i])
            self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_color(i, colors[i])
            self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_style(i, styles[i])
            self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_marker(i, markers[i])
            self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.set_line_alpha(i, alphas[i])

        self._qtgui_time_sink_x_0_0_0_0_0_0_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0_0_0_0_0_0_0.pyqwidget(), Qt.QWidget)
        self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_0_0_0_0_0_0_0_win, 1, 2, 1, 1)
        for r in range(1, 2):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(2, 3):
            self.top_grid_layout.setColumnStretch(c, 1)
        self.qtgui_time_sink_x_0_0_0_0_0 = qtgui.time_sink_f(
        	102400, #size
        	samp_rate/decimation, #samp_rate
        	"FM Demodulation", #name
        	0 #number of inputs
        )
        self.qtgui_time_sink_x_0_0_0_0_0.set_update_time(0.01)
        self.qtgui_time_sink_x_0_0_0_0_0.set_y_axis(-2, 2)

        self.qtgui_time_sink_x_0_0_0_0_0.set_y_label('Amplitude', "")

        self.qtgui_time_sink_x_0_0_0_0_0.enable_tags(-1, True)
        self.qtgui_time_sink_x_0_0_0_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.000001, .001, 0, "")
        self.qtgui_time_sink_x_0_0_0_0_0.enable_autoscale(False)
        self.qtgui_time_sink_x_0_0_0_0_0.enable_grid(False)
        self.qtgui_time_sink_x_0_0_0_0_0.enable_axis_labels(True)
        self.qtgui_time_sink_x_0_0_0_0_0.enable_control_panel(False)
        self.qtgui_time_sink_x_0_0_0_0_0.enable_stem_plot(False)

        if not True:
          self.qtgui_time_sink_x_0_0_0_0_0.disable_legend()

        labels = ['', '', '', '', '',
                  '', '', '', '', '']
        widths = [1, 1, 1, 1, 1,
                  1, 1, 1, 1, 1]
        colors = ["blue", "red", "green", "black", "cyan",
                  "magenta", "yellow", "dark red", "dark green", "blue"]
        styles = [1, 1, 1, 1, 1,
                  1, 1, 1, 1, 1]
        markers = [-1, -1, -1, -1, -1,
                   -1, -1, -1, -1, -1]
        alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
                  1.0, 1.0, 1.0, 1.0, 1.0]

        for i in xrange(1):
            if len(labels[i]) == 0:
                self.qtgui_time_sink_x_0_0_0_0_0.set_line_label(i, "Data {0}".format(i))
            else:
                self.qtgui_time_sink_x_0_0_0_0_0.set_line_label(i, labels[i])
            self.qtgui_time_sink_x_0_0_0_0_0.set_line_width(i, widths[i])
            self.qtgui_time_sink_x_0_0_0_0_0.set_line_color(i, colors[i])
            self.qtgui_time_sink_x_0_0_0_0_0.set_line_style(i, styles[i])
            self.qtgui_time_sink_x_0_0_0_0_0.set_line_marker(i, markers[i])
            self.qtgui_time_sink_x_0_0_0_0_0.set_line_alpha(i, alphas[i])

        self._qtgui_time_sink_x_0_0_0_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0_0_0_0.pyqwidget(), Qt.QWidget)
        self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_0_0_0_0_win, 1, 1, 1, 1)
        for r in range(1, 2):
            self.top_grid_layout.setRowStretch(r, 1)
        for c in range(1, 2):
            self.top_grid_layout.setColumnStretch(c, 1)
        self.pdu_utils_pdu_split_0_0 = pdu_utils.pdu_split(False)
        self.pdu_utils_pdu_fir_filter_1 = pdu_utils.pdu_fir_filter(2, (fir_taps))
        self.pdu_utils_pdu_fine_time_measure_0 = pdu_utils.pdu_fine_time_measure(pre_burst_time, post_burst_time, 10, 15)
        self.pdu_utils_pdu_clock_recovery_0_0 = pdu_utils.pdu_clock_recovery(True)
        self.pdu_utils_pdu_clock_recovery_0 = pdu_utils.pdu_clock_recovery(False)
        self.fhss_utils_tagged_burst_to_pdu_0 = fhss_utils.tagged_burst_to_pdu(decimation, (decim_taps), min_burst_time, max_burst_time, 0.0, 1.0, 1.0, samp_rate, 7)
        self.fhss_utils_pdu_quadrature_demod_cf_0 = fhss_utils.pdu_quadrature_demod_cf(([1]), 1)
        self.fhss_utils_fine_burst_measure_0 = fhss_utils.fine_burst_measure(4000, 2048, 0.5)
        self.fhss_utils_fft_burst_tagger_0 = fhss_utils.fft_burst_tagger(center_freq, fft_size, samp_rate, int(round((float(samp_rate)/fft_size)*pre_burst_time)), int(round((float(samp_rate)/fft_size)*post_burst_time)), burst_width, 0, 0, threshold, int(round((float(samp_rate)/fft_size)*hist_time)), int(round((float(samp_rate)/fft_size)*lookahead_time)), False)
        (self.fhss_utils_fft_burst_tagger_0).set_min_output_buffer(2048000)
        self.blocks_message_debug_0_1 = blocks.message_debug()



        ##################################################
        # Connections
        ##################################################
        self.msg_connect((self.fhss_utils_fine_burst_measure_0, 'pdu_out'), (self.pdu_utils_pdu_fir_filter_1, 'pdu_in'))
        self.msg_connect((self.fhss_utils_pdu_quadrature_demod_cf_0, 'fpdus'), (self.pdu_utils_pdu_clock_recovery_0, 'pdu_in'))
        self.msg_connect((self.fhss_utils_pdu_quadrature_demod_cf_0, 'fpdus'), (self.pdu_utils_pdu_clock_recovery_0_0, 'pdu_in'))
        self.msg_connect((self.fhss_utils_pdu_quadrature_demod_cf_0, 'fpdus'), (self.qtgui_time_sink_x_0_0_0_0_0, 'in'))
        self.msg_connect((self.fhss_utils_tagged_burst_to_pdu_0, 'cpdus'), (self.fhss_utils_fine_burst_measure_0, 'pdu_in'))
        self.msg_connect((self.pdu_utils_pdu_clock_recovery_0, 'pdu_out'), (self.pdu_utils_pdu_split_0_0, 'pdu_in'))
        self.msg_connect((self.pdu_utils_pdu_clock_recovery_0, 'pdu_out'), (self.qtgui_time_sink_x_0_0_0_0_0_0_0_0, 'in'))
        self.msg_connect((self.pdu_utils_pdu_fine_time_measure_0, 'pdu_out'), (self.fhss_utils_pdu_quadrature_demod_cf_0, 'cpdus'))
        self.msg_connect((self.pdu_utils_pdu_fine_time_measure_0, 'pdu_out'), (self.qtgui_waterfall_sink_x_0, 'in'))
        self.msg_connect((self.pdu_utils_pdu_fir_filter_1, 'pdu_out'), (self.pdu_utils_pdu_fine_time_measure_0, 'pdu_in'))
        self.msg_connect((self.pdu_utils_pdu_split_0_0, 'dict'), (self.blocks_message_debug_0_1, 'print'))
        self.connect((self.fhss_utils_fft_burst_tagger_0, 0), (self.fhss_utils_tagged_burst_to_pdu_0, 0))
        self.connect((self.uhd_usrp_source_1, 0), (self.fhss_utils_fft_burst_tagger_0, 0))
        self.connect((self.uhd_usrp_source_1, 0), (self.qtgui_waterfall_sink_x_0_0, 0))
    def __init__(self,
                 burst_width=int(500e3),
                 center_freq=915e6,
                 decimation=32,
                 fft_size=256,
                 hist_time=0.004,
                 lookahead_time=0.0005,
                 max_burst_time=0.5,
                 min_burst_time=0.001,
                 output_attenuation=40,
                 output_cutoff=0.26,
                 output_trans_width=0.4,
                 post_burst_time=0.00008,
                 pre_burst_time=0.00008,
                 samp_rate=int(16e6),
                 cfo_samps_to_average=2048,
                 cfo_bin_resolution=4000,
                 threshold=6):
        gr.hier_block2.__init__(
            self,
            "FSK Burst Extractor Hier",
            gr.io_signature(1, 1, gr.sizeof_gr_complex * 1),
            gr.io_signature(0, 0, 0),
        )
        self.message_port_register_hier_out("pdu_out")

        ##################################################
        # Parameters
        ##################################################
        self.burst_width = burst_width
        self.center_freq = center_freq
        self.decimation = decimation
        self.fft_size = fft_size
        self.hist_time = hist_time
        self.lookahead_time = lookahead_time
        self.max_burst_time = max_burst_time
        self.min_burst_time = min_burst_time
        self.output_attenuation = output_attenuation
        self.output_cutoff = output_cutoff
        self.output_trans_width = output_trans_width
        self.post_burst_time = post_burst_time
        self.pre_burst_time = pre_burst_time
        self.samp_rate = samp_rate
        self.threshold = threshold

        ##################################################
        # Blocks
        ##################################################
        # Low pass filter cutoff to half band.
        self.pdu_utils_pdu_fir_filter_1 = pdu_utils.pdu_fir_filter(
            1, (firdes.low_pass_2(1, 1, .25, .1, output_attenuation)))
        # This is a coarse filter,  Allow for transition band to alias onto itself.
        taps = firdes.low_pass_2(1, 1, output_cutoff / decimation,
                                 output_trans_width / decimation,
                                 output_attenuation)
        self.fhss_utils_tagged_burst_to_pdu_0 = fhss_utils.tagged_burst_to_pdu(
            decimation, taps, min_burst_time, max_burst_time, 0.0, 1.0, 1.0,
            samp_rate, 3)
        self.fhss_utils_fft_burst_tagger_0 = fhss_utils.fft_burst_tagger(
            center_freq, fft_size, samp_rate,
            int(round((float(samp_rate) / fft_size) * pre_burst_time)),
            int(round((float(samp_rate) / fft_size) * post_burst_time)),
            burst_width, 0, 0, threshold,
            int(round((float(samp_rate) / fft_size) * hist_time)),
            int(round((float(samp_rate) / fft_size) * lookahead_time)), False)
        (self.fhss_utils_fft_burst_tagger_0).set_min_output_buffer(2048000 * 2)
        self.fhss_utils_fine_burst_measure = fhss_utils.fine_burst_measure(
            cfo_bin_resolution, cfo_samps_to_average, .5)

        self.fine_time_measure = pdu_utils.pdu_fine_time_measure(
            pre_burst_time, post_burst_time, 10, 15)

        ##################################################
        # Connections
        ##################################################
        #self.msg_connect((self.pdu_utils_pdu_fir_filter_1, 'pdu_out'), (self, 'pdu_out'))
        self.msg_connect((self.fine_time_measure, 'pdu_out'),
                         (self, 'pdu_out'))
        self.msg_connect((self.pdu_utils_pdu_fir_filter_1, 'pdu_out'),
                         (self.fine_time_measure, 'pdu_in'))
        self.msg_connect((self.fhss_utils_fine_burst_measure, 'pdu_out'),
                         (self.pdu_utils_pdu_fir_filter_1, 'pdu_in'))
        self.msg_connect((self.fhss_utils_tagged_burst_to_pdu_0, 'cpdus'),
                         (self.fhss_utils_fine_burst_measure, 'pdu_in'))
        self.connect((self.fhss_utils_fft_burst_tagger_0, 0),
                     (self.fhss_utils_tagged_burst_to_pdu_0, 0))
        self.connect((self, 0), (self.fhss_utils_fft_burst_tagger_0, 0))