def handler(self, pdu): meta = pmt.car(pdu); samples = pmt.cdr(pdu); x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) x_2 = numpy.real(x * x.conjugate()) #mag squared # smoothing filter, running average, with 'length' samples x_2f = numpy.convolve(self.length*[1], x_2); # find max power to compute power thresh maxidx = numpy.argmax(x_2f); maxpow = x_2f[maxidx]; # find min power to compute power thresh minidx = numpy.argmin(x_2f); minpow = x_2f[minidx]; thr = maxpow / 16; # 6db down from max #find avg (or median) of samples above thresh (signal) min_avg = numpy.average(x_2f[x_2f<=thr]) #find avg (or median) of samples below thresh (noise) max_avg = numpy.average(x_2f[x_2f>thr]) #compute log scale snr [dB] #already have power of 2 from x_2 calc, so 10log10(snr) snr = 10 * numpy.log10(max_avg / min_avg) #Correction ratio based on samples per symbol snr = snr + 10*numpy.log10(self.sps) #add snr to metadata meta = pmt.dict_add(meta, pmt.intern("snr"), pmt.from_double(snr)); samples_out = pmt.init_c32vector(len(x), map(lambda i: complex(i), x)) cpdu = pmt.cons(meta,samples_out) self.message_port_pub(pmt.intern("out"), cpdu);
def test_003_c32noise(self): self.add.set_scale(4) self.add.set_offset(3) self.add.set_noise_level(0.1) self.add.set_seed(123) in_data = range(8) expected_data = [(3.1111398 + 3.1204658j), (6.879022 + 2.959537j), (10.845484 + 3.1079807j), (15.029028 + 3.12397j), (19.124151 + 2.994976j), (22.956503 + 3.1584077j), (27.271961 + 2.9496112j), (31.104555 + 3.0450819j)] in_pdu = pmt.cons(pmt.make_dict(), pmt.init_c32vector(len(in_data), in_data)) self.tb.start() time.sleep(.001) self.emitter.emit(pmt.intern("MALFORMED PDU")) time.sleep(.001) self.emitter.emit(in_pdu) time.sleep(.01) self.tb.stop() self.tb.wait() out_data = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(out_data, expected_data, 3)
def run_flow_graph(sync_sym1, sync_sym2, data_sym): top_block = gr.top_block() carr_offset = random.randint(-max_offset / 2, max_offset / 2) * 2 tx_data = shift_tuple(sync_sym1, carr_offset) + \ shift_tuple(sync_sym2, carr_offset) + \ shift_tuple(data_sym, carr_offset) channel = [rand_range(min_chan_ampl, max_chan_ampl) * numpy.exp(1j * rand_range(0, 2 * numpy.pi)) for x in range(fft_len)] src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) noise = analog.noise_source_c(analog.GR_GAUSSIAN, wgn_amplitude) add = blocks.add_cc(fft_len) chanest = digital.ofdm_chanest_vcvc(sync_sym1, sync_sym2, 1) sink = blocks.vector_sink_c(fft_len) top_block.connect(src, chan, (add, 0), chanest, sink) top_block.connect(noise, blocks.stream_to_vector(gr.sizeof_gr_complex, fft_len), (add, 1)) top_block.run() channel_est = None carr_offset_hat = 0 rx_sym_est = [0,] * fft_len tags = sink.tags() for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': carr_offset_hat = pmt.to_long(tag.value) self.assertEqual(carr_offset, carr_offset_hat) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': channel_est = shift_tuple(pmt.c32vector_elements(tag.value), carr_offset) shifted_carrier_mask = shift_tuple(carrier_mask, carr_offset) for i in range(fft_len): if shifted_carrier_mask[i] and channel_est[i]: self.assertAlmostEqual(channel[i], channel_est[i], places=0) rx_sym_est[i] = (sink.data()[i] / channel_est[i]).real return (carr_offset, list(shift_tuple(rx_sym_est, -carr_offset_hat)))
def test_simple(self): # make the data and expected results data = [x + x * 1j for x in range(10)] pdu_in = pmt.cons(pmt.make_dict(), pmt.init_c32vector(len(data), data)) expected_energy = sum([abs(x)**2 for x in data]) expected_power = 10 * np.log10(expected_energy / len(data)) # run flowgraph self.tb.start() time.sleep(.001) self.emitter.emit(pmt.intern("BAD PDU")) time.sleep(.001) self.emitter.emit(pdu_in) time.sleep(.01) self.tb.stop() self.tb.wait() # don't wait...may not return in time # extract results rcv_pdu = self.debug.get_message(0) rcv_meta = pmt.car(rcv_pdu) rcv_data = pmt.c32vector_elements(pmt.cdr(rcv_pdu)) rcv_energy = pmt.to_double( pmt.dict_ref(rcv_meta, pmt.intern("energy"), pmt.PMT_NIL)) rcv_power = pmt.to_double( pmt.dict_ref(rcv_meta, pmt.intern("power"), pmt.PMT_NIL)) # assert expectations precision = 1e-3 self.assertTrue(abs(rcv_energy - expected_energy) < precision) self.assertTrue(abs(rcv_power - expected_power) < precision)
def test_004_channel_no_carroffset_1sym (self): """ Add a channel, check if it's correctly estimated. Only uses 1 synchronisation symbol. """ fft_len = 16 carr_offset = 0 sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol + data_symbol channel = (0, 0, 0, 2, 2, 2, 2, 3, 3, 2.5, 2.5, -3, -3, 1j, 1j, 0) #channel = (0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol, (), 1) sink = blocks.vector_sink_c(fft_len) sink_chanest = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.connect((chanest, 1), sink_chanest) self.tb.run() self.assertEqual(sink_chanest.data(), channel) tags = sink.tags() for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel)
def handler(self, pdu): meta = pmt.to_python(pmt.car(pdu)) samples = pmt.cdr(pdu) x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) #print meta #print meta['rx_time'], meta['es::event_time'] time_delta = meta['es::event_time'] / self.samp_rate rx_int_sec = meta['rx_time'][1][0] rx_frac_sec = meta['rx_time'][1][1] #print rx_int_sec, rx_frac_sec #print time_delta, math.modf(time_delta) td = math.modf(time_delta) dt = (numpy.int64(rx_int_sec + td[1]), rx_frac_sec + td[0]) #print datetime ts = numpy.datetime64(datetime.datetime.utcfromtimestamp(dt[0])) ts = ts + numpy.timedelta64(int(dt[1] * 1e9), 'ns') ts_ns = numpy.datetime_as_string(ts) + "Z" meta = pmt.to_pmt(meta) #meta = pmt.dict_add(meta, pmt.intern("pkt_rx_time"), pmt.make_tuple(dt)); meta = pmt.dict_add(meta, pmt.intern("datetime"), pmt.string_to_symbol(ts_ns)) #meta['pkt_rx_time'] = dt #meta['datetime'] = ts_ns samples_out = pmt.init_c32vector(len(x), map(lambda i: complex(i), x)) cpdu = pmt.cons(meta, samples_out) self.message_port_pub(pmt.intern("out"), cpdu)
def test_metadata_phase_set(self): phase_inc = np.pi / 4 self.dut = pdu_utils.pdu_rotate(phase_inc) self.connectUp() data = [x + x * 1j for x in range(16)] rot_data = self.rotate(data, -2 * phase_inc) meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("phase_inc"), pmt.from_double(phase_inc * 2)) in_pdu = pmt.cons(meta, pmt.init_c32vector(len(rot_data), rot_data)) e_vec = pmt.init_c32vector(len(data), data) self.tb.start() time.sleep(.01) self.emitter.emit(in_pdu) time.sleep(.1) self.tb.stop() self.tb.wait() #print("test_metadata_phase_inc:") #print(f"expected: {data}") #print(f"got: {self.debug.get_message(0)}") rcv = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(rcv, data, 2)
def test_001_three (self): in_data1 = [1+1j, 0-1j] in_data2 = [1, 0] in_data3 = [1j, -1] expected_data = in_data1 + in_data2 + in_data3 dict1 = pmt.dict_add(pmt.make_dict(), pmt.intern("burst_index"), pmt.cons(pmt.from_uint64(1), pmt.from_uint64(3))) dict2 = pmt.dict_add(pmt.make_dict(), pmt.intern("burst_index"), pmt.cons(pmt.from_uint64(2), pmt.from_uint64(3))) dict3 = pmt.dict_add(pmt.make_dict(), pmt.intern("burst_index"), pmt.cons(pmt.from_uint64(3), pmt.from_uint64(3))) in_pdu1 = pmt.cons(dict1, pmt.init_c32vector(len(in_data1), in_data1)) in_pdu2 = pmt.cons(dict2, pmt.init_c32vector(len(in_data2), in_data2)) in_pdu3 = pmt.cons(dict3, pmt.init_c32vector(len(in_data3), in_data3)) expected_pdu = pmt.cons(pmt.make_dict(), pmt.init_c32vector(len(expected_data), expected_data)) self.tb.start() time.sleep(.001) # handle non-pair input self.emitter.emit(pmt.intern("MALFORMED PDU")) time.sleep(.001) # handle malformed pair self.emitter.emit(pmt.cons(pmt.intern("NON-PDU"), pmt.intern("PAIR"))) time.sleep(.001) # handle out of order PDU self.emitter.emit(in_pdu3) time.sleep(.001) self.emitter.emit(in_pdu1) time.sleep(.001) self.emitter.emit(in_pdu2) time.sleep(.001) self.emitter.emit(in_pdu3) time.sleep(.01) self.tb.stop() self.tb.wait() out_data = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(out_data, expected_data)
def run_flow_graph(sync_sym1, sync_sym2, data_sym): top_block = gr.top_block() carr_offset = random.randint(-max_offset/2, max_offset/2) * 2 tx_data = shift_tuple(sync_sym1, carr_offset) + \ shift_tuple(sync_sym2, carr_offset) + \ shift_tuple(data_sym, carr_offset) channel = [rand_range(min_chan_ampl, max_chan_ampl) * numpy.exp(1j * rand_range(0, 2 * numpy.pi)) for x in range(fft_len)] src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) noise = analog.noise_source_c(analog.GR_GAUSSIAN, wgn_amplitude) add = blocks.add_cc(fft_len) chanest = digital.ofdm_chanest_vcvc(sync_sym1, sync_sym2, 1) sink = blocks.vector_sink_c(fft_len) top_block.connect(src, chan, (add, 0), chanest, sink) top_block.connect(noise, blocks.stream_to_vector(gr.sizeof_gr_complex, fft_len), (add, 1)) top_block.run() channel_est = None carr_offset_hat = 0 rx_sym_est = [0,] * fft_len tags = sink.tags() for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': carr_offset_hat = pmt.to_long(tag.value) self.assertEqual(carr_offset, carr_offset_hat) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': channel_est = shift_tuple(pmt.c32vector_elements(tag.value), carr_offset) shifted_carrier_mask = shift_tuple(carrier_mask, carr_offset) for i in range(fft_len): if shifted_carrier_mask[i] and channel_est[i]: self.assertAlmostEqual(channel[i], channel_est[i], places=0) rx_sym_est[i] = (sink.data()[i] / channel_est[i]).real return (carr_offset, list(shift_tuple(rx_sym_est, -carr_offset_hat)))
def test_003_channel_no_carroffset (self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 0 sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol1 + sync_symbol2 + data_symbol channel = [0, 0, 0, 2, -2, 2, 3j, 2, 0, 2, 2, 2, 2, 3, 0, 0] src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol1, sync_symbol2, 1) sink = blocks.vector_sink_c(fft_len) sink_chanest = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.connect((chanest, 1), sink_chanest) self.tb.run() tags = sink.tags() self.assertEqual(shift_tuple(sink.data(), -carr_offset), tuple(numpy.multiply(data_symbol, channel))) for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel) self.assertEqual(sink_chanest.data(), channel)
def test_006_channel_and_carroffset (self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 2 # Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) # Channel 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # Shifted (0, 0, 0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1) chanest_exp = [0, 0, 0, 5, 6, 7, 8, 9, 0, 11, 12, 13, 14, 15, 0, 0] tx_data = shift_tuple(sync_symbol1, carr_offset) + \ shift_tuple(sync_symbol2, carr_offset) + \ shift_tuple(data_symbol, carr_offset) channel = list(range(fft_len)) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol1, sync_symbol2, 1) sink = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.run() tags = sink.tags() chan_est = None for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': chan_est = pmt.c32vector_elements(tag.value) self.assertEqual(chan_est, chanest_exp) self.assertEqual(sink.data(), list(numpy.multiply(shift_tuple(data_symbol, carr_offset), channel)))
def test_002_oneshot(self): in_data1 = [1 + 1j, 0 - 1j] expected_data = in_data1 dict1 = pmt.dict_add(pmt.make_dict(), pmt.intern("burst_index"), pmt.cons(pmt.from_uint64(1), pmt.from_uint64(1))) in_pdu1 = pmt.cons(dict1, pmt.init_c32vector(len(in_data1), in_data1)) expected_pdu = pmt.cons( pmt.make_dict(), pmt.init_c32vector(len(expected_data), expected_data)) self.tb.start() time.sleep(.001) # handle non-pair input self.emitter.emit(pmt.intern("MALFORMED PDU")) time.sleep(.001) # handle malformed pair self.emitter.emit(pmt.cons(pmt.intern("NON-PDU"), pmt.intern("PAIR"))) time.sleep(.001) self.emitter.emit(in_pdu1) time.sleep(.01) self.tb.stop() self.tb.wait() out_data = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(out_data, expected_data)
def handler(self, msg): if (self.idx > self.maxidx): return ba = bitarray.bitarray() meta = pmt.car(msg) cdata = pmt.cdr(msg) pydict = None try: pydict = pmt.to_python(meta) except: pass x = pmt.c32vector_elements(cdata) #fn = "/tmp/cpdu_burst_%f.txt"%(time.time()); fn = "/tmp/cpdu_burst_%f.txt" % (self.idx) print "writing %s" % (fn) f = open(fn, "w") x = ", ".join(map(lambda x: "%f+%fj" % (x.real, x.imag), x)) f.write("x = [%s]\n" % (str(x))) # f.write("meta = %s"%(str(pydict))); f.close() f = None self.idx = self.idx + 1
def test_004_channel_no_carroffset_1sym (self): """ Add a channel, check if it's correctly estimated. Only uses 1 synchronisation symbol. """ fft_len = 16 carr_offset = 0 sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol + data_symbol channel = [0, 0, 0, 2, 2, 2, 2, 3, 3, 2.5, 2.5, -3, -3, 1j, 1j, 0] #channel = (0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol, (), 1) sink = blocks.vector_sink_c(fft_len) sink_chanest = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.connect((chanest, 1), sink_chanest) self.tb.run() self.assertEqual(sink_chanest.data(), channel) tags = sink.tags() for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel)
def test_006_channel_and_carroffset (self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 2 # Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) # Channel 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # Shifted (0, 0, 0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1) chanest_exp = (0, 0, 0, 5, 6, 7, 8, 9, 0, 11, 12, 13, 14, 15, 0, 0) tx_data = shift_tuple(sync_symbol1, carr_offset) + \ shift_tuple(sync_symbol2, carr_offset) + \ shift_tuple(data_symbol, carr_offset) channel = range(fft_len) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol1, sync_symbol2, 1) sink = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.run() tags = sink.tags() chan_est = None for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': chan_est = pmt.c32vector_elements(tag.value) self.assertEqual(chan_est, chanest_exp) self.assertEqual(sink.data(), tuple(numpy.multiply(shift_tuple(data_symbol, carr_offset), channel)))
def handler(self, msg): if(self.idx > self.maxidx): return; ba = bitarray.bitarray(); meta = pmt.car(msg); cdata = pmt.cdr(msg); pydict = None; try: pydict = pmt.to_python(meta); except: pass; x = pmt.c32vector_elements(cdata) #fn = "/tmp/cpdu_burst_%f.txt"%(time.time()); fn = "/tmp/cpdu_burst_%f.txt"%(self.idx); print "writing %s"%(fn); f = open(fn,"w"); x = ", ".join( map( lambda x: "%f+%fj"%(x.real, x.imag), x) ); f.write("x = [%s]\n"%(str(x))); # f.write("meta = %s"%(str(pydict))); f.close(); f = None; self.idx = self.idx + 1;
def test_003_channel_no_carroffset (self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 0 sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol1 + sync_symbol2 + data_symbol channel = (0, 0, 0, 2, -2, 2, 3j, 2, 0, 2, 2, 2, 2, 3, 0, 0) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) chanest = digital.ofdm_chanest_vcvc(sync_symbol1, sync_symbol2, 1) sink = blocks.vector_sink_c(fft_len) sink_chanest = blocks.vector_sink_c(fft_len) self.tb.connect(src, chan, chanest, sink) self.tb.connect((chanest, 1), sink_chanest) self.tb.run() tags = sink.tags() self.assertEqual(shift_tuple(sink.data(), -carr_offset), tuple(numpy.multiply(data_symbol, channel))) for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel) self.assertEqual(sink_chanest.data(), channel)
def test_001_t (self): in_data = [0, 1, 0, 0, 1, 0, 1, 1] print("in_data = ", in_data) expected_data = [(1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (0.9999558329582214-0.009149551391601562j), (0.9986380934715271-0.05212688446044922j), (0.9845290780067444-0.17521238327026367j), (0.9109043478965759-0.4126133918762207j), (0.6968833208084106-0.717181921005249j), (0.31042835116386414-0.950594425201416j), (-0.17273569107055664-0.9849666953086853j), (-0.6225566864013672-0.7825717926025391j), (-0.914273738861084-0.4051017761230469j), (-0.999992847442627-0.003090381622314453j), (-0.9691651463508606+0.24640250205993652j), (-0.968771755695343+0.24795293807983398j), (-0.9999971389770508+0.0017070770263671875j), (-0.9174799919128418-0.39777708053588867j), (-0.6312775611877441-0.7755542993545532j), (-0.18532180786132812-0.9826757907867432j), (0.2910269498825073-0.9567151069641113j), (0.6513003706932068-0.7588169574737549j), (0.81996750831604-0.5724067687988281j), (0.8208843469619751-0.5710964202880859j), (0.6549332737922668-0.7556841373443604j), (0.2986666262149811-0.9543551206588745j), (-0.17431020736694336-0.9846884608268738j), (-0.6225566864013672-0.7825717926025391j), (-0.9215338230133057-0.3883037567138672j), (-0.994880199432373+0.10103797912597656j), (-0.8246530294418335+0.5656423568725586j), (-0.4525153636932373+0.8917537331581116j), (0.030410051345825195+0.9995390772819519j), (0.5058896541595459+0.8625954985618591j), (0.8575133085250854+0.5144641399383545j), (0.9991825222969055+0.040370840579271317j), (0.9041904211044312-0.42713212966918945j), (0.6559781432151794-0.7547774314880371j), (0.44701042771339417-0.8945262432098389j), (0.44557973742485046-0.8952407836914062j), (0.6523504257202148-0.7579166889190674j), (0.9007443785667419-0.43434762954711914j), (0.9995729923248291+0.029183024540543556j), (0.8648265600204468+0.5020678639411926j), (0.533815860748291+0.8455996513366699j), (0.14855670928955078+0.9889022707939148j), (-0.1027672290802002+0.99470454454422j), (-0.10435843467712402+0.9945414066314697j), (0.14381003379821777+0.9896029233932495j), (0.5270366668701172+0.8498398065567017j), (0.8591512441635132+0.5117172598838806j), (0.9991825222969055+0.040370840579271317j), (0.9041904211044312-0.42713212966918945j), (0.6559781432151794-0.7547774314880371j), (0.44701042771339417-0.8945262432098389j), (0.44557973742485046-0.8952407836914062j), (0.6523504257202148-0.7579166889190674j), (0.9007443785667419-0.43434762954711914j), (0.9995729923248291+0.029183024540543556j), (0.8648265600204468+0.5020678639411926j), (0.5182530879974365+0.8552265167236328j), (0.04479217529296875+0.9989947080612183j), (-0.4396350383758545+0.8981758952140808j), (-0.8164236545562744+0.5774505138397217j), (-0.9933251738548279+0.11534643173217773j), (-0.9270230531692505-0.3749988079071045j), (-0.6337566375732422-0.773532509803772j), (-0.18532228469848633-0.9826757311820984j), (0.29976776242256165-0.954010009765625j), (0.6899716258049011-0.7238376140594482j), (0.9075756072998047-0.41988372802734375j), (0.9833885431289673-0.18150663375854492j), (0.9983774423599243-0.05691719055175781j), (0.9999259114265442-0.012347698211669922j), (0.9999974370002747-0.0015993118286132812j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j), (1.000002384185791+7.219194575469601e-09j)] log_scale = [10**((x-50)/10.) for x in range(0,50)] for i in range(len(log_scale)): expected_data[i] *= log_scale[i] in_pdu = pmt.cons(pmt.make_dict(), pmt.init_u8vector(len(in_data), in_data)) expected_pdu = pmt.cons(pmt.make_dict(), pmt.init_c32vector(len(expected_data), expected_data)) self.tb.start() time.sleep(.001) # handle non-pair input self.emitter2.emit(pmt.intern("MALFORMED PDU")) time.sleep(.001) # handle malformed pair self.emitter2.emit(pmt.cons(pmt.intern("NON-PDU"), pmt.intern("PAIR"))) time.sleep(.001) # handle incorrect PDU self.emitter2.emit(in_pdu) time.sleep(.001) self.emitter.emit(in_pdu) time.sleep(.01) self.tb.stop() self.tb.wait() out_data = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(out_data, expected_data, 5)
def test_004_c32noise_gaus(self): self.add.set_scale(4) self.add.set_offset(3) self.add.set_noise_level(0.1) self.add.set_noise_dist(pdu_utils.GAUSSIAN) self.add.set_seed(123) in_data = range(8) expected_data = [(3.3071127 + 3.283337j), (6.8398867 + 2.5212853j), (11.206407 + 2.7046404j), (15.492073 + 3.1152205j), (18.979256 + 3.5126355j), (23.402103 + 2.8895853j), (26.984592 + 3.0831635j), (31.213652 + 3.4955065j)] in_pdu = pmt.cons(pmt.make_dict(), pmt.init_c32vector(len(in_data), in_data)) self.tb.start() time.sleep(.001) self.emitter.emit(pmt.intern("MALFORMED PDU")) time.sleep(.001) self.emitter.emit(in_pdu) time.sleep(.01) self.tb.stop() self.tb.wait() out_data = pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) self.assertComplexTuplesAlmostEqual(out_data, expected_data, 3)
def handler(self, msg): #print "synch starting new sync" self.start_timer() # get input meta = pmt.car(msg) samples = pmt.cdr(msg) x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) self.diff_timer("get_input") # correct for CFO eqBurst = self.qpskBurstCFOCorrect(x, self.Fs) self.diff_timer("cfo") # determine preamble start preCrossCorr = numpy.absolute( numpy.correlate(self.preSyms_x2, eqBurst, 'full')) maxIdx = numpy.argmax(preCrossCorr) preambleIdxStart = len(eqBurst) - maxIdx - 1 eqIn = eqBurst[preambleIdxStart:] # decimate the signal to 1sps (right now the constructor enforces teh 2 sps) eqIn_decimated = eqIn[0:len(eqIn):2] self.diff_timer("timing") wOpt = self.determineOptimalFilter(eqIn_decimated) self.diff_timer("est_filter") # filter the input signal w/ the optimal filter (in MMSE sense) # todo, do we need to remove the extra syms at the end produced by conv? whFilt = numpy.convolve(wOpt, eqIn_decimated) whFiltMean = numpy.mean(numpy.absolute(whFilt)) whFilt /= whFiltMean self.diff_timer("apply filt") # correct any residual phase offset w/ the 1st order PLL alpha = 0.002 phRecoveredSyms = self.qpskFirstOrderPLL(whFilt, alpha) self.diff_timer("residual phase") # if(self.debugMode): # dictToSave = {} # dictToSave['gr_eqBurst'] = eqBurst # dictToSave['gr_preCrossCorr'] = preCrossCorr # dictToSave['gr_eqIn'] = eqIn # dictToSave['gr_wOpt'] = wOpt # dictToSave['gr_whFilt'] = whFilt # dictToSave['gr_phRecoveredSyms'] = phRecoveredSyms # sio.savemat(self.debugFilename, dictToSave) # publish equalized symbols c = map(lambda i: complex(i), phRecoveredSyms) xcm = pmt.init_c32vector(len(c), c) #xcm = pmt.init_c32vector(phRecoveredSyms.size, map(lambda i: complex(i), phRecoveredSyms)) xcm_cpdu = pmt.cons(meta, xcm) self.message_port_pub(pmt.intern("cpdus"), xcm_cpdu) self.diff_timer("publish result") self.burstidx = self.burstidx + 1
def sched_pdu(self, pdu): # always schedule on a multiple of slot_length (because we can?) sched_time = int((self.nproduced_val + self.min_gap) / self.slot_length) * self.slot_length pdu = pdu_arg_add(pdu, pmt.intern("event_time"), pmt.from_uint64(sched_time)) self.nproduced_val = self.nproduced_val + len( pmt.c32vector_elements(pmt.cdr(pdu))) self.message_port_pub(pmt.intern("scheduled_pdu"), pdu)
def handler(self, msg): #print "synch starting new sync" self.start_timer(); # get input meta = pmt.car(msg); samples = pmt.cdr(msg); x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) self.diff_timer("get_input"); # correct for CFO eqBurst = self.qpskBurstCFOCorrect(x, self.Fs) self.diff_timer("cfo") # determine preamble start preCrossCorr = numpy.absolute(numpy.correlate(self.preSyms_x2, eqBurst, 'full')) maxIdx = numpy.argmax(preCrossCorr) preambleIdxStart = len(eqBurst) - maxIdx - 1 eqIn = eqBurst[preambleIdxStart:] # decimate the signal to 1sps (right now the constructor enforces teh 2 sps) eqIn_decimated = eqIn[0:len(eqIn):2] self.diff_timer("timing") wOpt = self.determineOptimalFilter(eqIn_decimated) self.diff_timer("est_filter") # filter the input signal w/ the optimal filter (in MMSE sense) # todo, do we need to remove the extra syms at the end produced by conv? whFilt = numpy.convolve(wOpt, eqIn_decimated) whFiltMean = numpy.mean(numpy.absolute(whFilt)) whFilt /= whFiltMean self.diff_timer("apply filt") # correct any residual phase offset w/ the 1st order PLL alpha = 0.002 phRecoveredSyms = self.qpskFirstOrderPLL(whFilt, alpha) self.diff_timer("residual phase") # if(self.debugMode): # dictToSave = {} # dictToSave['gr_eqBurst'] = eqBurst # dictToSave['gr_preCrossCorr'] = preCrossCorr # dictToSave['gr_eqIn'] = eqIn # dictToSave['gr_wOpt'] = wOpt # dictToSave['gr_whFilt'] = whFilt # dictToSave['gr_phRecoveredSyms'] = phRecoveredSyms # sio.savemat(self.debugFilename, dictToSave) # publish equalized symbols c = map(lambda i: complex(i), phRecoveredSyms); xcm = pmt.init_c32vector(len(c), c) #xcm = pmt.init_c32vector(phRecoveredSyms.size, map(lambda i: complex(i), phRecoveredSyms)) xcm_cpdu = pmt.cons(meta,xcm) self.message_port_pub(pmt.intern("cpdus"), xcm_cpdu); self.diff_timer("publish result") self.burstidx = self.burstidx + 1;
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 handle_weights(self, msg): weights = np.conj(pmt.c32vector_elements(msg)) angles = np.array(np.linspace(-90.0, 90.0, 1801), dtype=np.float32) wr = self.weight_response(weights, angles, self.sep_lambda) # print(weights) self.message_port_pub(pmt.intern("plot"), pmt.to_pmt({ "r": wr, "theta": angles }))
def test_half_power(self): self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.HALF_POWER, []) self.debug = blocks.message_debug() self.tb.msg_connect((self.emitter, 'msg'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # original data in_data = np.exp(1j * np.array(np.linspace(0, 1 * np.pi * .02, 20))) i_vec = pmt.init_c32vector(len(in_data), in_data) out_data = [(1 + 0j), (0.9999945 + 0.0033069337j), (0.9999781 + 0.006613831j), (0.99995077 + 0.009920656j), (0.9999125 + 0.013227372j), (0.9998633 + 0.016533945j), (0.9998032 + 0.019840335j), (0.9997321 + 0.02314651j), (0.99965006 + 0.026452431j), (0.99955714 + 0.029758062j), (0.99945325 + 0.03306337j), (0.99933845 + 0.036368314j), (0.99921274 + 0.039672863j), (0.99907607 + 0.042976975j), (0.9989285 + 0.04628062j), (0.99877 + 0.049583755j), (0.99860054 + 0.05288635j), (0.9984202 + 0.056188367j), (0.9982289 + 0.059489768j), (0.9980267 + 0.06279052j)] e_vec = pmt.init_c32vector(len(out_data), out_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(910.6e6)) in_pdu = pmt.cons(meta, i_vec) e_pdu = pmt.cons(meta, e_vec) 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.to_double( 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(abs(rcv_cf - 910.6e6) < 100)
def test_rms(self): self.emitter = pdu_utils.message_emitter() self.cf = fhss_utils.cf_estimate(fhss_utils.RMS, []) self.debug = blocks.message_debug() self.tb.msg_connect((self.emitter, 'msg'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # original data in_data = np.exp(1j * np.array(np.linspace(0, 1 * np.pi * .02, 20))) i_vec = pmt.init_c32vector(len(in_data), in_data) out_data = [(1 + 0j), (0.9999966 + 0.0026077442j), (0.9999864 + 0.0052154697j), (0.9999694 + 0.007823161j), (0.99994564 + 0.010430798j), (0.99991506 + 0.013038365j), (0.99987763 + 0.015645843j), (0.99983346 + 0.018253215j), (0.99978244 + 0.020860463j), (0.9997247 + 0.023467569j), (0.99966 + 0.026074518j), (0.99958867 + 0.028681284j), (0.9995105 + 0.03128786j), (0.9994256 + 0.033894222j), (0.99933374 + 0.03650035j), (0.99923515 + 0.03910623j), (0.9991298 + 0.04171185j), (0.99901766 + 0.044317182j), (0.9988987 + 0.046922214j), (0.9987729 + 0.04952693j)] e_vec = pmt.init_c32vector(len(out_data), out_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(910.6e6)) in_pdu = pmt.cons(meta, i_vec) e_pdu = pmt.cons(meta, e_vec) 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.to_double( 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(abs(rcv_cf - 910.6001e6) < 100)
def test_coerce(self): 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() self.tb.msg_connect((self.emitter, 'msg'), (self.cf, 'in')) self.tb.msg_connect((self.cf, 'out'), (self.debug, 'store')) # original data in_data = np.exp(1j * np.array(np.linspace(0, 10 * np.pi * 2, 20))) i_vec = pmt.init_c32vector(len(in_data), in_data) out_data = [(1 + 0j), (-0.9863691 - 0.16454819j), (0.9458478 + 0.32461047j), (-0.8795409 - 0.47582325j), (0.7892561 + 0.61406416j), (-0.67745465 - 0.7355646j), (0.54718447 + 0.8370121j), (-0.40199703 - 0.915641j), (0.24585037 + 0.9693079j), (-0.083001345 - 0.9965495j), (-0.08211045 + 0.99662334j), (0.24498378 - 0.96952736j), (-0.4011784 + 0.9160001j), (0.5464361 - 0.83750105j), (-0.6767969 + 0.73617005j), (0.78870696 - 0.6147696j), (-0.87911534 + 0.47660938j), (0.94555736 - 0.3254559j), (-0.9862217 + 0.16542989j), (0.9999997 - 0.00089395075j)] e_vec = pmt.init_c32vector(len(out_data), out_data) meta = pmt.make_dict() meta = pmt.dict_add(meta, pmt.intern("sample_rate"), pmt.from_float(1e3)) meta = pmt.dict_add(meta, pmt.intern("center_frequency"), pmt.from_float(910.6e6)) in_pdu = pmt.cons(meta, i_vec) e_pdu = pmt.cons(meta, e_vec) 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 msg_handler(self, pdu): meta = pmt.car(pdu) data = pmt.c32vector_elements(pmt.cdr(pdu)) data = [ d * r for d, r in zip( data, np.exp(1j * np.linspace(0, 2 * np.pi * self.rotate * len(data), len(data)))) ] self.message_port_pub( pmt.intern("out"), pmt.cons(meta, pmt.init_c32vector(len(data), data)))
def handler(self, pdu): meta = pmt.car(pdu) samples = pmt.cdr(pdu) x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) x_pow = numpy.power(x, 2) X2 = numpy.fft.fftshift(numpy.absolute(numpy.fft.fft(x_pow))) f = numpy.linspace(-self.Fs / 2, self.Fs / 2, num=len(x_pow)) #This generates two peaks, find max peak first max_1 = numpy.argmax(X2) cfo_est_1 = f[max_1] #suppress first peak, including +- 10 bins on either side pk1_range = numpy.linspace(max_1 - 10, max_1 + 10, 21) #print pk1_range, max_1 for i in pk1_range: X2[int(i)] = 0 #find second peak max_2 = numpy.argmax(X2) cfo_est_2 = f[max_2] #baud rate should be from to ratelines baud = numpy.absolute(cfo_est_1 - cfo_est_2) #find halfway point between the peaks in frequency (not index) if (cfo_est_2 > cfo_est_1): cfo_est = (cfo_est_1 + baud / 2.0) / 2.0 elif (cfo_est_2 < cfo_est_1): cfo_est = (cfo_est_2 + baud / 2.0) / 2.0 #print cfo_est_1, cfo_est_2, baud, cfo_est #add snr to metadata meta = pmt.dict_add(meta, pmt.intern("cfo_est"), pmt.from_double(cfo_est)) meta = pmt.dict_add(meta, pmt.intern("baud_est"), pmt.from_double(baud)) # perform the frequency correction t0 = numpy.arange(0, len(x), 1) / float(self.Fs) freqCorrVector = numpy.exp(-1j * 2 * numpy.pi * cfo_est * t0) y = numpy.multiply(x, freqCorrVector) x_out = pmt.init_c32vector(len(x), map(lambda i: complex(i), x)) cpdu_original = pmt.cons(meta, x_out) y_out = pmt.init_c32vector(len(y), map(lambda i: complex(i), y)) cpdu_corrected = pmt.cons(meta, y_out) self.message_port_pub(pmt.intern("out"), cpdu_original) self.message_port_pub(pmt.intern("corrected"), cpdu_corrected)
def test_005_c32(self): ''' complex input data, no decimation, even number of taps ''' self.dut = pdu_utils.pdu_fir_filter(1, [.2] * 6) self.connectUp() i_data = [ 1, ] * 10 i_meta = pmt.dict_add(pmt.make_dict(), pmt.intern("sample_rate"), pmt.from_double(100.0)) i_meta = pmt.dict_add(i_meta, pmt.intern("start_time"), pmt.from_double(9.9)) in_pdu = pmt.cons(i_meta, pmt.init_c32vector(len(i_data), i_data)) e_data = [ .6, .8, 1, ] + [ 1.2, ] * 5 + [1, .8, .6] e_meta = pmt.dict_add(pmt.make_dict(), pmt.intern("sample_rate"), pmt.from_double(100.0)) e_meta = pmt.dict_add(e_meta, pmt.intern("start_time"), pmt.from_double(9.895)) e_pdu = pmt.cons(e_meta, pmt.init_c32vector(len(e_data), e_data)) self.tb.start() time.sleep(.01) self.emitter.emit(in_pdu) time.sleep(.1) self.tb.stop() self.tb.wait() #print("test_005:") #print("pdu expected: " + repr(pmt.car(e_pdu))) #print("pdu got: " + repr(pmt.car(self.debug.get_message(0)))) #print("data expected: " + repr(pmt.to_python(pmt.cdr(e_pdu)))) #print("data got: " + repr(pmt.to_python(pmt.cdr(self.debug.get_message(0))))) #print self.assertTrue(pmt.equal(pmt.car(self.debug.get_message(0)), e_meta)) v_diff = np.abs( pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) - np.array(e_data)) / np.abs(e_data) print("Maximum error is", np.max(v_diff)) self.assertTrue(np.max(v_diff) < 0.00001)
def test_006_c32(self): ''' complex input data, complicated input, decimation, and filtering ''' self.dut = pdu_utils.pdu_fir_filter(2, [2.5, 5, 10, 20, 10, 5, 2.5]) self.connectUp() i_data = [ 1j, 1, -1j, -1, ] * 4 i_meta = pmt.dict_add(pmt.make_dict(), pmt.intern("sample_rate"), pmt.from_double(22.2)) i_meta = pmt.dict_add(i_meta, pmt.intern("start_time"), pmt.from_double(0)) in_pdu = pmt.cons(i_meta, pmt.init_c32vector(len(i_data), i_data)) e_data = [ 7.5 + 15.j, 2.5 - 10.j, 10.j, -0 - 10.j, +10.j, -0 - 10.j, +10.j, -2.5 - 15.j ] e_meta = pmt.dict_add(pmt.make_dict(), pmt.intern("start_time"), pmt.from_double(0)) e_meta = pmt.dict_add(e_meta, pmt.intern("sample_rate"), pmt.from_double(11.1)) e_pdu = pmt.cons(e_meta, pmt.init_c32vector(len(e_data), e_data)) self.tb.start() time.sleep(.01) self.emitter.emit(in_pdu) time.sleep(.1) self.tb.stop() self.tb.wait() #print("test_005:") #print("pdu expected: " + repr(pmt.car(e_pdu))) #print("pdu got: " + repr(pmt.car(self.debug.get_message(0)))) #print("data expected: " + repr(pmt.to_python(pmt.cdr(e_pdu)))) #print("data got: " + repr(pmt.to_python(pmt.cdr(self.debug.get_message(0))))) #print self.assertTrue(pmt.equal(pmt.car(self.debug.get_message(0)), e_meta)) v_diff = np.abs( pmt.c32vector_elements(pmt.cdr(self.debug.get_message(0))) - np.array(e_data)) / np.abs(e_data) print("Maximum error is", np.max(v_diff)) self.assertTrue(np.max(v_diff) < 0.0001)
def test_002_simpledfe (self): """ Use the simple DFE equalizer. """ fft_len = 8 # 4 5 6 7 0 1 2 3 tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 -1, -1, 0, 2, -1, 2, 0, -1, # 8 -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) equalizer = digital.ofdm_equalizer_simpledfe( fft_len, cnst.base(), occupied_carriers, pilot_carriers, pilot_symbols, 0, 0.01 ) channel = [ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly... 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 # ...and again here. ] for idx in range(fft_len, 2*fft_len): channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) idx2 = idx+2*fft_len channel[idx2] = channel[idx2] * numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand()-.5)) len_tag_key = "frame_len" len_tag = gr.tag_t() len_tag.offset = 0 len_tag.key = pmt.string_to_symbol(len_tag_key) len_tag.value = pmt.from_long(4) chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") chan_tag.value = pmt.init_c32vector(fft_len, channel[:fft_len]) src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len, (len_tag, chan_tag)) eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, len_tag_key, True) sink = blocks.vector_sink_c(fft_len) self.tb.connect(src, eq, sink) self.tb.run () rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()] self.assertEqual(tx_data, rx_data) for tag in sink.tags(): if pmt.symbol_to_string(tag.key) == len_tag_key: self.assertEqual(pmt.to_long(tag.value), 4) if pmt.symbol_to_string(tag.key) == "ofdm_sync_chan_taps": self.assertComplexTuplesAlmostEqual(list(pmt.c32vector_elements(tag.value)), channel[-fft_len:], places=1)
def handler(self, msg): # Check if msg is c32_vector if not pmt.is_pair(msg): print("Not expected c32 vector type") sizevec = pmt.u32vector_elements(pmt.car(msg)) # print(sizevec) weights = pmt.c32vector_elements(pmt.cdr(msg)) weights = numpy.reshape(weights, sizevec, order='C') # print(weights.shape) # print(weights) # print(weights.tolist()) # print(weights[0]) self.message_port_pub(pmt.intern("A"), pmt.to_pmt(weights.tolist()))
def test23_absolute_serialization_float_uvecs(self): # f32_vector SERDES in_vec = [0x01020304, 2.1, 3.1415, 1e-9] # old serialization (f32 serialized as f64): # in_str = b'\n\x08\x00\x00\x00\x04\x01\x00Ap 0@\x00\x00\x00@\x00\xcc\xcc\xc0\x00\x00\x00@\t!\xca\xc0\x00\x00\x00>\x11.\x0b\xe0\x00\x00\x00' in_str = b'\n\x08\x00\x00\x00\x04\x01\x00K\x81\x01\x82@\x06ff@I\x0eV0\x89p_' out_str = pmt.serialize_str(pmt.init_f32vector(len(in_vec), in_vec)) self.assertEqual(out_str, in_str) # old serialization (f32 serialized as f64): # in_str = b'\n\x08\x00\x00\x00\x04\x01\x00?\xf0\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\xbf\xc0\x00\x00\x00\x00\x00\x00@\xfe$\x00\x00\x00\x00\x00' in_str = b'\n\x08\x00\x00\x00\x04\x01\x00?\x80\x00\x00@\x00\x00\x00\xbe\x00\x00\x00G\xf1 \x00' in_vec = [1., 2., -0.125, 123456.0] out_vec = pmt.f32vector_elements(pmt.deserialize_str(in_str)) self.assertEqual(out_vec, in_vec) # f64_vector SERDES in_vec = [0x010203040506, 2.1, 1e-9] in_str = b'\n\t\x00\x00\x00\x03\x01\x00Bp 0@P`\x00@\x00\xcc\xcc\xcc\xcc\xcc\xcd>\x11.\x0b\xe8&\xd6\x95' out_str = pmt.serialize_str(pmt.init_f64vector(len(in_vec), in_vec)) self.assertEqual(out_str, in_str) in_str = b'\n\t\x00\x00\x00\x04\x01\x00?\xf0\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\xbf\xc0\x00\x00\x00\x00\x00\x00A\x9do4T\x00\x00\x00' in_vec = [1., 2., -0.125, 123456789.0] out_vec = pmt.f64vector_elements(pmt.deserialize_str(in_str)) self.assertEqual(out_vec, in_vec) # c32_vector SERDES in_vec = [0x01020304 - 1j, 3.1415 + 99.99j] # old serialization (c32 serialized as c64): # in_str = b'\n\n\x00\x00\x00\x02\x01\x00Ap 0@\x00\x00\x00\xbf\xf0\x00\x00\x00\x00\x00\x00@\t!\xca\xc0\x00\x00\x00@X\xff\\ \x00\x00\x00' in_str = b'\n\n\x00\x00\x00\x02\x01\x00\xbf\x80\x00\x00K\x81\x01\x82B\xc7\xfa\xe1@I\x0eV' out_str = pmt.serialize_str(pmt.init_c32vector(len(in_vec), in_vec)) self.assertEqual(out_str, in_str) # old serialization (c32 serialized as c64): # in_str = b'\n\n\x00\x00\x00\x02\x01\x00?\xf0\x00\x00\x00\x00\x00\x00?\xf0\x00\x00\x00\x00\x00\x00?\xc0\x00\x00\x00\x00\x00\x00\xc1c\x12\xcf\xe0\x00\x00\x00' in_str = b'\n\n\x00\x00\x00\x02\x01\x00?\x80\x00\x00?\x80\x00\x00\xcb\x18\x96\x7f>\x00\x00\x00' in_vec = [1 + 1j, .125 - 9999999j] out_vec = pmt.c32vector_elements(pmt.deserialize_str(in_str)) self.assertEqual(out_vec, in_vec) # c64_vector SERDES in_vec = [0xffffffff, .9j] in_str = b'\n\x0b\x00\x00\x00\x02\x01\x00A\xef\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xec\xcc\xcc\xcc\xcc\xcc\xcd' out_str = pmt.serialize_str(pmt.init_c64vector(len(in_vec), in_vec)) self.assertEqual(out_str, in_str) in_str = b'\n\x0b\x00\x00\x00\x02\x01\x00?\xf0\x00\x00\x00\x00\x00\x00?\xf0\x00\x00\x00\x00\x00\x00?\xc0\x00\x00\x00\x00\x00\x00\xc1c\x12\xcf\xe0\x00\x00\x00' in_vec = [1 + 1j, .125 - 9999999j] out_vec = pmt.c64vector_elements(pmt.deserialize_str(in_str)) self.assertEqual(out_vec, in_vec)
def handle_weights(self, msg): # weights = np.conj(pmt.c32vector_elements(msg)) sizevec = pmt.u32vector_elements(pmt.car(msg)) # print(sizevec) weights = pmt.c32vector_elements(pmt.cdr(msg)) weights = numpy.reshape(weights, sizevec, order='C') # print(weights.shape) angles = np.array(np.linspace(-180.0, 180.0, 3601), dtype=np.float32) wr = self.weight_response(weights[0], angles, self.sep_lambda) # TODO: make the polar plot do multiple weight vectors # print(weights) self.message_port_pub(pmt.intern("plot"), pmt.to_pmt({ "r": wr, "theta": angles }))
def handler(self, msg): # get input meta = pmt.car(msg) samples = pmt.cdr(msg) x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) # correct for CFO eqBurst = self.qpskBurstCFOCorrect(x, self.Fs) # determine preamble start preCrossCorr = numpy.absolute( numpy.correlate(self.preSyms_x2, eqBurst, 'full')) maxIdx = numpy.argmax(preCrossCorr) preambleIdxStart = len(eqBurst) - maxIdx - 1 eqIn = eqBurst[preambleIdxStart:] # decimate the signal to 1sps (right now the constructor enforces teh 2 sps) eqIn_decimated = eqIn[0:len(eqIn):2] wOpt = self.determineOptimalFilter(eqIn_decimated) # filter the input signal w/ the optimal filter (in MMSE sense) whFilt = signal.lfilter(wOpt, [1], eqIn_decimated) whFiltMean = numpy.mean(numpy.absolute(whFilt)) whFilt /= whFiltMean # correct any residual phase offset w/ the 1st order PLL alpha = 0.002 phRecoveredSyms = self.qpskFirstOrderPLL(whFilt, alpha) if (self.debugMode): dictToSave = {} dictToSave['gr_eqBurst'] = eqBurst dictToSave['gr_preCrossCorr'] = preCrossCorr dictToSave['gr_eqIn'] = eqIn dictToSave['gr_wOpt'] = wOpt dictToSave['gr_whFilt'] = whFilt dictToSave['gr_phRecoveredSyms'] = phRecoveredSyms sio.savemat(self.debugFilename, dictToSave) # publish equalized symbols xcm = pmt.init_c32vector(phRecoveredSyms.size, map(lambda i: complex(i), phRecoveredSyms)) xcm_cpdu = pmt.cons(meta, xcm) self.message_port_pub(pmt.intern("cpdus"), xcm_cpdu)
def handler(self, msg): # get input meta = pmt.car(msg); samples = pmt.cdr(msg); x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) # correct for CFO eqBurst = self.qpskBurstCFOCorrect(x, self.Fs) # determine preamble start preCrossCorr = numpy.absolute(numpy.correlate(self.preSyms_x2, eqBurst, 'full')) maxIdx = numpy.argmax(preCrossCorr) preambleIdxStart = len(eqBurst) - maxIdx - 1 eqIn = eqBurst[preambleIdxStart:] # decimate the signal to 1sps (right now the constructor enforces teh 2 sps) eqIn_decimated = eqIn[0:len(eqIn):2] wOpt = self.determineOptimalFilter(eqIn_decimated) # filter the input signal w/ the optimal filter (in MMSE sense) whFilt = signal.lfilter(wOpt, [1], eqIn_decimated) whFiltMean = numpy.mean(numpy.absolute(whFilt)) whFilt /= whFiltMean # correct any residual phase offset w/ the 1st order PLL alpha = 0.002 phRecoveredSyms = self.qpskFirstOrderPLL(whFilt, alpha) if(self.debugMode): dictToSave = {} dictToSave['gr_eqBurst'] = eqBurst dictToSave['gr_preCrossCorr'] = preCrossCorr dictToSave['gr_eqIn'] = eqIn dictToSave['gr_wOpt'] = wOpt dictToSave['gr_whFilt'] = whFilt dictToSave['gr_phRecoveredSyms'] = phRecoveredSyms sio.savemat(self.debugFilename, dictToSave) # publish equalized symbols xcm = pmt.init_c32vector(phRecoveredSyms.size, map(lambda i: complex(i), phRecoveredSyms)) xcm_cpdu = pmt.cons(meta,xcm) self.message_port_pub(pmt.intern("cpdus"), xcm_cpdu);
def handler(self, msg): meta = pmt.car(msg); samples = pmt.cdr(msg); x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) x_2 = numpy.real(x * x.conjugate()) # smoothing filter x_2f = numpy.convolve(50*[1], x_2); # find max power to compute power thresh maxidx = numpy.argmax(x_2f); maxpow = x_2f[maxidx]; thr = maxpow / 16; # 6db down # find where we are below thresh start_offset = 1000; idx = numpy.argmax(x_2f[start_offset:] < thr) + start_offset + 1000; # print "below = (%d, %f)"%(idx, x_2f[idx]) # discard bursts where we dont find an end if idx == start_offset: print "WARNING: length detect: discarding burst" return # tack on some metadata meta = pmt.dict_add(meta, pmt.intern("est_len"), pmt.from_double(int(idx))); meta = pmt.dict_add(meta, pmt.intern("orig_len"), pmt.from_double(len(x))); # extract the useful signal x = x[0:idx]; # send it on its way samples_out = pmt.init_c32vector(len(x), map(lambda i: complex(i), x)) cpdu = pmt.cons(meta,samples_out) self.message_port_pub(pmt.intern("cpdus"), cpdu);
def test_002_static (self): """ - Add a simple channel - Make symbols QPSK """ fft_len = 8 # 4 5 6 7 0 1 2 3 tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 -1, -1, 0, 2, -1, 2, 0, -1, # 8 -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) equalizer = digital.ofdm_equalizer_static(fft_len, occupied_carriers, pilot_carriers, pilot_symbols) channel = [ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly (but less than \pi/2) 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 ] channel = [ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly (but less than \pi/2) 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 ] for idx in range(fft_len, 2*fft_len): channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") chan_tag.value = pmt.init_c32vector(fft_len, channel[:fft_len]) src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len, (chan_tag,)) sink = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key, True) self.tb.connect( src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key), eq, sink ) self.tb.run () rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()[0]] # Check data self.assertEqual(tx_data, rx_data) # Check tags tag_dict = dict() for tag in sink.tags(): ptag = gr.tag_to_python(tag) tag_dict[ptag.key] = ptag.value if ptag.key == 'ofdm_sync_chan_taps': tag_dict[ptag.key] = list(pmt.c32vector_elements(tag.value)) else: tag_dict[ptag.key] = pmt.to_python(tag.value) expected_dict = { 'ofdm_sync_chan_taps': channel[-fft_len:] } self.assertEqual(tag_dict, expected_dict)
def sched_pdu(self, pdu): # always schedule on a multiple of slot_length (because we can?) sched_time = int((self.nproduced_val + self.min_gap)/self.slot_length)*self.slot_length; pdu = pdu_arg_add(pdu, pmt.intern("event_time"), pmt.from_uint64(sched_time)); self.nproduced_val = self.nproduced_val + len(pmt.c32vector_elements(pmt.cdr(pdu))); self.message_port_pub(pmt.intern("scheduled_pdu"), pdu);
def handler(self, msg): # get input meta = pmt.car(msg); samples = pmt.cdr(msg); x = numpy.array(pmt.c32vector_elements(samples), dtype=numpy.complex64) # upsample and normalize power xi = signal.resample(x, len(x)* (self.N / self.T)); # compute the symbol timing xt = numpy.real(xi*xi.conjugate()) * numpy.exp( (-1j*2.0*numpy.pi/self.N) * numpy.linspace(1,len(xi),len(xi)) ); s = numpy.sum(x); tau = (-self.T/(2*numpy.pi)) * numpy.arctan2(numpy.imag(s), numpy.real(s)); # publish timing metric for debugging tm = pmt.init_c32vector(xt.size, map(lambda i: complex(i), xt)) tm_cpdu = pmt.cons(meta,tm) self.message_port_pub(pmt.intern("timing_metric"), tm_cpdu); # extract symbols offset = round(self.N*tau/self.T); fo = (offset + self.N)%self.N; sym = xi[fo:-1:self.N]; # normalize power to 1 sym = sym / numpy.mean(numpy.real(sym * sym.conjugate())); # publish timing correct symbols (with frequency offset) sm = pmt.init_c32vector(sym.size, map(lambda i: complex(i), sym)) sm_cpdu = pmt.cons(meta,sm) self.message_port_pub(pmt.intern("sym_timed"), sm_cpdu); # compute symbol frequency offset (linear phase offset within block) x_n = numpy.power(sym[200:1000], self.O); phase_ramp = numpy.unwrap(numpy.angle( x_n )); f_off_O = numpy.mean(numpy.diff(phase_ramp)); goodstat = numpy.std(numpy.diff(phase_ramp)); f_off = f_off_O / self.O; # check percentages self.nburst = self.nburst + 1; if(goodstat < 1.0): self.nburst_ok = self.nburst_ok + 1; else: print "WARNING: feedforward synchronizer discarding burst, goodness metric %f < 1.0 (likely poor timing recovery occurred, the CFO phase ramp looks like garbage)"%(goodstat) return print "sync: "+str((goodstat, self.nburst, self.nburst_ok, self.nburst_ok*100.0 / self.nburst)); # export phase ramp pr = pmt.init_f32vector(phase_ramp.size, map(lambda i: float(i), phase_ramp)) pr_fpdu = pmt.cons(meta,pr) self.message_port_pub(pmt.intern("phase_ramp"), pr_fpdu); # apply frequency offset correction xc = numpy.multiply(sym, numpy.exp(-1j * f_off * numpy.linspace(1,sym.size,sym.size))); # compute and correct static symbol phase offset xcp = numpy.power(xc[400:1000], self.O); # linear mean theta = numpy.mean( numpy.angle( xcp ) ) / self.O + numpy.pi/4; # weighted mean # theta = numpy.sum(numpy.angle(xcp) * numpy.abs(xcp)) / numpy.sum(numpy.abs(xcp)); # theta = theta / self.O + numpy.pi/4; xc = xc * numpy.exp(-1j*theta); # show time, frequency and phase estimates #print "tau = %f, f_off = %f, theta = %f"%(tau, f_off, theta); # add our estimates to the metadata dictionary meta = pmt.dict_add(meta, pmt.intern("tau"), pmt.from_double(tau)); meta = pmt.dict_add(meta, pmt.intern("f_off"), pmt.from_double(f_off)); meta = pmt.dict_add(meta, pmt.intern("theta"), pmt.from_double(theta)); # publish freq corrected symbols xcm = pmt.init_c32vector(xc.size, map(lambda i: complex(i), xc)) xcm_cpdu = pmt.cons(meta,xcm) self.message_port_pub(pmt.intern("cpdus"), xcm_cpdu);