def test_descriptor_001(self): src_data = range(1000) expected_result = range(1000) filename = "tmp.32f" fhandle0 = open(filename, "wb") fd0 = fhandle0.fileno() src = blocks.vector_source_f(src_data) snk = blocks.file_descriptor_sink(gr.sizeof_float, fd0) self.tb.connect(src, snk) self.tb.run() os.fsync(fd0) fhandle0.close() fhandle1 = open(filename, "rb") fd1 = fhandle1.fileno() src2 = blocks.file_descriptor_source(gr.sizeof_float, fd1, False) snk2 = blocks.vector_sink_f() self.tb.disconnect(src, snk) self.tb.connect(src2, snk2) self.tb.run() os.fsync(fd1) fhandle1.close() os.remove(filename) result_data = snk2.data() self.assertFloatTuplesAlmostEqual(expected_result, result_data)
def test_file_descriptor(self): src_data = range(1000) expected_result = range(1000) snk2 = blocks.vector_sink_f() with tempfile.NamedTemporaryFile() as temp: fhandle0 = open(temp.name, "wb") fd0 = fhandle0.fileno() src = blocks.vector_source_f(src_data) snk = blocks.file_descriptor_sink(gr.sizeof_float, fd0) self.tb.connect(src, snk) self.tb.run() os.fsync(fd0) fhandle0.close() fhandle1 = open(temp.name, "rb") fd1 = fhandle1.fileno() src2 = blocks.file_descriptor_source(gr.sizeof_float, fd1, False) self.tb.disconnect(src, snk) self.tb.connect(src2, snk2) self.tb.run() os.fsync(fd1) fhandle1.close() result_data = snk2.data() self.assertFloatTuplesAlmostEqual(expected_result, result_data) self.assertEqual(len(snk2.tags()), 0)
def init_audio(self, config): filename = config['args'].replace('audio:', '') if filename.startswith('file:'): filename = filename.replace('file:', '') repeat = False s2f = blocks.short_to_float() K = 1 / 32767.0 src = blocks.multiply_const_ff(K) throttle = blocks.throttle( gr.sizeof_short, self.sample_rate) # may be redundant in stdin case ? if filename == '-': fd = 0 # stdin fsrc = blocks.file_descriptor_source(gr.sizeof_short, fd, repeat) else: fsrc = blocks.file_source(gr.sizeof_short, filename, repeat) self.tb.connect(fsrc, throttle, s2f, src) else: src = audio.source(self.sample_rate, filename) gain = 1.0 if config['gains'].startswith('audio:'): gain = float(config['gains'].replace('audio:', '')) self.src = blocks.multiply_const_ff(gain) self.tb.connect(src, self.src)
def __init__(self, itemsize, addr, port, server=True): # init hier block gr.hier_block2.__init__( self, 'tcp_source', gr.io_signature(0, 0, 0), gr.io_signature(1, 1, itemsize), ) fd = _get_sock_fd(addr, port, server) self.connect(blocks.file_descriptor_source(itemsize, fd), self)
def __init__(self, itemsize, addr, port, server=True): #init hier block gr.hier_block2.__init__( self, 'tcp_source', gr.io_signature(0, 0, 0), gr.io_signature(1, 1, itemsize), ) fd = _get_sock_fd(addr, port, server) self.connect(blocks.file_descriptor_source(itemsize, fd), self)
def test_file_descriptor_source(): tmp_f = tempfile.TemporaryFile() array.array('f', [random.random() for _ in range(262144)]).tofile(tmp_f) tmp_f.seek(0) top = gr.top_block() src = blocks.file_descriptor_source(gr.sizeof_float, os.dup(tmp_f.fileno()), True) probe = blocks.probe_rate(gr.sizeof_float) top.connect(src, probe) return top, probe
def __init__(self, addr, port, rate, freq1, freq2, corr): gr.hier_block2.__init__( self, name = "red_pitaya_source", input_signature = gr.io_signature(0, 0, 0), output_signature = gr.io_signature(1, 1, gr.sizeof_gr_complex) ) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((addr, port)) fd = os.dup(self.sock.fileno()) self.connect(blocks.file_descriptor_source(gr.sizeof_gr_complex, fd), self) self.set_rate(rate) self.set_freq1(freq1, corr) self.set_freq2(freq2, corr)
def __init__(self, addr, port, freq, corr): gr.hier_block2.__init__(self, name="red_pitaya_source", input_signature=gr.io_signature(0, 0, 0), output_signature=gr.io_signature( 1, 1, gr.sizeof_gr_complex)) self.ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.ctrl_sock.connect((addr, port)) self.ctrl_sock.send(struct.pack('<I', 0)) self.data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.data_sock.connect((addr, port)) self.data_sock.send(struct.pack('<I', 1)) fd = os.dup(self.data_sock.fileno()) self.connect(blocks.file_descriptor_source(gr.sizeof_gr_complex, fd), self) self.set_freq(freq, corr)
def __init__(self, addr, port, freq, corr): gr.hier_block2.__init__( self, name = "red_pitaya_source", input_signature = gr.io_signature(0, 0, 0), output_signature = gr.io_signature(1, 1, gr.sizeof_gr_complex) ) self.ctrl_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.ctrl_sock.connect((addr, port)) self.ctrl_sock.send(struct.pack('<I', 0)) self.data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.data_sock.connect((addr, port)) self.data_sock.send(struct.pack('<I', 1)) fd = os.dup(self.data_sock.fileno()) self.connect(blocks.file_descriptor_source(gr.sizeof_gr_complex, fd), self) self.set_freq(freq, corr)
def _tcp_client(self): dst = blocks.vector_sink_s() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) for t in (0, 0.2): # wait until server listens sleep(t) try: sock.connect((self.addr, self.port)) except socket.error as e: if e.errno != 111: raise continue break fd = os.dup(sock.fileno()) self.tb_rcv.connect(blocks.file_descriptor_source(self.itemsize, fd), dst) self.tb_rcv.run() self.assertEqual(self.data, dst.data())
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Dvbc Tx Wxgui") _icon_path = "/usr/share/icons/hicolor/32x32/apps/gnuradio-grc.png" self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY)) ################################################## # Variables ################################################## self._symrate_config = ConfigParser.ConfigParser() self._symrate_config.read('./dvbc.conf') try: symrate = self._symrate_config.getint('dvbc', 'symbolrate') except: symrate = 0 self.symrate = symrate self._mode_config = ConfigParser.ConfigParser() self._mode_config.read('./dvbc.conf') try: mode = self._mode_config.get('dvbc', 'mode') except: mode = 0 self.mode = mode self._center_freq_config = ConfigParser.ConfigParser() self._center_freq_config.read('./dvbc.conf') try: center_freq = self._center_freq_config.getint( 'hackrf', 'frequency') except: center_freq = 0 self.center_freq = center_freq self.samp_rate = samp_rate = symrate * 2 self.rrc_taps = rrc_taps = 100 self._rf_gain_config = ConfigParser.ConfigParser() self._rf_gain_config.read('./dvbc.conf') try: rf_gain = self._rf_gain_config.getint('hackrf', 'rf-gain') except: rf_gain = 0 self.rf_gain = rf_gain self._if_gain_config = ConfigParser.ConfigParser() self._if_gain_config.read('./dvbc.conf') try: if_gain = self._if_gain_config.getint('hackrf', 'if-gain') except: if_gain = 0 self.if_gain = if_gain self.anz0 = anz0 = str( center_freq / 1000000) + "MHZ / " + mode + " / " + str( symrate / 1000) + " kSym/s" infile = str(sys.argv[1]) if mode == "16QAM": mod = dvbc.MOD_16QAM elif mode == "32QAM": mod = dvbc.MOD_32QAM elif mode == "64QAM": mod = dvbc.MOD_64QAM elif mode == "128QAM": mod = dvbc.MOD_128QAM elif mode == "256QAM": mod = dvbc.MOD_256QAM else: sys.stderr.write( "MODE IN CONFIG WRONG! Values: 16QAM, 32QAM, 64QAM, 128QAM or 256QAM \n" ) sys.exit(1) print "Frequency: ", center_freq / 1000000, "Mhz / Mode: ", mode, "/ Symbolrate: ", symrate / 1000, "\n" ################################################## # Blocks ################################################## self.wxgui_fftsink2_0 = fftsink2.fft_sink_c( self.GetWin(), baseband_freq=center_freq, y_per_div=10, y_divs=10, ref_level=0, ref_scale=2.0, sample_rate=samp_rate, fft_size=1024, fft_rate=15, average=False, avg_alpha=None, title='FFT Plot', peak_hold=False, ) self.Add(self.wxgui_fftsink2_0.win) self.osmosdr_sink_1 = osmosdr.sink(args="numchan=" + str(1) + " " + 'hackrf,buffers=128,buflen=32768') self.osmosdr_sink_1.set_sample_rate(samp_rate) self.osmosdr_sink_1.set_center_freq(center_freq, 0) self.osmosdr_sink_1.set_freq_corr(0, 0) self.osmosdr_sink_1.set_gain(rf_gain, 0) self.osmosdr_sink_1.set_if_gain(if_gain, 0) self.osmosdr_sink_1.set_bb_gain(0, 0) self.osmosdr_sink_1.set_antenna('', 0) self.osmosdr_sink_1.set_bandwidth(8750000, 0) self.fft_filter_xxx_0 = filter.fft_filter_ccc( 1, (firdes.root_raised_cosine(0.85, samp_rate, samp_rate / 2, 0.15, rrc_taps)), 1) self.fft_filter_xxx_0.declare_sample_delay(0) self.dvbc_symbolmapper_bb_0 = dvbc.symbolmapper_bb(mod) self.dvbc_modulator_bc_0 = dvbc.modulator_bc(mod) self.dtv_dvbt_reed_solomon_enc_0 = dtv.dvbt_reed_solomon_enc( 2, 8, 0x11d, 255, 239, 8, 51, 8) self.dtv_dvbt_energy_dispersal_0 = dtv.dvbt_energy_dispersal(1) self.dtv_dvbt_convolutional_interleaver_0 = dtv.dvbt_convolutional_interleaver( 136, 12, 17) if infile == "-": self.blocks_file_descriptor_source_0 = blocks.file_descriptor_source( gr.sizeof_char * 1, 0, True) else: self.blocks_file_source_0 = blocks.file_source( gr.sizeof_char * 1, infile, True) self._anz0_static_text = forms.static_text( parent=self.GetWin(), value=self.anz0, callback=self.set_anz0, label='Parameter', converter=forms.str_converter(), ) self.Add(self._anz0_static_text) ################################################## # Connections ################################################## if infile == "-": self.connect((self.blocks_file_descriptor_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) else: self.connect((self.blocks_file_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) self.connect((self.dtv_dvbt_convolutional_interleaver_0, 0), (self.dvbc_symbolmapper_bb_0, 0)) self.connect((self.dtv_dvbt_energy_dispersal_0, 0), (self.dtv_dvbt_reed_solomon_enc_0, 0)) self.connect((self.dtv_dvbt_reed_solomon_enc_0, 0), (self.dtv_dvbt_convolutional_interleaver_0, 0)) self.connect((self.dvbc_modulator_bc_0, 0), (self.fft_filter_xxx_0, 0)) self.connect((self.dvbc_symbolmapper_bb_0, 0), (self.dvbc_modulator_bc_0, 0)) self.connect((self.fft_filter_xxx_0, 0), (self.osmosdr_sink_1, 0)) self.connect((self.fft_filter_xxx_0, 0), (self.wxgui_fftsink2_0, 0))
def __init__(self): gr.top_block.__init__(self, "Dvbt2 Master") ################################################## # Variables ################################################## self.samp_rate = samp_rate = (8000000.0 * 8) / 7 self._rf_gain_config = ConfigParser.ConfigParser() self._rf_gain_config.read('./dvbt2.conf') try: rf_gain = self._rf_gain_config.getint('hackrf', 'rf-gain') except: rf_gain = 0 self.rf_gain = rf_gain self._if_gain_config = ConfigParser.ConfigParser() self._if_gain_config.read('./dvbt2.conf') try: if_gain = self._if_gain_config.getint('hackrf', 'if-gain') except: if_gain = 0 self.if_gain = if_gain self._center_freq_config = ConfigParser.ConfigParser() self._center_freq_config.read('./dvbt2.conf') try: center_freq = self._center_freq_config.getint( 'hackrf', 'frequency') except: center_freq = 0 self.center_freq = center_freq self._band_width_config = ConfigParser.ConfigParser() self._band_width_config.read('./dvbt2.conf') try: band_width = self._band_width_config.getint('hackrf', 'bandwidth') except: band_width = 0 self.band_width = band_width self._VERSION_config = ConfigParser.ConfigParser() self._VERSION_config.read('./dvbt2.conf') try: VERSION = self._VERSION_config.getint('dvbt2', 'version') except: VERSION = 0 self.VERSION = VERSION self._PREAMBLE_config = ConfigParser.ConfigParser() self._PREAMBLE_config.read('./dvbt2.conf') try: PREAMBLE = self._PREAMBLE_config.get('dvbt2', 'preamble') except: PREAMBLE = '0' self.PREAMBLE = PREAMBLE self._PILOT_config = ConfigParser.ConfigParser() self._PILOT_config.read('./dvbt2.conf') try: PILOT = self._PILOT_config.getint('dvbt2', 'pilot-pattern') except: PILOT = 0 self.PILOT = PILOT self._PAPR_config = ConfigParser.ConfigParser() self._PAPR_config.read('./dvbt2.conf') try: PAPR = self._PAPR_config.get('dvbt2', 'papr') except: PAPR = '0' self.PAPR = PAPR self._L1MOD_config = ConfigParser.ConfigParser() self._L1MOD_config.read('./dvbt2.conf') try: L1MOD = self._L1MOD_config.get('dvbt2', 'L1-mod') except: L1MOD = '0' self.L1MOD = L1MOD self._GI_config = ConfigParser.ConfigParser() self._GI_config.read('./dvbt2.conf') try: GI = self._GI_config.get('dvbt2', 'guard-interval') except: GI = '0' self.GI = GI self._FFTSIZE_config = ConfigParser.ConfigParser() self._FFTSIZE_config.read('./dvbt2.conf') try: FFTSIZE = self._FFTSIZE_config.get('dvbt2', 'fft-size') except: FFTSIZE = '0' self.FFTSIZE = FFTSIZE self._FECBLKS_config = ConfigParser.ConfigParser() self._FECBLKS_config.read('./dvbt2.conf') try: FECBLKS = self._FECBLKS_config.getint('dvbt2', 'fec-blocks') except: FECBLKS = 0 self.FECBLKS = FECBLKS self._DATASYM_config = ConfigParser.ConfigParser() self._DATASYM_config.read('./dvbt2.conf') try: DATASYM = self._DATASYM_config.getint('dvbt2', 'datasymbols') except: DATASYM = 0 self.DATASYM = DATASYM self._CONSTELLATION_config = ConfigParser.ConfigParser() self._CONSTELLATION_config.read('./dvbt2.conf') try: CONSTELLATION = self._CONSTELLATION_config.get( 'dvbt2', 'constellation') except: CONSTELLATION = '0' self.CONSTELLATION = CONSTELLATION self._CODERATE_config = ConfigParser.ConfigParser() self._CODERATE_config.read('./dvbt2.conf') try: CODERATE = self._CODERATE_config.get('dvbt2', 'coderate') except: CODERATE = '0' self.CODERATE = CODERATE self._CARREXT_config = ConfigParser.ConfigParser() self._CARREXT_config.read('./dvbt2.conf') try: CARREXT = self._CARREXT_config.get('dvbt2', 'ext-carriers') except: CARREXT = '0' self.CARREXT = CARREXT infile = str(sys.argv[1]) if VERSION == 111: ver = dtv.VERSION_111 elif VERSION == 131: ver = dtv.VERSION_131 else: sys.stderr.write("VERSION IN CONFIG WRONG! Values: 111 or 131 \n") sys.exit(1) if PREAMBLE == "SISO": preamb = dtv.PREAMBLE_T2_SISO elif PREAMBLE == "MISO": preamb = dtv.PREAMBLE_T2_MISO else: sys.stderr.write( "PREAMBLE IN CONFIG WRONG! Values: SISO or MISO \n") sys.exit(1) if PILOT == 1: pil = dtv.PILOT_PP1 elif PILOT == 2: pil = dtv.PILOT_PP2 elif PILOT == 3: pil = dtv.PILOT_PP3 elif PILOT == 4: pil = dtv.PILOT_PP4 elif PILOT == 5: pil = dtv.PILOT_PP5 elif PILOT == 6: pil = dtv.PILOT_PP6 elif PILOT == 7: pil = dtv.PILOT_PP7 elif PILOT == 8: pil = dtv.PILOT_PP8 else: sys.stderr.write( "PILOT-PATTERN IN CONFIG WRONG! Values: 1, 2, 3, 4, 5, 6, 7 or 8 \n" ) sys.exit(1) if PAPR == "on": pap = dtv.PAPR_ON elif PAPR == "off": pap = dtv.PAPR_OFF else: sys.stderr.write("PAPR IN CONFIG WRONG! Values: on or off \n") sys.exit(1) if L1MOD == "QPSK": l1m = dtv.L1_MOD_QPSK elif L1MOD == "BPSK": l1m = dtv.L1_MOD_BPSK elif L1MOD == "16QAM": l1m = dtv.L1_MOD_16QAM elif L1MOD == "64QAM": l1m = dtv.L1_MOD_64QAM else: sys.stderr.write( "L1-MOD IN CONFIG WRONG! Values: QPSK, BPSK, 16QAM or 64QAM \n" ) sys.exit(1) if GI == "1/32": gint = dtv.GI_1_32 mul = 1 div = 32 elif GI == "1/16": gint = dtv.GI_1_16 mul = 1 div = 16 elif GI == "1/8": gint = dtv.GI_1_8 mul = 1 div = 8 elif GI == "1/4": gint = dtv.GI_1_4 mul = 1 div = 4 elif GI == "1/128": gint = dtv.GI_1_128 mul = 1 div = 128 elif GI == "19/128": gint = dtv.GI_19_128 mul = 19 div = 128 elif GI == "19/256": gint = dtv.GI_19_256 mul = 19 div = 256 else: sys.stderr.write( "GUARD-INTERVAL IN CONFIG WRONG! Values: 1/32, 1/16, 1/8, 1/4, 1/128, 19/128, 19/256 \n" ) sys.exit(1) if FFTSIZE == "16k": ffts = dtv.FFTSIZE_16K fft_length = 16384 elif FFTSIZE == "32k": ffts = dtv.FFTSIZE_32K fft_length = 32768 else: sys.stderr.write("FFTSIZE IN CONFIG WRONG! Values: 16k or 32k \n") sys.exit(1) if CONSTELLATION == "QPSK": const = dtv.MOD_QPSK elif CONSTELLATION == "16QAM": const = dtv.MOD_16QAM elif CONSTELLATION == "64QAM": const = dtv.MOD_64QAM elif CONSTELLATION == "256QAM": const = dtv.MOD_256QAM else: sys.stderr.write( "CONSTELLATION IN CONFIG WRONG! Values: QPSK 16QAM 64QAM 256QAM \n" ) sys.exit(1) if CODERATE == "1/2": codr = dtv.C1_2 elif CODERATE == "2/5": codr = dtv.C2_5 elif CODERATE == "3/5": codr = dtv.C3_5 elif CODERATE == "2/3": codr = dtv.C2_3 elif CODERATE == "3/4": codr = dtv.C3_4 elif CODERATE == "4/5": codr = dtv.C4_5 elif CODERATE == "5/6": codr = dtv.C5_6 else: sys.stderr.write( "CODERATE IN CONFIG WRONG! Values: 1/2 2/5 3/5 2/3 3/4 4/5 5/6 \n" ) sys.exit(1) if CARREXT == "on": extcarr = dtv.CARRIERS_EXTENDED elif CARREXT == "off": extcarr = dtv.CARRIERS_NORMAL else: sys.stderr.write( "EXT-CARRIERS IN CONFIG WRONG! Values: on or off \n") sys.exit(1) cp_length = fft_length + (fft_length * mul) / div ################################################## # Blocks ################################################## self.osmosdr_sink_0 = osmosdr.sink(args="numchan=" + str(1) + " " + 'hackrf,buffers=128,buflen=32768') self.osmosdr_sink_0.set_sample_rate(samp_rate) self.osmosdr_sink_0.set_center_freq(center_freq, 0) self.osmosdr_sink_0.set_freq_corr(0, 0) self.osmosdr_sink_0.set_gain(rf_gain, 0) self.osmosdr_sink_0.set_if_gain(if_gain, 0) self.osmosdr_sink_0.set_bb_gain(0, 0) self.osmosdr_sink_0.set_antenna('', 0) self.osmosdr_sink_0.set_bandwidth(band_width, 0) self.dtv_dvbt2_pilotgenerator_cc_0 = dtv.dvbt2_pilotgenerator_cc( extcarr, ffts, pil, gint, DATASYM, pap, ver, preamb, dtv.MISO_TX1, dtv.EQUALIZATION_OFF, dtv.BANDWIDTH_8_0_MHZ, fft_length) self.dtv_dvbt2_p1insertion_cc_0 = dtv.dvbt2_p1insertion_cc( extcarr, ffts, gint, DATASYM, preamb, dtv.SHOWLEVELS_OFF, 3.3) self.dtv_dvbt2_modulator_bc_0 = dtv.dvbt2_modulator_bc( dtv.FECFRAME_NORMAL, const, dtv.ROTATION_OFF) self.dtv_dvbt2_interleaver_bb_0 = dtv.dvbt2_interleaver_bb( dtv.FECFRAME_NORMAL, codr, const) self.dtv_dvbt2_freqinterleaver_cc_0 = dtv.dvbt2_freqinterleaver_cc( extcarr, ffts, pil, gint, DATASYM, pap, ver, preamb) self.dtv_dvbt2_framemapper_cc_0 = dtv.dvbt2_framemapper_cc( dtv.FECFRAME_NORMAL, codr, const, dtv.ROTATION_OFF, FECBLKS, 3, extcarr, ffts, gint, l1m, pil, 2, DATASYM, pap, ver, preamb, dtv.INPUTMODE_NORMAL, dtv.RESERVED_OFF, dtv.L1_SCRAMBLED_OFF, dtv.INBAND_OFF) self.dtv_dvbt2_cellinterleaver_cc_0 = dtv.dvbt2_cellinterleaver_cc( dtv.FECFRAME_NORMAL, const, FECBLKS, 3) self.dtv_dvb_ldpc_bb_0 = dtv.dvb_ldpc_bb(dtv.STANDARD_DVBT2, dtv.FECFRAME_NORMAL, codr, dtv.MOD_OTHER) self.dtv_dvb_bch_bb_0 = dtv.dvb_bch_bb(dtv.STANDARD_DVBT2, dtv.FECFRAME_NORMAL, codr) self.dtv_dvb_bbscrambler_bb_0 = dtv.dvb_bbscrambler_bb( dtv.STANDARD_DVBT2, dtv.FECFRAME_NORMAL, codr) self.dtv_dvb_bbheader_bb_0 = dtv.dvb_bbheader_bb( dtv.STANDARD_DVBT2, dtv.FECFRAME_NORMAL, codr, dtv.RO_0_35, dtv.INPUTMODE_HIEFF, dtv.INBAND_OFF, 168, 4000000) self.digital_ofdm_cyclic_prefixer_0 = digital.ofdm_cyclic_prefixer( fft_length, cp_length, 0, '') self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc((0.2, )) if infile == "-": self.blocks_file_descriptor_source_0 = blocks.file_descriptor_source( gr.sizeof_char * 1, 0, True) else: self.blocks_file_source_0 = blocks.file_source( gr.sizeof_char * 1, infile, True) ################################################## # Connections ################################################## if infile == "-": self.connect((self.blocks_file_descriptor_source_0, 0), (self.dtv_dvb_bbheader_bb_0, 0)) else: self.connect((self.blocks_file_source_0, 0), (self.dtv_dvb_bbheader_bb_0, 0)) self.connect((self.blocks_multiply_const_vxx_0, 0), (self.osmosdr_sink_0, 0)) self.connect((self.digital_ofdm_cyclic_prefixer_0, 0), (self.dtv_dvbt2_p1insertion_cc_0, 0)) self.connect((self.dtv_dvb_bbheader_bb_0, 0), (self.dtv_dvb_bbscrambler_bb_0, 0)) self.connect((self.dtv_dvb_bbscrambler_bb_0, 0), (self.dtv_dvb_bch_bb_0, 0)) self.connect((self.dtv_dvb_bch_bb_0, 0), (self.dtv_dvb_ldpc_bb_0, 0)) self.connect((self.dtv_dvb_ldpc_bb_0, 0), (self.dtv_dvbt2_interleaver_bb_0, 0)) self.connect((self.dtv_dvbt2_cellinterleaver_cc_0, 0), (self.dtv_dvbt2_framemapper_cc_0, 0)) self.connect((self.dtv_dvbt2_framemapper_cc_0, 0), (self.dtv_dvbt2_freqinterleaver_cc_0, 0)) self.connect((self.dtv_dvbt2_freqinterleaver_cc_0, 0), (self.dtv_dvbt2_pilotgenerator_cc_0, 0)) self.connect((self.dtv_dvbt2_interleaver_bb_0, 0), (self.dtv_dvbt2_modulator_bc_0, 0)) self.connect((self.dtv_dvbt2_modulator_bc_0, 0), (self.dtv_dvbt2_cellinterleaver_cc_0, 0)) self.connect((self.dtv_dvbt2_p1insertion_cc_0, 0), (self.blocks_multiply_const_vxx_0, 0)) self.connect((self.dtv_dvbt2_pilotgenerator_cc_0, 0), (self.digital_ofdm_cyclic_prefixer_0, 0))
def __init__(self): gr.top_block.__init__(self, "Dvbt Tx") ################################################## # Variables ################################################## self._bandwidth_config = ConfigParser.ConfigParser() self._bandwidth_config.read('./dvbt.conf') try: bandwidth = self._bandwidth_config.getint('dvbt', 'bandwidth') except: bandwidth = 8000000 self.bandwidth = bandwidth self.samp_rate = samp_rate = (bandwidth / 7) * 8 self._rf_gain_config = ConfigParser.ConfigParser() self._rf_gain_config.read('./dvbt.conf') try: rf_gain = self._rf_gain_config.getint('hackrf', 'rf_gain') except: rf_gain = 0 self.rf_gain = rf_gain self._mode_config = ConfigParser.ConfigParser() self._mode_config.read('./dvbt.conf') try: mode = self._mode_config.get('dvbt', 'mode') except: mode = 0 self.mode = mode self._if_gain_config = ConfigParser.ConfigParser() self._if_gain_config.read('./dvbt.conf') try: if_gain = self._if_gain_config.getint('hackrf', 'if_gain') except: if_gain = 0 self.if_gain = if_gain self._guard_interval_config = ConfigParser.ConfigParser() self._guard_interval_config.read('./dvbt.conf') try: guard_interval = self._guard_interval_config.get( 'dvbt', 'guard_interval') except: guard_interval = 0 self.guard_interval = guard_interval self._frequency_config = ConfigParser.ConfigParser() self._frequency_config.read('./dvbt.conf') try: frequency = self._frequency_config.getint('hackrf', 'frequency') except: frequency = 858000000 self.frequency = frequency self._constellation_config = ConfigParser.ConfigParser() self._constellation_config.read('./dvbt.conf') try: constellation = self._constellation_config.get( 'dvbt', 'constellation') except: constellation = 0 self.constellation = constellation self._coderate_config = ConfigParser.ConfigParser() self._coderate_config.read('./dvbt.conf') try: coderate = self._coderate_config.get('dvbt', 'coderate') except: coderate = 0 self.coderate = coderate infile = str(sys.argv[1]) #Constellation QPSK 16QAM 64QAM if constellation == "QPSK": const = dtv.MOD_QPSK elif constellation == "16QAM": const = dtv.MOD_16QAM elif constellation == "64QAM": const = dtv.MOD_64QAM else: sys.stderr.write( "CONSTELLATION IN CONFIG WRONG! Values: QPSK, 16QAM or 64QAM \n" ) sys.exit(1) # Coderate 1/2 2/3 3/4 5/6 7/8 if coderate == "1/2": codr = dtv.C1_2 elif coderate == "2/3": codr = dtv.C2_3 elif coderate == "3/4": codr = dtv.C3_4 elif coderate == "5/6": codr = dtv.C5_6 elif coderate == "7/8": codr = dtv.C7_8 else: sys.stderr.write( "CODERATE IN CONFIG WRONG! Values: 1/2, 2/3, 3/4, 5/6 or 7/8 \n" ) sys.exit(1) if mode == "2k": factor = 1 carriers = 2048 modus = dtv.T2k elif mode == "8k": factor = 4 carriers = 8192 modus = dtv.T8k else: sys.stderr.write("MODE IN CONFIG WRONG! Values: 2k or 8k \n") sys.exit(1) #guard_interval dtv.GI_1_32 1/4 1/8 1/16 1/32 if guard_interval == "1/4": guardi = dtv.GI_1_4 gi = carriers / 4 elif guard_interval == "1/8": guardi = dtv.GI_1_8 gi = carriers / 8 elif guard_interval == "1/16": guardi = dtv.GI_1_16 gi = carriers / 16 elif guard_interval == "1/32": guardi = dtv.GI_1_32 gi = carriers / 32 else: sys.stderr.write( "GUARD_INTERVAL IN CONFIG WRONG! Values: 1/4, 1/8, 1/16 or 1/32 \n" ) sys.exit(1) ################################################## # Blocks ################################################## self.osmosdr_sink_0 = osmosdr.sink(args="numchan=" + str(1) + " " + '') self.osmosdr_sink_0.set_sample_rate(samp_rate) self.osmosdr_sink_0.set_center_freq(frequency, 0) self.osmosdr_sink_0.set_freq_corr(0, 0) self.osmosdr_sink_0.set_gain(rf_gain, 0) self.osmosdr_sink_0.set_if_gain(if_gain, 0) self.osmosdr_sink_0.set_bb_gain(0, 0) self.osmosdr_sink_0.set_antenna('', 0) self.osmosdr_sink_0.set_bandwidth(0, 0) self.fft_vxx_0 = fft.fft_vcc(carriers, False, (window.rectangular(carriers)), True, 1) self.dtv_dvbt_symbol_inner_interleaver_0 = dtv.dvbt_symbol_inner_interleaver( (1512 * factor), modus, 1) self.dtv_dvbt_reference_signals_0 = dtv.dvbt_reference_signals( gr.sizeof_gr_complex, (1512 * factor), carriers, const, dtv.NH, codr, codr, guardi, modus, 1, 0) self.dtv_dvbt_reed_solomon_enc_0 = dtv.dvbt_reed_solomon_enc( 2, 8, 0x11d, 255, 239, 8, 51, (8 * factor)) self.dtv_dvbt_map_0 = dtv.dvbt_map((1512 * factor), const, dtv.NH, modus, 1) self.dtv_dvbt_inner_coder_0 = dtv.dvbt_inner_coder( 1, (1512 * factor), const, dtv.NH, codr) self.dtv_dvbt_energy_dispersal_0 = dtv.dvbt_energy_dispersal(1 * factor) self.dtv_dvbt_convolutional_interleaver_0 = dtv.dvbt_convolutional_interleaver( (136 * factor), 12, 17) self.dtv_dvbt_bit_inner_interleaver_0 = dtv.dvbt_bit_inner_interleaver( (1512 * factor), const, dtv.NH, modus) self.digital_ofdm_cyclic_prefixer_0 = digital.ofdm_cyclic_prefixer( carriers, carriers + (gi), 0, '') self.blocks_multiply_const_vxx_0 = blocks.multiply_const_vcc( (0.0022097087, )) if infile == "-": self.blocks_file_descriptor_source_0 = blocks.file_descriptor_source( gr.sizeof_char * 1, 0, True) else: self.blocks_file_source_0 = blocks.file_source( gr.sizeof_char * 1, infile, True) ################################################## # Connections ################################################## if infile == "-": self.connect((self.blocks_file_descriptor_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) else: self.connect((self.blocks_file_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) self.connect((self.blocks_multiply_const_vxx_0, 0), (self.osmosdr_sink_0, 0)) self.connect((self.digital_ofdm_cyclic_prefixer_0, 0), (self.blocks_multiply_const_vxx_0, 0)) self.connect((self.dtv_dvbt_bit_inner_interleaver_0, 0), (self.dtv_dvbt_symbol_inner_interleaver_0, 0)) self.connect((self.dtv_dvbt_convolutional_interleaver_0, 0), (self.dtv_dvbt_inner_coder_0, 0)) self.connect((self.dtv_dvbt_energy_dispersal_0, 0), (self.dtv_dvbt_reed_solomon_enc_0, 0)) self.connect((self.dtv_dvbt_inner_coder_0, 0), (self.dtv_dvbt_bit_inner_interleaver_0, 0)) self.connect((self.dtv_dvbt_map_0, 0), (self.dtv_dvbt_reference_signals_0, 0)) self.connect((self.dtv_dvbt_reed_solomon_enc_0, 0), (self.dtv_dvbt_convolutional_interleaver_0, 0)) self.connect((self.dtv_dvbt_reference_signals_0, 0), (self.fft_vxx_0, 0)) self.connect((self.dtv_dvbt_symbol_inner_interleaver_0, 0), (self.dtv_dvbt_map_0, 0)) self.connect((self.fft_vxx_0, 0), (self.digital_ofdm_cyclic_prefixer_0, 0))
def __init__(self): gr.top_block.__init__(self) bitrate = 8000 channel_bw = 12500 chan0_freq = 358400000 options = get_options() self.rfgain = options.gain self.channels = [ int(ch) for ch in options.channels.split(',') if ch ] self.ch_freqs = [ ch * channel_bw + chan0_freq for ch in self.channels ] self.ch_freqs.extend( [ int(f) for f in options.channels_by_freq.split(',') if f ]) while len(self.channels) < len(self.ch_freqs): self.channels.append(-1) if options.frequency is None: self.ifreq = (max(self.ch_freqs) + min(self.ch_freqs)) / 2 / channel_bw * channel_bw else: self.ifreq = options.frequency ch0 = (self.ifreq - chan0_freq ) / channel_bw n = options.sample_rate / channel_bw s = options.sample_rate / bitrate / 2 c = '' for ch in range(0,len(self.channels)): c = c + '%i,'%((self.channels[ch] - ch0)%n) c=c[:-1] self.src = osmosdr.source(options.args) self.src.set_center_freq(self.ifreq) self.src.set_sample_rate(options.sample_rate) self.src.set_freq_corr(options.ppm, 0) fcl_args = ['./fcl', '-n', '%i'%n, '-s', '%i'%s, '-t', '2', '-c', '%s'%c, '-f', './fir.py %i 7900 2000 rcos'%options.sample_rate, '-o', '/dev/stdout'] sys.stderr.write(string.join(fcl_args)) self.fcl = subprocess.Popen(fcl_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.fcl_in = blocks.file_descriptor_sink(gr.sizeof_gr_complex*1, self.fcl.stdin.fileno()) self.fcl_out = blocks.file_descriptor_source(gr.sizeof_gr_complex*1, self.fcl.stdout.fileno(), False) self.deinterleave = blocks.deinterleave(gr.sizeof_gr_complex*1, 1) self.connect((self.src, 0), (self.fcl_in, 0)) self.connect((self.fcl_out, 0), (self.deinterleave, 0)) if self.rfgain is None: self.src.set_gain_mode(True, 0) self.iagc = 1 self.rfgain = 0 else: self.iagc = 0 self.src.set_gain_mode(False) self.src.set_gain(-9.7) self.src.set_gain(self.rfgain) self.src.set_if_gain(37) # may differ from the requested rate sample_rate = int(self.src.get_sample_rate()) sys.stderr.write("sample rate: %d\n" % (sample_rate)) first_decim = int(options.sample_rate / bitrate / 2) sys.stderr.write("decim: %d\n" % (first_decim)) out_sample_rate=sample_rate/first_decim sys.stderr.write("output sample rate: %d\n" % (out_sample_rate)) sps=out_sample_rate/bitrate sys.stderr.write("samples per symbol: %d\n" % (sps)) self.tuners = [] self.afc_probes = [] if len(self.channels) != 1: if options.output_file: if options.output_file.find('%%') == -1: raise ValueError('Output name template missing "%%".') elif options.output_pipe: if options.output_pipe.find('%%') == -1: raise ValueError('Output name template missing "%%".') else: raise ValueError('WTF') for ch in range(0,len(self.channels)): bw = (9200 + options.afc_ppm_threshold)/2 taps = filter.firdes.low_pass(1.0,out_sample_rate, bw, bw*options.transition_width, filter.firdes.WIN_HANN) # offset = self.ch_freqs[ch] - self.ifreq offset = 0 sys.stderr.write("channel[%d]: %d frequency=%d, offset=%d Hz\n" % (ch, self.channels[ch], self.ch_freqs[ch], offset)) tuner = filter.freq_xlating_fir_filter_ccc(1, taps, offset, out_sample_rate) self.tuners.append(tuner) demod = digital.gmsk_demod(samples_per_symbol=sps) fname = self.channels[ch] if fname == -1: fname = self.ch_freqs[ch] if options.output_pipe is None: file = options.output_file.replace('%%', str(fname)) output = blocks.file_sink(gr.sizeof_char, file) else: cmd = options.output_pipe.replace('%%', str(fname)) pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, shell=True) fd = pipe.stdin.fileno() output = blocks.file_descriptor_sink(gr.sizeof_char, fd) self.connect((self.deinterleave, ch), (tuner, 0)) self.connect((tuner, 0), (demod, 0)) self.connect((demod, 0), (output, 0)) afc_decimation = 32000 afc_demod = analog.quadrature_demod_cf(sample_rate/first_decim/(2*math.pi*afc_decimation)) integrate = blocks.integrate_ff(afc_decimation) afc_probe = blocks.probe_signal_f() self.afc_probes.append(afc_probe) self.connect((tuner, 0), (afc_demod,0)) self.connect((afc_demod, 0), (integrate,0)) self.connect((integrate, 0), (afc_probe, 0)) def _variable_function_probe_0_probe(): while True: time.sleep(options.afc_period) for ch in range(0,len(self.channels)): err = self.afc_probes[ch].level() if abs(err) < options.afc_ppm_threshold: continue freq = self.tuners[ch].center_freq() + err * options.afc_gain self.tuners[ch].set_center_freq(freq) if self.channels[ch] == -1: sys.stderr.write("Freq %d freq err: %5.0f\tfreq: %f\n" % (self.ch_freqs[ch], err, freq)) else: sys.stderr.write("Chan %d freq err: %5.0f\tfreq: %f\n" % (self.channels[ch], err, freq)) sys.stderr.write("\n") _variable_function_probe_0_thread = threading.Thread(target=_variable_function_probe_0_probe) _variable_function_probe_0_thread.daemon = True _variable_function_probe_0_thread.start()
def __init__(self, center_frequency, sample_rate, decimation, filename, sample_format=None, threshold=7.0, burst_width=40e3, offline=False, max_queue_len=500, handle_multiple_frames_per_burst=False, raw_capture_filename=None, debug_id=None, max_bursts=0, verbose=False, file_info="", samples_per_symbol=10, config={}): gr.top_block.__init__(self, "Top Block") self.handle_sigint = False self._center_frequency = center_frequency self._burst_width = burst_width self._input_sample_rate = sample_rate self._verbose = verbose self._threshold = threshold self._filename = filename self._offline = offline self._max_queue_len = max_queue_len self._handle_multiple_frames_per_burst = handle_multiple_frames_per_burst self._decimation = decimation # Sample rate of the bursts exiting the burst downmix block self._burst_sample_rate = 25000 * samples_per_symbol if (self._input_sample_rate / self._decimation) % self._burst_sample_rate != 0: raise RuntimeError("Selected sample rate and decimation can not be matched. Please try a different combination. Sample rate divided by decimation must be a multiple of %d." % self._burst_sample_rate) self._fft_size = 2**round(math.log(self._input_sample_rate / 1000, 2)) # FFT is approx. 1 ms long self._burst_pre_len = 2 * self._fft_size # Keep 16 ms of signal after the FFT loses track self._burst_post_len = int(self._input_sample_rate * 16e-3) # Just to keep the code below a bit more portable tb = self if self._decimation > 1: self._use_channelizer = True # We will set up a filter bank with an odd number of outputs and # and an over sampling ratio to still get the desired decimation. # The goal is to reconstruct signals which (due to Doppler shift) end up # on the border of two channels. # For this to work the desired decimation must be even. if self._decimation % 2: raise RuntimeError("The desired decimation must be 1 or an even number.") self._channels = self._decimation + 1 if self._decimation >= 8: self._use_fft_channelizer = True if 2**int(math.log(self._decimation, 2)) != self._decimation: raise RuntimeError("Decimations >= 8 must be a power of two.") self._channel_sample_rate = self._input_sample_rate // self._decimation # On low end ARM machines we only create a single burst downmixer to not # overload the CPU. Rather drop bursts than samples. if platform.machine() == 'aarch64' and multiprocessing.cpu_count() == 4: self._n_burst_downmixers = 1 else: self._n_burst_downmixers = 2 else: self._use_fft_channelizer = False self._n_burst_downmixers = self._channels self._channelizer_over_sample_ratio = self._channels / (self._channels - 1.) channelizer_output_sample_rate = int(round(float(self._input_sample_rate) / self._channels * self._channelizer_over_sample_ratio)) self._channel_sample_rate = channelizer_output_sample_rate assert channelizer_output_sample_rate == self._input_sample_rate / self._decimation assert channelizer_output_sample_rate % self._burst_sample_rate == 0 # The over sampled region of the FIR filter contains half of the signal width and # the transition region of the FIR filter. # The bandwidth is simply increased by the signal width. # A signal which has its center frequency directly on the border of # two channels will reconstruct correctly on both channels. self._fir_bw = (self._input_sample_rate / self._channels + self._burst_width) / 2 # The remaining bandwidth inside the over sampled region is used to # contain the transition region of the filter. # It can be multiplied by two as it is allowed to continue into the # transition region of the neighboring channel. # Some details can be found here: https://youtu.be/6ngYp8W-AX0?t=2289 self._fir_tw = (channelizer_output_sample_rate / 2 - self._fir_bw) * 2 # Real world data shows only a minor degradation in performance when # doubling the transition width. self._fir_tw *= 2 # If the over sampling ratio is not large enough, there is not # enough room to construct a transition region. if self._fir_tw < 0: raise RuntimeError("PFB over sampling ratio not enough to create a working FIR filter. Please try a different decimation.") self._pfb_fir_filter = gnuradio.filter.firdes.low_pass_2(1, self._input_sample_rate, self._fir_bw, self._fir_tw, 60) # If the transition width approaches 0, the filter size goes up significantly. if len(self._pfb_fir_filter) > 300: print("Warning: The PFB FIR filter has an abnormal large number of taps:", len(self._pfb_fir_filter), file=sys.stderr) print("Consider reducing the decimation factor or use a decimation >= 8.", file=sys.stderr) pfb_input_delay = (len(self._pfb_fir_filter) + 1) // 2 - self._channels / self._channelizer_over_sample_ratio self._channelizer_delay = pfb_input_delay / self._decimation if self._verbose: print("self._channels", self._channels, file=sys.stderr) print("len(self._pfb_fir_filter)", len(self._pfb_fir_filter), file=sys.stderr) print("self._channelizer_over_sample_ratio", self._channelizer_over_sample_ratio, file=sys.stderr) print("self._fir_bw", self._fir_bw, file=sys.stderr) print("self._fir_tw", self._fir_tw, file=sys.stderr) print("self._channel_sample_rate", self._channel_sample_rate, file=sys.stderr) else: self._use_channelizer = False self._channel_sample_rate = self._input_sample_rate self._channels = 1 # After 90 ms there needs to be a pause in the frame sturcture. # Let's make that the limit for a detected burst self._max_burst_len = int(self._channel_sample_rate * 0.09) if self._verbose: print("require %.1f dB" % self._threshold, file=sys.stderr) print("burst_width: %d Hz" % self._burst_width, file=sys.stderr) print("source:", config['source'], file=sys.stderr) if config['source'] == 'osmosdr': d = config["osmosdr-source"] # work around https://github.com/gnuradio/gnuradio/issues/5121 sys.path.append('/usr/local/lib/python3/dist-packages') import osmosdr if 'device_args' in d: source = osmosdr.source(args=d['device_args']) else: source = osmosdr.source() source.set_sample_rate(self._input_sample_rate) source.set_center_freq(self._center_frequency, 0) # Set a rough time estimate for potential rx_time tags from USRP devices # This prevents the output from having bogous time stamps if no GPSDO is available source.set_time_now(osmosdr.time_spec_t(time.time())) if 'gain' in d: gain = int(d['gain']) source.set_gain(gain, 0) print("(RF) Gain:", source.get_gain(0), '(Requested %d)' % gain, file=sys.stderr) for key, value in d.items(): if key.endswith("_gain"): gain_option_name = key.split('_')[0] gain_value = int(value) def match_gain(gain, gain_names): for gain_name in gain_names: if gain.lower() == gain_name.lower(): return gain_name return None gain_name = match_gain(gain_option_name, source.get_gain_names()) if gain_name is not None: source.set_gain(gain_value, gain_name, 0) print(gain_name, "Gain:", source.get_gain(gain_name, 0), '(Requested %d)' % gain_value, file=sys.stderr) else: print("WARNING: Gain", gain_option_name, "not supported by source!", file=sys.stderr) print("Supported gains:", source.get_gain_names(), file=sys.stderr) if 'bandwidth' in d: bandwidth = int(d['bandwidth']) source.set_bandwidth(bandwidth, 0) print("Bandwidth:", source.get_bandwidth(0), '(Requested %d)' % bandwidth, file=sys.stderr) else: source.set_bandwidth(0, 0) print("Warning: Setting bandwidth to", source.get_bandwidth(0), file=sys.stderr) if 'antenna' in d: antenna = d['antenna'] source.set_antenna(antenna, 0) print("Antenna:", source.get_antenna(0), '(Requested %s)' % antenna, file=sys.stderr) else: print("Warning: Setting antenna to", source.get_antenna(0), file=sys.stderr) if 'clock_source' in d: print("Setting clock source to:", d['clock_source'], file=sys.stderr) source.set_clock_source(d['clock_source'], 0) if 'time_source' in d: print("Setting time source to:", d['time_source'], file=sys.stderr) source.set_time_source(d['time_source'], 0) while (time.time() % 1) < 0.4 or (time.time() % 1) > 0.6: pass t = time.time() source.set_time_next_pps(osmosdr.time_spec_t(int(t) + 1)) time.sleep(1) #source.set_freq_corr($corr0, 0) #source.set_dc_offset_mode($dc_offset_mode0, 0) #source.set_iq_balance_mode($iq_balance_mode0, 0) #source.set_gain_mode($gain_mode0, 0) elif config['source'] == 'soapy': d = config["soapy-source"] try: from gnuradio import soapy except ImportError: raise ImportError("gr-soapy not found. Make sure you are running GNURadio >= 3.9.2.0") if 'driver' not in d: print("No driver specified for soapy", file=sys.stderr) print("Run 'SoapySDRUtil -i' to see available drivers(factories)", file=sys.stderr) exit(1) dev = 'driver=' + d['driver'] # Strip quotes def sanitize(s): if s.startswith('"') and s.endswith('"'): return s.strip('""') if s.startswith("'") and s.endswith("'"): return s.strip("''") return s # Remove all outer quotes from the args if they are present in the config if 'device_args' in d: dev_args = sanitize(d['device_args']) elif 'dev_args' in d: dev_args = sanitize(d['dev_args']) else: dev_args = '' stream_args = sanitize(d['stream_args']) if 'stream_args' in d else '' tune_args = sanitize(d['tune_args']) if 'tune_args' in d else '' other_settings = sanitize(d['other_settings']) if 'other_settings' in d else '' # We only support a single channel. Apply tune_args and other_settings to that channel. source = soapy.source(dev, "fc32", 1, dev_args, stream_args, [tune_args], [other_settings]) source.set_sample_rate(0, self._input_sample_rate) source.set_frequency(0, self._center_frequency) if 'gain' in d: gain = int(d['gain']) source.set_gain_mode(0, False) # AGC: OFF source.set_gain(0, gain) print("Gain:", source.get_gain(0), '(Requested %d)' % gain, file=sys.stderr) for key, value in d.items(): if key.endswith("_gain"): gain_option_name = key.split('_')[0] gain_value = int(value) def match_gain(gain, gain_names): for gain_name in gain_names: if gain.lower() == gain_name.lower(): return gain_name return None gain_name = match_gain(gain_option_name, source.list_gains(0)) if gain_name is not None: source.set_gain(0, gain_name, gain_value) print(gain_name, "Gain:", source.get_gain(0, gain_name), '(Requested %d)' % gain_value, source.get_gain_range(0, gain_name), file=sys.stderr) else: print("WARNING: Gain", gain_option_name, "not supported by source!", file=sys.stderr) print("Supported gains:", source.list_gains(0), file=sys.stderr) if 'bandwidth' in d: bandwidth = int(d['bandwidth']) source.set_bandwidth(0, bandwidth) print("Bandwidth:", source.get_bandwidth(0), '(Requested %d)' % bandwidth, file=sys.stderr) else: source.set_bandwidth(0, 0) print("Warning: Setting bandwidth to", source.get_bandwidth(0), file=sys.stderr) if 'antenna' in d: antenna = d['antenna'] source.set_antenna(0, antenna) print("Antenna:", source.get_antenna(0), '(Requested %s)' % antenna, file=sys.stderr) else: print("Warning: Setting antenna to", source.get_antenna(0), file=sys.stderr) #source.set_frequency_correction(0, f_corr) #source.set_dc_offset_mode(0, True) #source.set_dc_offset(0, dc_off) #source.set_iq_balance(0, iq_bal) elif config['source'] == 'zeromq-sub': d = config["zeromq-sub-source"] from gnuradio import zeromq if 'address' not in d: print("No address specified for zeromq sub", file=sys.stderr) exit(1) pass_tags = False if 'pass_tags' in d: pass_tags = bool(distutils.util.strtobool(d['pass_tags'])) timeout = 100 if 'timeout' in d: timeout = int(d['timeout']) high_water_mark = -1 if 'high_water_mark' in d: high_water_mark = int(d['high_water_mark']) source = zeromq.sub_source(gr.sizeof_gr_complex, 1, d['address'], timeout, pass_tags, high_water_mark, '') elif config['source'] == 'uhd': d = config["uhd-source"] from gnuradio import uhd dev_addr = "" if "device_addr" in d: dev_addr = d['device_addr'] dev_args = d['device_args'] cpu_format = 'fc32' wire_format = 'sc16' stream_args = "" stream_args = uhd.stream_args(cpu_format, wire_format, args=stream_args) source = uhd.usrp_source(dev_addr + "," + dev_args, stream_args) source.set_samp_rate(self._input_sample_rate) source.set_center_freq(self._center_frequency) if 'gain' in d: gain = int(d['gain']) source.set_gain(gain, 0) print("Gain:", source.get_gain(0), '(Requested %d)' % gain, file=sys.stderr) if 'bandwidth' in d: bandwidth = int(d['bandwidth']) source.set_bandwidth(bandwidth, 0) print("Bandwidth:", source.get_bandwidth(0), '(Requested %d)' % bandwidth, file=sys.stderr) else: source.set_bandwidth(0) print("Warning: Setting bandwidth to", source.get_bandwidth(0), file=sys.stderr) if 'antenna' in d: antenna = d['antenna'] source.set_antenna(antenna, 0) print("Antenna:", source.get_antenna(0), '(Requested %s)' % antenna, file=sys.stderr) else: print("Warning: Setting antenna to", source.get_antenna(0), file=sys.stderr) print("mboard sensors:", source.get_mboard_sensor_names(0), file=sys.stderr) #for sensor in source.get_mboard_sensor_names(0): # print(sensor, source.get_mboard_sensor(sensor, 0)) gpsdo_sources = ('gpsdo', 'jacksonlabs') time_source = None if 'time_source' in d: time_source = d['time_source'] if time_source in gpsdo_sources: source.set_time_source("gpsdo", 0) else: source.set_time_source(time_source, 0) clock_source = None if 'clock_source' in d: clock_source = d['time_source'] if clock_source in gpsdo_sources: source.set_clock_source("gpsdo", 0) else: source.set_clock_source(clock_source, 0) if time_source in gpsdo_sources or clock_source in gpsdo_sources: print("Waiting for gps_locked...", file=sys.stderr) while True: try: if d['time_source'] == "jacksonlabs": servo = source.get_mboard_sensor("gps_servo", 0) # See https://lists.ettus.com/empathy/thread/6ZOCFQSKLHSG2IH3ID7XPWVKHVHZXPBP gps_locked = str(servo).split()[8] == "6" else: gps_locked = source.get_mboard_sensor("gps_locked", 0).to_bool() if gps_locked: break except ValueError as e: print(e, file=sys.stderr) pass time.sleep(1) print("gps_locked!", file=sys.stderr) if clock_source: print("Waiting for ref_locked...", file=sys.stderr) while True: try: ref_locked = source.get_mboard_sensor("ref_locked", 0) if ref_locked.to_bool(): break except ValueError as e: print(e, file=sys.stderr) pass time.sleep(1) print("ref_locked!", file=sys.stderr) if time_source: if time_source in gpsdo_sources: while True: try: gps_time = uhd.time_spec_t(source.get_mboard_sensor("gps_time").to_int()) break except ValueError as e: print(e, file=sys.stderr) pass time.sleep(1) next_pps_time = gps_time + 1 else: system_time = uhd.time_spec_t(int(time.time())) next_pps_time = system_time + 1 source.set_time_next_pps(next_pps_time) print("Next PPS at", next_pps_time.get_real_secs(), file=sys.stderr) print("Sleeping 2 seconds...", file=sys.stderr) time.sleep(2) # TODO: Check result for plausibility print("USRP time:", source.get_time_last_pps(0).get_real_secs(), file=sys.stderr) else: # Set a rough time estimate for rx_time tags from the USRP. # This prevents the output from having bogous time stamps if no GPSDO is available. source.set_time_now(uhd.time_spec_t(time.time())) self.source = source else: if sample_format == "cu8": converter = iridium.iuchar_to_complex() itemsize = gr.sizeof_char scale = 1 itemtype = np.uint8 elif sample_format == "ci8": converter = blocks.interleaved_char_to_complex() itemsize = gr.sizeof_char scale = 1 / 128. itemtype = np.int8 elif sample_format == "ci16_le": converter = blocks.interleaved_short_to_complex() itemsize = gr.sizeof_short scale = 1 / 32768. itemtype = np.int16 elif sample_format == "cf32_le": converter = None itemsize = gr.sizeof_gr_complex itemtype = np.complex64 else: raise RuntimeError("Unknown sample format for offline mode given") if config['source'] == 'stdin': file_source = blocks.file_descriptor_source(itemsize=itemsize, fd=0, repeat=False) elif config['source'] == 'object': from iridium.file_object_source import file_object_source file_source = file_object_source(fileobject=config['object'], itemtype=itemtype) else: file_source = blocks.file_source(itemsize=itemsize, filename=config['file'], repeat=False) self.source = file_source # XXX: keep reference if converter: multi = blocks.multiply_const_cc(scale) tb.connect(file_source, converter, multi) source = multi else: source = file_source self._fft_burst_tagger = iridium.fft_burst_tagger(center_frequency=self._center_frequency, fft_size=self._fft_size, sample_rate=self._input_sample_rate, burst_pre_len=self._burst_pre_len, burst_post_len=self._burst_post_len, burst_width=int(self._burst_width), max_bursts=max_bursts, max_burst_len=int(self._input_sample_rate * 0.09), threshold=self._threshold, history_size=512, offline=self._offline, debug=self._verbose) self._fft_burst_tagger.set_min_output_buffer(1024 * 64) # Initial filter to filter the detected bursts. Runs at burst_sample_rate. Used to decimate the signal. input_filter = gnuradio.filter.firdes.low_pass_2(1, self._channel_sample_rate, self._burst_width / 2, self._burst_width, 40) #input_filter = gnuradio.filter.firdes.low_pass_2(1, self._channel_sample_rate, 42e3/2, 24e3, 40) #print len(input_filter) # Filter to find the start of the signal. Should be fairly narrow. start_finder_filter = gnuradio.filter.firdes.low_pass_2(1, self._burst_sample_rate, 5e3 / 2, 10e3 / 2, 60) #print len(start_finder_filter) self._iridium_qpsk_demod = iridium.iridium_qpsk_demod(self._channels) self._frame_sorter = iridium.frame_sorter() self._iridium_frame_printer = iridium.iridium_frame_printer(file_info) if raw_capture_filename: multi = blocks.multiply_const_cc(32768) converter = blocks.complex_to_interleaved_short() raw_sink = blocks.file_sink(itemsize=gr.sizeof_short, filename=raw_capture_filename + '.sigmf-data') tb.connect(source, multi, converter, raw_sink) # Enable the following if not fast enough #self._burst_to_pdu_converters = [] #self._burst_downmixers = [] #return tb.connect(source, self._fft_burst_tagger) if self._use_channelizer: self._burst_to_pdu_converters = [] self._burst_downmixers = [] sinks = [] for channel in range(self._channels): if not self._use_fft_channelizer: center = channel if channel <= self._channels / 2 else (channel - self._channels) relative_center = center / float(self._channels) relative_span = 1. / self._channels relative_sample_rate = relative_span * self._channelizer_over_sample_ratio # Second and third parameters tell the block where after the PFB it sits. burst_to_pdu_converter = iridium.tagged_burst_to_pdu(self._max_burst_len, relative_center, relative_span, relative_sample_rate, -self._channelizer_delay, self._max_queue_len, not self._offline) self._burst_to_pdu_converters.append(burst_to_pdu_converter) burst_downmixer = iridium.burst_downmix(self._burst_sample_rate, int(0.007 * self._burst_sample_rate), 0, (input_filter), (start_finder_filter), self._handle_multiple_frames_per_burst) if debug_id is not None: burst_downmixer.debug_id(debug_id) self._burst_downmixers.append(burst_downmixer) channelizer_debug_sinks = [] #channelizer_debug_sinks = [blocks.file_sink(itemsize=gr.sizeof_gr_complex, filename="/tmp/channel-%d.f32"%i) for i in range(self._channels)] if self._use_fft_channelizer: if not channelizer_debug_sinks and self._offline: # HACK: if there are no stream outputs active GNURadio has issues terminating the # flowgraph on completion. Connect some dummy sinks to them. channelizer_debug_sinks = [blocks.null_sink(gr.sizeof_gr_complex) for i in range(self._channels)] activate_streams = len(channelizer_debug_sinks) > 0 self._channelizer = iridium.fft_channelizer(1024, self._channels - 1, activate_streams, self._n_burst_downmixers, self._max_burst_len, self._max_queue_len * self._n_burst_downmixers, not self._offline) else: self._channelizer = gnuradio.filter.pfb.channelizer_ccf(numchans=self._channels, taps=self._pfb_fir_filter, oversample_rate=self._channelizer_over_sample_ratio) tb.connect(self._fft_burst_tagger, self._channelizer) for i in range(self._channels): if channelizer_debug_sinks: tb.connect((self._channelizer, i), channelizer_debug_sinks[i]) for i in range(self._n_burst_downmixers): if self._burst_to_pdu_converters: tb.connect((self._channelizer, i), self._burst_to_pdu_converters[i]) tb.msg_connect((self._burst_to_pdu_converters[i], 'cpdus'), (self._burst_downmixers[i], 'cpdus')) tb.msg_connect((self._burst_downmixers[i], 'burst_handled'), (self._burst_to_pdu_converters[i], 'burst_handled')) else: tb.msg_connect((self._channelizer, 'cpdus%d' % i), (self._burst_downmixers[i], 'cpdus')) tb.msg_connect((self._burst_downmixers[i], 'burst_handled'), (self._channelizer, 'burst_handled')) tb.msg_connect((self._burst_downmixers[i], 'cpdus'), (self._iridium_qpsk_demod, 'cpdus%d' % i)) else: burst_downmix = iridium.burst_downmix(self._burst_sample_rate, int(0.007 * self._burst_sample_rate), 0, (input_filter), (start_finder_filter), self._handle_multiple_frames_per_burst) if debug_id is not None: burst_downmix.debug_id(debug_id) burst_to_pdu = iridium.tagged_burst_to_pdu(self._max_burst_len, 0.0, 1.0, 1.0, 0, self._max_queue_len, not self._offline) tb.connect(self._fft_burst_tagger, burst_to_pdu) tb.msg_connect((burst_to_pdu, 'cpdus'), (burst_downmix, 'cpdus')) tb.msg_connect((burst_downmix, 'burst_handled'), (burst_to_pdu, 'burst_handled')) # Final connection to the demodulator. It prints the output to stdout tb.msg_connect((burst_downmix, 'cpdus'), (self._iridium_qpsk_demod, 'cpdus')) self._burst_downmixers = [burst_downmix] self._burst_to_pdu_converters = [burst_to_pdu] tb.msg_connect((self._iridium_qpsk_demod, 'pdus'), (self._frame_sorter, 'pdus')) tb.msg_connect((self._frame_sorter, 'pdus'), (self._iridium_frame_printer, 'pdus'))
def __init__(self): gr.top_block.__init__(self, "Dvbc Tx Nogui") ################################################## # Variables ################################################## self._symrate_config = ConfigParser.ConfigParser() self._symrate_config.read('./dvbc.conf') try: symrate = self._symrate_config.getint('dvbc', 'symbolrate') except: symrate = 0 self.symrate = symrate self.samp_rate = samp_rate = symrate * 2 self.rrc_taps = rrc_taps = 100 self._rf_gain_config = ConfigParser.ConfigParser() self._rf_gain_config.read('./dvbc.conf') try: rf_gain = self._rf_gain_config.getint('hackrf', 'rf-gain') except: rf_gain = 0 self.rf_gain = rf_gain self._mode_config = ConfigParser.ConfigParser() self._mode_config.read('./dvbc.conf') try: mode = self._mode_config.get('dvbc', 'mode') except: mode = 0 self.mode = mode self._if_gain_config = ConfigParser.ConfigParser() self._if_gain_config.read('./dvbc.conf') try: if_gain = self._if_gain_config.getint('hackrf', 'if-gain') except: if_gain = 0 self.if_gain = if_gain self._center_freq_config = ConfigParser.ConfigParser() self._center_freq_config.read('./dvbc.conf') try: center_freq = self._center_freq_config.getint( 'hackrf', 'frequency') except: center_freq = 0 self.center_freq = center_freq infile = str(sys.argv[1]) if mode == "16QAM": mod = dvbc.MOD_16QAM elif mode == "32QAM": mod = dvbc.MOD_32QAM elif mode == "64QAM": mod = dvbc.MOD_64QAM elif mode == "128QAM": mod = dvbc.MOD_128QAM elif mode == "256QAM": mod = dvbc.MOD_256QAM else: sys.stderr.write( "MODE IN CONFIG WRONG! Values: 16QAM, 32QAM, 64QAM, 128QAM or 256QAM \n" ) sys.exit(1) print "Frequency: ", center_freq / 1000000, "Mhz / Mode: ", mode, "/ Symbolrate: ", symrate / 1000, "\n" ################################################## # Blocks ################################################## self.osmosdr_sink_1 = osmosdr.sink(args="numchan=" + str(1) + " " + 'hackrf,buffers=128,buflen=32768') self.osmosdr_sink_1.set_sample_rate(samp_rate) self.osmosdr_sink_1.set_center_freq(center_freq, 0) self.osmosdr_sink_1.set_freq_corr(0, 0) self.osmosdr_sink_1.set_gain(rf_gain, 0) self.osmosdr_sink_1.set_if_gain(if_gain, 0) self.osmosdr_sink_1.set_bb_gain(0, 0) self.osmosdr_sink_1.set_antenna('', 0) self.osmosdr_sink_1.set_bandwidth(8750000, 0) self.fft_filter_xxx_0 = filter.fft_filter_ccc( 1, (firdes.root_raised_cosine(0.85, samp_rate, samp_rate / 2, 0.15, rrc_taps)), 1) self.fft_filter_xxx_0.declare_sample_delay(0) self.dvbc_symbolmapper_bb_0 = dvbc.symbolmapper_bb(mod) self.dvbc_modulator_bc_0 = dvbc.modulator_bc(mod) self.dtv_dvbt_reed_solomon_enc_0 = dtv.dvbt_reed_solomon_enc( 2, 8, 0x11d, 255, 239, 8, 51, 8) self.dtv_dvbt_energy_dispersal_0 = dtv.dvbt_energy_dispersal(1) self.dtv_dvbt_convolutional_interleaver_0 = dtv.dvbt_convolutional_interleaver( 136, 12, 17) if infile == "-": self.blocks_file_descriptor_source_0 = blocks.file_descriptor_source( gr.sizeof_char * 1, 0, True) else: self.blocks_file_source_0 = blocks.file_source( gr.sizeof_char * 1, infile, True) ################################################## # Connections ################################################## if infile == "-": self.connect((self.blocks_file_descriptor_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) else: self.connect((self.blocks_file_source_0, 0), (self.dtv_dvbt_energy_dispersal_0, 0)) self.connect((self.dtv_dvbt_convolutional_interleaver_0, 0), (self.dvbc_symbolmapper_bb_0, 0)) self.connect((self.dtv_dvbt_energy_dispersal_0, 0), (self.dtv_dvbt_reed_solomon_enc_0, 0)) self.connect((self.dtv_dvbt_reed_solomon_enc_0, 0), (self.dtv_dvbt_convolutional_interleaver_0, 0)) self.connect((self.dvbc_modulator_bc_0, 0), (self.fft_filter_xxx_0, 0)) self.connect((self.dvbc_symbolmapper_bb_0, 0), (self.dvbc_modulator_bc_0, 0)) self.connect((self.fft_filter_xxx_0, 0), (self.osmosdr_sink_1, 0))
def __init__(self): gr.top_block.__init__(self) bitrate = 8000 channel_bw = 12500 chan0_freq = 358400000 options = get_options() self.rfgain = options.gain self.channels = [int(ch) for ch in options.channels.split(',') if ch] self.ch_freqs = [ch * channel_bw + chan0_freq for ch in self.channels] self.ch_freqs.extend( [int(f) for f in options.channels_by_freq.split(',') if f]) while len(self.channels) < len(self.ch_freqs): self.channels.append(-1) if options.frequency is None: self.ifreq = (max(self.ch_freqs) + min(self.ch_freqs)) / 2 / channel_bw * channel_bw else: self.ifreq = options.frequency ch0 = (self.ifreq - chan0_freq) / channel_bw n = options.sample_rate / channel_bw s = options.sample_rate / bitrate / 2 c = '' for ch in range(0, len(self.channels)): c = c + '%i,' % ((self.channels[ch] - ch0) % n) c = c[:-1] self.src = osmosdr.source(options.args) self.src.set_center_freq(self.ifreq) self.src.set_sample_rate(options.sample_rate) self.src.set_freq_corr(options.ppm, 0) fcl_args = [ './fcl', '-n', '%i' % n, '-s', '%i' % s, '-t', '2', '-c', '%s' % c, '-f', './fir.py %i 7900 2000 rcos' % options.sample_rate, '-o', '/dev/stdout' ] sys.stderr.write(string.join(fcl_args)) self.fcl = subprocess.Popen(fcl_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.fcl_in = blocks.file_descriptor_sink(gr.sizeof_gr_complex * 1, self.fcl.stdin.fileno()) self.fcl_out = blocks.file_descriptor_source(gr.sizeof_gr_complex * 1, self.fcl.stdout.fileno(), False) self.deinterleave = blocks.deinterleave(gr.sizeof_gr_complex * 1, 1) self.connect((self.src, 0), (self.fcl_in, 0)) self.connect((self.fcl_out, 0), (self.deinterleave, 0)) if self.rfgain is None: self.src.set_gain_mode(True, 0) self.iagc = 1 self.rfgain = 0 else: self.iagc = 0 self.src.set_gain_mode(False) self.src.set_gain(-9.7) self.src.set_gain(self.rfgain) self.src.set_if_gain(37) # may differ from the requested rate sample_rate = int(self.src.get_sample_rate()) sys.stderr.write("sample rate: %d\n" % (sample_rate)) first_decim = int(options.sample_rate / bitrate / 2) sys.stderr.write("decim: %d\n" % (first_decim)) out_sample_rate = sample_rate / first_decim sys.stderr.write("output sample rate: %d\n" % (out_sample_rate)) sps = out_sample_rate / bitrate sys.stderr.write("samples per symbol: %d\n" % (sps)) self.tuners = [] self.afc_probes = [] if len(self.channels) != 1: if options.output_file: if options.output_file.find('%%') == -1: raise ValueError('Output name template missing "%%".') elif options.output_pipe: if options.output_pipe.find('%%') == -1: raise ValueError('Output name template missing "%%".') else: raise ValueError('WTF') for ch in range(0, len(self.channels)): bw = (9200 + options.afc_ppm_threshold) / 2 taps = filter.firdes.low_pass(1.0, out_sample_rate, bw, bw * options.transition_width, filter.firdes.WIN_HANN) # offset = self.ch_freqs[ch] - self.ifreq offset = 0 sys.stderr.write( "channel[%d]: %d frequency=%d, offset=%d Hz\n" % (ch, self.channels[ch], self.ch_freqs[ch], offset)) tuner = filter.freq_xlating_fir_filter_ccc(1, taps, offset, out_sample_rate) self.tuners.append(tuner) demod = digital.gmsk_demod(samples_per_symbol=sps) fname = self.channels[ch] if fname == -1: fname = self.ch_freqs[ch] if options.output_pipe is None: file = options.output_file.replace('%%', str(fname)) output = blocks.file_sink(gr.sizeof_char, file) else: cmd = options.output_pipe.replace('%%', str(fname)) pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, shell=True) fd = pipe.stdin.fileno() output = blocks.file_descriptor_sink(gr.sizeof_char, fd) self.connect((self.deinterleave, ch), (tuner, 0)) self.connect((tuner, 0), (demod, 0)) self.connect((demod, 0), (output, 0)) afc_decimation = 32000 afc_demod = analog.quadrature_demod_cf( sample_rate / first_decim / (2 * math.pi * afc_decimation)) integrate = blocks.integrate_ff(afc_decimation) afc_probe = blocks.probe_signal_f() self.afc_probes.append(afc_probe) self.connect((tuner, 0), (afc_demod, 0)) self.connect((afc_demod, 0), (integrate, 0)) self.connect((integrate, 0), (afc_probe, 0)) def _variable_function_probe_0_probe(): while True: time.sleep(options.afc_period) for ch in range(0, len(self.channels)): err = self.afc_probes[ch].level() if abs(err) < options.afc_ppm_threshold: continue freq = self.tuners[ch].center_freq( ) + err * options.afc_gain self.tuners[ch].set_center_freq(freq) if self.channels[ch] == -1: sys.stderr.write( "Freq %d freq err: %5.0f\tfreq: %f\n" % (self.ch_freqs[ch], err, freq)) else: sys.stderr.write( "Chan %d freq err: %5.0f\tfreq: %f\n" % (self.channels[ch], err, freq)) sys.stderr.write("\n") _variable_function_probe_0_thread = threading.Thread( target=_variable_function_probe_0_probe) _variable_function_probe_0_thread.daemon = True _variable_function_probe_0_thread.start()
def __init__(self, center_frequency, sample_rate, decimation, filename, sample_format=None, threshold=7.0, burst_width=40e3, offline=False, max_queue_len=500, handle_multiple_frames_per_burst=False, raw_capture_filename=None, debug_id=None, max_bursts=0, verbose=False, file_info=None, samples_per_symbol=10): gr.top_block.__init__(self, "Top Block") self.handle_sigint = False self._center_frequency = center_frequency self._burst_width = burst_width self._input_sample_rate = sample_rate self._verbose = verbose self._threshold = threshold self._filename = filename self._offline = offline self._max_queue_len = max_queue_len self._handle_multiple_frames_per_burst = handle_multiple_frames_per_burst # Sample rate of the bursts exiting the burst downmix block self._burst_sample_rate = 25000 * samples_per_symbol assert (self._input_sample_rate / decimation) % self._burst_sample_rate == 0 self._fft_size = 2**round(math.log(self._input_sample_rate / 1000, 2)) # FFT is approx. 1 ms long self._burst_pre_len = 2 * self._fft_size # Keep 16 ms of signal after the FFT loses track self._burst_post_len = int(self._input_sample_rate * 16e-3) # Just to keep the code below a bit more portable tb = self if decimation > 1: self._use_pfb = True # We will set up a filter bank with an odd number of outputs and # and an over sampling ratio to still get the desired decimation. # The goal is to reconstruct signals which (due to Doppler shift) end up # on the border of two channels. # For this to work the desired decimation must be even. if decimation % 2: raise RuntimeError( "The desired decimation must be 1 or an even number") self._channels = decimation + 1 self._pfb_over_sample_ratio = self._channels / (self._channels - 1.) pfb_output_sample_rate = int( round( float(self._input_sample_rate) / self._channels * self._pfb_over_sample_ratio)) assert pfb_output_sample_rate == self._input_sample_rate / decimation assert pfb_output_sample_rate % self._burst_sample_rate == 0 # The over sampled region of the FIR filter contains half of the signal width and # the transition region of the FIR filter. # The bandwidth is simply increased by the signal width. # A signal which has its center frequency directly on the border of # two channels will reconstruct correctly on both channels. self._fir_bw = (self._input_sample_rate / self._channels + self._burst_width) / 2 # The remaining bandwidth inside the over sampled region is used to # contain the transition region of the filter. # It can be multiplied by two as it is allowed to continue into the # transition region of the neighboring channel. # Some details can be found here: https://youtu.be/6ngYp8W-AX0?t=2289 self._fir_tw = (pfb_output_sample_rate / 2 - self._fir_bw) * 2 # Real world data shows only a minor degradation in performance when # doubling the transition width. self._fir_tw *= 2 # If the over sampling ratio is not large enough, there is not # enough room to construct a transition region. if self._fir_tw < 0: raise RuntimeError( "PFB over sampling ratio not enough to create a working FIR filter" ) self._pfb_fir_filter = gnuradio.filter.firdes.low_pass_2( 1, self._input_sample_rate, self._fir_bw, self._fir_tw, 60) # If the transition width approaches 0, the filter size goes up significantly. if len(self._pfb_fir_filter) > 300: print( "Warning: The PFB FIR filter has an abnormal large number of taps:", len(self._pfb_fir_filter), file=sys.stderr) print("Consider reducing the decimation factor", file=sys.stderr) pfb_input_delay = ( len(self._pfb_fir_filter) + 1) // 2 - self._channels / self._pfb_over_sample_ratio self._pfb_delay = pfb_input_delay / decimation self._channel_sample_rate = pfb_output_sample_rate if self._verbose: print("self._channels", self._channels, file=sys.stderr) print("len(self._pfb_fir_filter)", len(self._pfb_fir_filter), file=sys.stderr) print("self._pfb_over_sample_ratio", self._pfb_over_sample_ratio, file=sys.stderr) print("self._fir_bw", self._fir_bw, file=sys.stderr) print("self._fir_tw", self._fir_tw, file=sys.stderr) print("self._channel_sample_rate", self._channel_sample_rate, file=sys.stderr) else: self._use_pfb = False self._channel_sample_rate = self._input_sample_rate self._channels = 1 # After 90 ms there needs to be a pause in the frame sturcture. # Let's make that the limit for a detected burst self._max_burst_len = int(self._channel_sample_rate * 0.09) if self._verbose: print("require %.1f dB" % self._threshold, file=sys.stderr) print("burst_width: %d Hz" % self._burst_width, file=sys.stderr) if self._filename.endswith(".conf"): import configparser config = configparser.ConfigParser() config.read(self._filename) items = config.items("osmosdr-source") d = {key: value for key, value in items} import osmosdr if 'device_args' in d: source = osmosdr.source(args=d['device_args']) else: source = osmosdr.source() source.set_sample_rate(self._input_sample_rate) source.set_center_freq(self._center_frequency, 0) if 'gain' in d: gain = int(d['gain']) source.set_gain(gain, 0) print("(RF) Gain:", source.get_gain(0), '(Requested %d)' % gain, file=sys.stderr) for key, value in d.items(): if key.endswith("_gain"): gain_option_name = key.split('_')[0] gain_value = int(value) def match_gain(gain, gain_names): for gain_name in gain_names: if gain.lower() == gain_name.lower(): return gain_name return None gain_name = match_gain(gain_option_name, source.get_gain_names()) if gain_name is not None: source.set_gain(gain_value, gain_name, 0) print(gain_name, "Gain:", source.get_gain(gain_name, 0), '(Requested %d)' % gain_value, file=sys.stderr) else: print("WARNING: Gain", gain_option_name, "not supported by source!", file=sys.stderr) print("Supported gains:", source.get_gain_names(), file=sys.stderr) if 'bandwidth' in d: bandwidth = int(d['bandwidth']) source.set_bandwidth(bandwidth, 0) print("Bandwidth:", source.get_bandwidth(0), '(Requested %d)' % bandwidth, file=sys.stderr) else: source.set_bandwidth(0, 0) print("Warning: Setting bandwidth to", source.get_bandwidth(0), file=sys.stderr) if 'antenna' in d: antenna = d['antenna'] source.set_antenna(antenna, 0) print("Antenna:", source.get_antenna(0), '(Requested %s)' % antenna, file=sys.stderr) else: print("Warning: Setting antenna to", source.get_antenna(0), file=sys.stderr) #source.set_freq_corr($corr0, 0) #source.set_dc_offset_mode($dc_offset_mode0, 0) #source.set_iq_balance_mode($iq_balance_mode0, 0) #source.set_gain_mode($gain_mode0, 0) #source.set_antenna($ant0, 0) else: if sample_format == "rtl": converter = iridium.iuchar_to_complex() itemsize = gr.sizeof_char scale = 1 elif sample_format == "hackrf": converter = blocks.interleaved_char_to_complex() itemsize = gr.sizeof_char scale = 1 / 128. elif sample_format == "sc16": converter = blocks.interleaved_short_to_complex() itemsize = gr.sizeof_short scale = 1 / 32768. elif sample_format == "float": converter = None itemsize = gr.sizeof_gr_complex else: raise RuntimeError( "Unknown sample format for offline mode given") if self._filename == '/dev/stdin': file_source = blocks.file_descriptor_source(itemsize=itemsize, fd=0, repeat=False) else: file_source = blocks.file_source(itemsize=itemsize, filename=self._filename, repeat=False) if converter: multi = blocks.multiply_const_cc(scale) tb.connect(file_source, converter, multi) source = multi else: source = file_source self._fft_burst_tagger = iridium.fft_burst_tagger( center_frequency=self._center_frequency, fft_size=self._fft_size, sample_rate=self._input_sample_rate, burst_pre_len=self._burst_pre_len, burst_post_len=self._burst_post_len, burst_width=int(self._burst_width), max_bursts=max_bursts, threshold=self._threshold, history_size=512, debug=self._verbose) # Initial filter to filter the detected bursts. Runs at burst_sample_rate. Used to decimate the signal. input_filter = gnuradio.filter.firdes.low_pass_2( 1, self._channel_sample_rate, self._burst_width / 2, self._burst_width, 40) #input_filter = gnuradio.filter.firdes.low_pass_2(1, self._channel_sample_rate, 42e3/2, 24e3, 40) #print len(input_filter) # Filter to find the start of the signal. Should be fairly narrow. start_finder_filter = gnuradio.filter.firdes.low_pass_2( 1, self._burst_sample_rate, 5e3 / 2, 10e3 / 2, 60) #print len(start_finder_filter) self._iridium_qpsk_demod = iridium.iridium_qpsk_demod_cpp( self._channels) self._frame_sorter = iridium.frame_sorter() self._iridium_frame_printer = iridium.iridium_frame_printer(file_info) if raw_capture_filename: multi = blocks.multiply_const_cc(32768) converter = blocks.complex_to_interleaved_short() raw_sink = blocks.file_sink(itemsize=gr.sizeof_short, filename=raw_capture_filename) tb.connect(source, multi, converter, raw_sink) # Enable the following if not fast enough #self._burst_to_pdu_converters = [] #self._burst_downmixers = [] #return tb.connect(source, self._fft_burst_tagger) if self._use_pfb: self._burst_to_pdu_converters = [] self._burst_downmixers = [] sinks = [] for channel in range(self._channels): center = channel if channel <= self._channels / 2 else ( channel - self._channels) # Second and third parameters tell the block where after the PFB it sits. relative_center = center / float(self._channels) relative_span = 1. / self._channels relative_sample_rate = relative_span * self._pfb_over_sample_ratio burst_to_pdu_converter = iridium.tagged_burst_to_pdu( self._max_burst_len, relative_center, relative_span, relative_sample_rate, -(self._pfb_delay + self._burst_pre_len / decimation), self._max_queue_len, not self._offline) burst_downmixer = iridium.burst_downmix( self._burst_sample_rate, int(0.007 * self._burst_sample_rate), 0, (input_filter), (start_finder_filter), self._handle_multiple_frames_per_burst) if debug_id is not None: burst_downmixer.debug_id(debug_id) self._burst_downmixers.append(burst_downmixer) self._burst_to_pdu_converters.append(burst_to_pdu_converter) #pfb_debug_sinks = [blocks.file_sink(itemsize=gr.sizeof_gr_complex, filename="/tmp/channel-%d.f32"%i) for i in range(self._channels)] pfb_debug_sinks = None pfb = gnuradio.filter.pfb.channelizer_ccf( numchans=self._channels, taps=self._pfb_fir_filter, oversample_rate=self._pfb_over_sample_ratio) tb.connect(self._fft_burst_tagger, pfb) for i in range(self._channels): tb.connect((pfb, i), self._burst_to_pdu_converters[i]) if pfb_debug_sinks: tb.connect((pfb, i), pfb_debug_sinks[i]) tb.msg_connect((self._burst_to_pdu_converters[i], 'cpdus'), (self._burst_downmixers[i], 'cpdus')) tb.msg_connect( (self._burst_downmixers[i], 'burst_handled'), (self._burst_to_pdu_converters[i], 'burst_handled')) tb.msg_connect((self._burst_downmixers[i], 'cpdus'), (self._iridium_qpsk_demod, 'cpdus%d' % i)) else: burst_downmix = iridium.burst_downmix( self._burst_sample_rate, int(0.007 * self._burst_sample_rate), 0, (input_filter), (start_finder_filter), self._handle_multiple_frames_per_burst) if debug_id is not None: burst_downmix.debug_id(debug_id) burst_to_pdu = iridium.tagged_burst_to_pdu(self._max_burst_len, 0.0, 1.0, 1.0, -self._burst_pre_len, self._max_queue_len, not self._offline) tb.connect(self._fft_burst_tagger, burst_to_pdu) tb.msg_connect((burst_to_pdu, 'cpdus'), (burst_downmix, 'cpdus')) tb.msg_connect((burst_downmix, 'burst_handled'), (burst_to_pdu, 'burst_handled')) # Final connection to the demodulator. It prints the output to stdout tb.msg_connect((burst_downmix, 'cpdus'), (self._iridium_qpsk_demod, 'cpdus')) self._burst_downmixers = [burst_downmix] self._burst_to_pdu_converters = [burst_to_pdu] tb.msg_connect((self._iridium_qpsk_demod, 'pdus'), (self._frame_sorter, 'pdus')) tb.msg_connect((self._frame_sorter, 'pdus'), (self._iridium_frame_printer, 'pdus'))