def test_coerce(self): samp_rate = 1e6 freq_offset = -400e3 center_freq = 911e6 # blocks self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.COERCE, [x * 1e6 for x in range(900, 930)]) self.debug = blocks.message_debug() # connections self.tb.msg_connect((self.emitter, 'msg'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # data in_data = (1 + 0j, ) * 2048 i_vec = pmt.init_c32vector(len(in_data), in_data) out_data = np.exp(1j * np.arange(0, 2 * np.pi * (freq_offset / samp_rate * len(in_data)), 2 * np.pi * (freq_offset / samp_rate), dtype=np.complex64)) e_vec = pmt.init_c32vector(len(out_data), out_data.tolist( )) # pmt doesn't play nice with numpy sometimes, convert to list meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("sample_rate"), pmt.from_float(samp_rate)) meta = pmt.dict_add(meta, pmt.intern("center_frequency"), pmt.from_float(center_freq + freq_offset)) in_pdu = pmt.cons(meta, i_vec) e_pdu = pmt.cons(meta, e_vec) # flowgraph self.tb.start() time.sleep(.001) self.emitter.emit(in_pdu) time.sleep(.01) self.tb.stop() self.tb.wait() # parse output #print "got ", list(pmt.to_python(pmt.cdr(self.debug.get_message(0)))) #print "got ", self.debug.get_message(0) rcv = self.debug.get_message(0) rcv_meta = pmt.car(rcv) rcv_data = pmt.cdr(rcv) rcv_cf = pmt.dict_ref(rcv_meta, pmt.intern("center_frequency"), pmt.PMT_NIL) # asserts self.assertComplexTuplesAlmostEqual( tuple(pmt.c32vector_elements(rcv_data)), tuple(out_data), 2) self.assertTrue(pmt.equal(rcv_cf, pmt.from_float(911e6)))
def test_middle_out_metadata(self): samp_rate = 1e6 rot_offset = 1.0 / 16.0 self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.MIDDLE_OUT, []) self.sm = self.simple_modulator() self.rt = self.pdu_rotate(rot_offset) self.debug = blocks.message_debug() self.tb.msg_connect((self.emitter, 'msg'), (self.sm, 'in')) #self.tb.msg_connect((self.cf, 'debug'), (self.debug, 'print')) self.tb.msg_connect((self.sm, 'out'), (self.rt, 'in')) self.tb.msg_connect((self.rt, 'out'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # original data in_data = [0xAA] * 10 + [0x69] * 10 + [ 0x55 ] * 10 # 30 bytes = 240 bits = 1920 samples i_vec = pmt.init_u8vector(len(in_data), in_data) fc = 100e6 meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("sample_rate"), pmt.from_float(1e6)) meta = pmt.dict_add(meta, pmt.intern("center_frequency"), pmt.from_float(fc)) meta = pmt.dict_add(meta, pmt.intern("noise_density"), pmt.from_float(-105.0)) in_pdu = pmt.cons(meta, i_vec) self.tb.start() time.sleep(.1) self.emitter.emit(in_pdu) time.sleep(.1) self.tb.stop() self.tb.wait() # parse output rcv = self.debug.get_message(0) rcv_meta = pmt.car(rcv) rcv_data = pmt.cdr(rcv) # asserts rcv_cf = pmt.to_double( pmt.dict_ref(rcv_meta, pmt.intern("center_frequency"), pmt.PMT_NIL)) expected_cf = 100e6 + samp_rate * rot_offset # we rotated the burst 62500 Hz off max_diff = samp_rate / 256 / 2 # half an FFT bin error allowed #print("M-O: got ", rcv_cf - fc, " expected ", expected_cf-fc, "(diff ", rcv_cf-expected_cf, ")") self.assertTrue(abs(rcv_cf - expected_cf) < max_diff)
def test_half_power_metadata(self): samp_rate = 1e6 rot_offset = 1.0 / 16.0 self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.HALF_POWER, []) self.sm = self.simple_modulator() self.rt = self.pdu_rotate(rot_offset) self.debug = blocks.message_debug() self.tb.msg_connect((self.emitter, 'msg'), (self.sm, 'in')) self.tb.msg_connect((self.sm, 'out'), (self.rt, 'in')) self.tb.msg_connect((self.rt, 'out'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # original data in_data = [0xAA] * 10 + [0x69] * 10 + [ 0x55 ] * 10 # 30 bytes = 240 bits = 1920 samples i_vec = pmt.init_u8vector(len(in_data), in_data) meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("sample_rate"), pmt.from_float(1e6)) meta = pmt.dict_add(meta, pmt.intern("center_frequency"), pmt.from_float(100.0e6)) in_pdu = pmt.cons(meta, i_vec) self.tb.start() time.sleep(.1) self.emitter.emit(in_pdu) time.sleep(.1) self.tb.stop() self.tb.wait() # parse output #print("got ", list(pmt.to_python(pmt.cdr(self.debug.get_message(0))))) #print("got ", pmt.car(self.debug.get_message(0))) rcv = self.debug.get_message(0) rcv_meta = pmt.car(rcv) rcv_data = pmt.cdr(rcv) # asserts rcv_cf = pmt.to_double( pmt.dict_ref(rcv_meta, pmt.intern("center_frequency"), pmt.PMT_NIL)) expected_cf = 100e6 + samp_rate * rot_offset # we rotated the burst 62500 Hz off self.assertTrue( abs(rcv_cf - expected_cf) < 1.0) # less than 1 Hz off (no noise)
def test_input_sanitization(self): samp_rate = 1e6 freq_offset = -400e3 center_freq = 911e6 # blocks self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.COERCE, [x * 1e6 for x in range(900, 930)]) self.debug = blocks.message_debug() # connections self.tb.msg_connect((self.emitter, 'msg'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # data in_data = (1 + 0j, ) * 2048 i_vec = pmt.init_c32vector(len(in_data), in_data) meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("sample_rate"), pmt.from_float(samp_rate)) meta = pmt.dict_add(meta, pmt.intern("center_freq"), pmt.from_float(center_freq + freq_offset)) in_pdu = pmt.cons(meta, i_vec) # flowgraph self.tb.start() time.sleep(.001) self.emitter.emit(pmt.PMT_T) time.sleep(.01) self.emitter.emit(pmt.cons(pmt.PMT_T, pmt.PMT_NIL)) time.sleep(.01) self.emitter.emit(meta) time.sleep(.01) self.emitter.emit(i_vec) time.sleep(.01) self.emitter.emit(in_pdu) time.sleep(.01) self.tb.stop() self.tb.wait() self.assertEqual(0, self.debug.num_messages())
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))