From 3a4380f459f5e60e7c83b87a3fba4af0a6cc6689 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 May 2015 11:53:21 +0200 Subject: [PATCH 1/3] Allow input options on dvbt-tx.py --- dvbt-tx.py | 263 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 179 insertions(+), 84 deletions(-) diff --git a/dvbt-tx.py b/dvbt-tx.py index 6f9aea6..0ecb740 100755 --- a/dvbt-tx.py +++ b/dvbt-tx.py @@ -23,90 +23,185 @@ import dvbt import osmosdr import sys +from optparse import OptionParser -def main(args): - nargs = len(args) - if nargs == 1: - infile = args[0] - outfile = None - elif nargs == 2: - infile = args[0] - outfile = args[1] +# ====================================================================== + +# ---------------------------------------------------------------------- +def getInputFromDict(input_dict, input_key): +# ---------------------------------------------------------------------- + if input_key in input_dict: + return input_dict[input_key] + else: + return None + +# ---------------------------------------------------------------------- +def getInputOptions(): +# ---------------------------------------------------------------------- + default_ts_file = "/tmp/in.fifo" + default_freq = 437.5e6 + default_width = 1e6 + fft_sizes = {"2k": dvbt.T2k, "8k": dvbt.T8k} + code_rates = {"1/2": dvbt.C1_2, "2/3": dvbt.C2_3} + guard_intervals = {"1/4": dvbt.G1_4, "2/3": dvbt.G1_32} + constellations = {"QPSK": dvbt.QPSK, "QAM16": dvbt.QAM16, "QAM64": dvbt.QAM64} + default_txvga_gains_str = "-4,20" + + parser = OptionParser(usage="usage: %%prog -r [-d [-f] [-q]] [-a] [-H]\n\n%s") + parser.add_option("-i", "--ts-file", dest="ts_file", help="Input transport stream file or FIFO (default %s)" % default_ts_file, metavar="DATA_FILE", type="string") + parser.add_option("-o", "--output-file", dest="out_file", help="Output complex samples file (default None)", metavar="OUTPUT_FILE", type="string") + parser.add_option("-f", "--frequency", dest="freq", help="Transmit center frequency in Hz (default %.3e)" % default_freq, metavar="FREQUENCY", type="float") + parser.add_option("-w", "--width", dest="width", help="Channel width in Hz (default %.3e)" % default_width, metavar="WIDTH", type="float") + parser.add_option("-F", "--fft-size", dest="fft_size_str", help="FFT size: %s (default 2k)" % fft_sizes.keys(), metavar="FFT_SIZE", type="string") + parser.add_option("-r", "--code-rate", dest="code_rate_str", help="FEC code rate: %s (default 1/2)" % code_rates.keys(), metavar="CODE_RATE", type="string") + parser.add_option("-g", "--guard-interval", dest="guard_interval_str", help="Guard interval: %s (default 1/4)" % guard_intervals.keys(), metavar="GUARD_INTERVAL", type="string") + parser.add_option("-c", "--constellation", dest="constellation_str", help="Constellations: %s (default QPSK)" % constellations.keys(), metavar="CONSTELLATION", type="string") + parser.add_option("-G", "--txvga-gains", dest="txvga_gains_str", help="Comma separated TX VGA gains 1 and 2 (default: %s)" % default_txvga_gains_str, metavar="GAINS", type="string") + + (options, args) = parser.parse_args() + + options.fft_size = None + options.code_rate = None + options.guard_interval = None + options.constellation = None + + if options.ts_file == None: + options.ts_file = default_ts_file + + if options.freq == None: + options.freq = int(default_freq) + else: + options.freq = int(options.freq) + + if options.width == None: + options.width = default_width + + if options.fft_size_str == None: + options.fft_size = dvbt.T2k else: - sys.stderr.write("Usage: dvbt-blade.py input_file [output_file]\n"); - sys.exit(1) - - channel_mhz = 6 - mode = dvbt.T2k - code_rate = dvbt.C1_2 - constellation = dvbt.QPSK - symbol_rate = channel_mhz * 8000000.0 / 7 - center_freq = 441000000 - txvga1_gain = -4 - txvga2_gain = 25 - - if mode == dvbt.T2k: - factor = 1 - carriers = 2048 - elif mode == dvbt.T8k: - factor = 4 - carriers = 8192 - - if channel_mhz == 8: - bandwidth = 8750000 - elif channel_mhz == 7: - bandwidth = 7000000 - elif channel_mhz == 6: - bandwidth = 6000000 - elif channel_mhz == 5: - bandwidth = 5000000 + options.fft_size = getInputFromDict(fft_sizes, options.fft_size_str) + if options.fft_size == None: + raise InputError("Invalid FFT size specified") + + if options.code_rate_str == None: + options.code_rate = dvbt.C1_2 + else: + options.code_rate = getInputFromDict(code_rates, options.code_rate_str) + if options.code_rate == None: + raise InputError("Invalid code rate specified") + + if options.guard_interval_str == None: + options.guard_interval = dvbt.G1_4 + else: + options.guard_interval = getInputFromDict(guard_intervals, options.guard_interval_str) + if options.code_rate == None: + raise InputError("Invalid guard interval specified") + + if options.constellation_str == None: + options.constellation = dvbt.QPSK else: - bandwidth = 8750000 - - tb = gr.top_block() - - src = blocks.file_source(gr.sizeof_char, infile, True) - - dvbt_energy_dispersal = dvbt.energy_dispersal(1 * factor) - dvbt_reed_solomon_enc = dvbt.reed_solomon_enc(2, 8, 0x11d, 255, 239, 8, 51, (8 * factor)) - dvbt_convolutional_interleaver = dvbt.convolutional_interleaver((136 * factor), 12, 17) - dvbt_inner_coder = dvbt.inner_coder(1, (1512 * factor), constellation, dvbt.NH, code_rate) - dvbt_bit_inner_interleaver = dvbt.bit_inner_interleaver((1512 * factor), constellation, dvbt.NH, mode) - dvbt_symbol_inner_interleaver = dvbt.symbol_inner_interleaver((1512 * factor), mode, 1) - dvbt_dvbt_map = dvbt.dvbt_map((1512 * factor), constellation, dvbt.NH, mode, 1) - dvbt_reference_signals = dvbt.reference_signals(gr.sizeof_gr_complex, (1512 * factor), carriers, constellation, dvbt.NH, code_rate, code_rate, dvbt.G1_32, mode, 0, 0) - fft_vxx = fft.fft_vcc(carriers, False, (window.rectangular(carriers)), True, 10) - digital_ofdm_cyclic_prefixer = digital.ofdm_cyclic_prefixer(carriers, carriers+(64 * factor), 0, "") - blocks_multiply_const_vxx = blocks.multiply_const_vcc((0.0022097087 * 2.5, )) - - out = osmosdr.sink(args="bladerf=0,buffers=128,buflen=32768") - out.set_sample_rate(symbol_rate) - out.set_center_freq(center_freq, 0) - out.set_freq_corr(0, 0) - out.set_gain(txvga2_gain, 0) - out.set_bb_gain(txvga1_gain, 0) - out.set_bandwidth(bandwidth, 0) - - tb.connect(src, dvbt_energy_dispersal) - tb.connect(dvbt_energy_dispersal, dvbt_reed_solomon_enc) - tb.connect(dvbt_reed_solomon_enc, dvbt_convolutional_interleaver) - tb.connect(dvbt_convolutional_interleaver, dvbt_inner_coder) - tb.connect(dvbt_inner_coder, dvbt_bit_inner_interleaver) - tb.connect(dvbt_bit_inner_interleaver, dvbt_symbol_inner_interleaver) - tb.connect(dvbt_symbol_inner_interleaver, dvbt_dvbt_map) - tb.connect(dvbt_dvbt_map, dvbt_reference_signals) - tb.connect(dvbt_reference_signals, fft_vxx) - tb.connect(fft_vxx, digital_ofdm_cyclic_prefixer) - tb.connect(digital_ofdm_cyclic_prefixer, blocks_multiply_const_vxx) - tb.connect(blocks_multiply_const_vxx, out) - - - if outfile: - dst = blocks.file_sink(gr.sizeof_gr_complex, outfile) - tb.connect(blocks_multiply_const_vxx, dst) - - tb.run() - - -if __name__ == '__main__': - main(sys.argv[1:]) + options.constellation = getInputFromDict(constellations, options.constellation_str.upper()) + if options.constellation == None: + raise InputError("Invalid constellation specified") + + if options.txvga_gains_str is None: + options.txvga_gains_str = default_txvga_gains_str + + options.txvga_gains = [] + for gain_str in options.txvga_gains_str.split(","): + options.txvga_gains.append(int(gain_str)) + + return options + +# ====================================================================== + +# ---------------------------------------------------------------------- +def main(): +# ---------------------------------------------------------------------- + try: + options = getInputOptions() + + + channel_mhz = options.width / 1e6 + symbol_rate = channel_mhz * 8000000.0 / 7 + center_freq = options.freq + + mode = options.fft_size + code_rate = options.code_rate + guard = options.guard_interval + constellation = options.constellation + + txvga1_gain = options.txvga_gains[0] + txvga2_gain = options.txvga_gains[1] + + if mode == dvbt.T2k: + factor = 1 + carriers = 2048 + elif mode == dvbt.T8k: + factor = 4 + carriers = 8192 + + if channel_mhz >= 8: + bandwidth = 8750000 + elif channel_mhz <= 7: + bandwidth = 7000000 + elif channel_mhz <= 6: + bandwidth = 6000000 + elif channel_mhz <= 5: + bandwidth = 5000000 + elif channel_mhz <= 2: + bandwidth = 2500000 + elif channel_mhz <= 1: + bandwidth = 1500000 + else: + bandwidth = 8750000 + + tb = gr.top_block() + + src = blocks.file_source(gr.sizeof_char, options.ts_file, True) + + dvbt_energy_dispersal = dvbt.energy_dispersal(1 * factor) + dvbt_reed_solomon_enc = dvbt.reed_solomon_enc(2, 8, 0x11d, 255, 239, 8, 51, (8 * factor)) + dvbt_convolutional_interleaver = dvbt.convolutional_interleaver((136 * factor), 12, 17) + dvbt_inner_coder = dvbt.inner_coder(1, (1512 * factor), constellation, dvbt.NH, code_rate) + dvbt_bit_inner_interleaver = dvbt.bit_inner_interleaver((1512 * factor), constellation, dvbt.NH, mode) + dvbt_symbol_inner_interleaver = dvbt.symbol_inner_interleaver((1512 * factor), mode, 1) + dvbt_dvbt_map = dvbt.dvbt_map((1512 * factor), constellation, dvbt.NH, mode, 1) + dvbt_reference_signals = dvbt.reference_signals(gr.sizeof_gr_complex, (1512 * factor), carriers, constellation, dvbt.NH, code_rate, code_rate, guard, mode, 0, 0) + fft_vxx = fft.fft_vcc(carriers, False, (window.rectangular(carriers)), True, 10) + digital_ofdm_cyclic_prefixer = digital.ofdm_cyclic_prefixer(carriers, carriers+(64 * factor), 0, "") + blocks_multiply_const_vxx = blocks.multiply_const_vcc((0.0022097087 * 2.5, )) + + out = osmosdr.sink(args="bladerf=0,buffers=128,buflen=32768") + out.set_sample_rate(symbol_rate) + out.set_center_freq(center_freq, 0) + out.set_freq_corr(0, 0) + out.set_gain(txvga2_gain, 0) + out.set_bb_gain(txvga1_gain, 0) + out.set_bandwidth(bandwidth, 0) + + tb.connect(src, dvbt_energy_dispersal) + tb.connect(dvbt_energy_dispersal, dvbt_reed_solomon_enc) + tb.connect(dvbt_reed_solomon_enc, dvbt_convolutional_interleaver) + tb.connect(dvbt_convolutional_interleaver, dvbt_inner_coder) + tb.connect(dvbt_inner_coder, dvbt_bit_inner_interleaver) + tb.connect(dvbt_bit_inner_interleaver, dvbt_symbol_inner_interleaver) + tb.connect(dvbt_symbol_inner_interleaver, dvbt_dvbt_map) + tb.connect(dvbt_dvbt_map, dvbt_reference_signals) + tb.connect(dvbt_reference_signals, fft_vxx) + tb.connect(fft_vxx, digital_ofdm_cyclic_prefixer) + tb.connect(digital_ofdm_cyclic_prefixer, blocks_multiply_const_vxx) + tb.connect(blocks_multiply_const_vxx, out) + + if options.out_file: + dst = blocks.file_sink(gr.sizeof_gr_complex, options.out_file) + tb.connect(blocks_multiply_const_vxx, dst) + + tb.run() + + except KeyboardInterrupt: + pass + +# ---------------------------------------------------------------------- +if __name__ == "__main__": + main() From e9e6702601c35dc1dae0c3b6b92772a1b8e4eed6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 May 2015 17:07:51 +0200 Subject: [PATCH 2/3] Added a DVB-S transmitter utility with the BladeRF --- dvbs-tx.py | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100755 dvbs-tx.py diff --git a/dvbs-tx.py b/dvbs-tx.py new file mode 100755 index 0000000..a2d4f00 --- /dev/null +++ b/dvbs-tx.py @@ -0,0 +1,176 @@ +#!/usr/bin/env /usr/bin/python + +# Copyright 2015 Edouard Griffiths, F4EXB +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from gnuradio import blocks +from gnuradio import digital +from gnuradio import fft +from gnuradio import gr +from gnuradio import filter +from gnuradio.filter import firdes +from gnuradio import trellis +from gnuradio.fft import window +import dvbs +import osmosdr +import sys +from optparse import OptionParser + +half_bws = [750000, 875000, 1250000, 1375000, 1500000, 1920000, 2500000, 2750000, 3000000, 3500000, 4375000, 5000000, 6000000, 7000000, 10000000, 14000000] + +# ====================================================================== + +# ---------------------------------------------------------------------- +def getInputFromDict(input_dict, input_key): +# ---------------------------------------------------------------------- + if input_key in input_dict: + return input_dict[input_key] + else: + return None + +# ---------------------------------------------------------------------- +def getInputOptions(): +# ---------------------------------------------------------------------- + default_ts_file = "/tmp/in.fifo" + default_freq = 1.27e9 + symbol_rates = {"160k": 160000, "400k": 400000, "1M": 1000000, "1.5M": 1500000, "2M": 2000000} + default_txvga_gains_str = "-4,20" + + parser = OptionParser(usage="usage: %%prog -r [-d [-f] [-q]] [-a] [-H]\n\n%s") + parser.add_option("-i", "--ts-file", dest="ts_file", help="Input transport stream file or FIFO (default %s)" % default_ts_file, metavar="DATA_FILE", type="string") + parser.add_option("-o", "--output-file", dest="out_file", help="Output complex samples file (default None)", metavar="OUTPUT_FILE", type="string") + parser.add_option("-f", "--frequency", dest="freq", help="Transmit center frequency in Hz (default %.3e)" % default_freq, metavar="FREQUENCY", type="float") + parser.add_option("-s", "--symbol-rate", dest="symbol_rate_str", help="Symbol rate: %s (default 1M)" % symbol_rates.keys(), metavar="SYMBOL_RATE", type="string") + parser.add_option("-G", "--txvga-gains", dest="txvga_gains_str", help="Comma separated TX VGA gains 1 and 2 (default: %s)" % default_txvga_gains_str, metavar="GAINS", type="string") + parser.add_option("-r", "--repeat", dest="repeat", help="Loop on input file indefinitely (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False) + parser.add_option("-I", "--stdin", dest="stdin", help="Input from stdin (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False) + + (options, args) = parser.parse_args() + + if options.ts_file == None: + options.ts_file = default_ts_file + + if options.freq == None: + options.freq = int(default_freq) + else: + options.freq = int(options.freq) + + if options.symbol_rate_str == None: + options.symbol_rate = 1000000 + else: + options.symbol_rate = getInputFromDict(symbol_rates, options.symbol_rate_str) + if options.symbol_rate == None: + raise InputError("Invalid symbol rate specified") + + if options.txvga_gains_str is None: + options.txvga_gains_str = default_txvga_gains_str + + options.txvga_gains = [] + for gain_str in options.txvga_gains_str.split(","): + options.txvga_gains.append(int(gain_str)) + + return options + +# ---------------------------------------------------------------------- +def getHalfBW(symbol_rate): +# ---------------------------------------------------------------------- + for half_bw in half_bws: + if symbol_rate / 2 <= half_bw: + return half_bw + return half_bws[:-1] + +# ====================================================================== + +# ---------------------------------------------------------------------- +def main(): +# ---------------------------------------------------------------------- + try: + options = getInputOptions() + + ################################################## + # Variables + ################################################## + + center_freq = options.freq + txvga1_gain = options.txvga_gains[0] + txvga2_gain = options.txvga_gains[1] + + samp_rate = 2*options.symbol_rate + half_bw = getHalfBW(options.symbol_rate) + + rrc_taps = 20 + + ################################################## + # Blocks + ################################################## + + tb = gr.top_block() + + if options.stdin: + blocks_file_source_0 = blocks.file_descriptor_source(gr.sizeof_char, 0, options.repeat) + else: + blocks_file_source_0 = blocks.file_source(gr.sizeof_char, options.ts_file, options.repeat) + + fft_filter_xxx_0 = filter.fft_filter_ccc(1, (firdes.root_raised_cosine(1.79, samp_rate, samp_rate/2, 0.35, rrc_taps)), 1) + fft_filter_xxx_0.declare_sample_delay(0) + dvbs_reed_solomon_enc_bb_0 = dvbs.reed_solomon_enc_bb() + dvbs_randomizer_bb_0 = dvbs.randomizer_bb() + dvbs_puncture_bb_0 = dvbs.puncture_bb(dvbs.C1_2) + dvbs_modulator_bc_0 = dvbs.modulator_bc() + dvbs_interleaver_bb_0 = dvbs.interleaver_bb() + blocks_unpack_k_bits_bb_0 = blocks.unpack_k_bits_bb(2) + blocks_packed_to_unpacked_xx_0 = blocks.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) + blocks_pack_k_bits_bb_0 = blocks.pack_k_bits_bb(2) + trellis_encoder_xx_0 = trellis.encoder_bb(trellis.fsm(1, 2, (0171, 0133)), 0, 0) if False else trellis.encoder_bb(trellis.fsm(1, 2, (0171, 0133)), 0) + + osmosdr_sink_0 = osmosdr.sink( args="bladerf=0,buffers=128,buflen=32768," +"numchan=" + str(1)) + osmosdr_sink_0.set_sample_rate(samp_rate) + osmosdr_sink_0.set_center_freq(center_freq, 0) + osmosdr_sink_0.set_freq_corr(0, 0) + osmosdr_sink_0.set_gain(txvga2_gain, 0) + osmosdr_sink_0.set_if_gain(0, 0) + osmosdr_sink_0.set_bb_gain(txvga1_gain, 0) + osmosdr_sink_0.set_antenna("", 0) + osmosdr_sink_0.set_bandwidth(half_bw * 2, 0) + + + ################################################## + # Connections + ################################################## + + tb.connect((blocks_file_source_0, 0), (dvbs_randomizer_bb_0, 0)) + tb.connect((blocks_pack_k_bits_bb_0, 0), (dvbs_modulator_bc_0, 0)) + tb.connect((blocks_packed_to_unpacked_xx_0, 0), (trellis_encoder_xx_0, 0)) + tb.connect((blocks_unpack_k_bits_bb_0, 0), (dvbs_puncture_bb_0, 0)) + tb.connect((dvbs_interleaver_bb_0, 0), (blocks_packed_to_unpacked_xx_0, 0)) + tb.connect((dvbs_modulator_bc_0, 0), (fft_filter_xxx_0, 0)) + tb.connect((dvbs_puncture_bb_0, 0), (blocks_pack_k_bits_bb_0, 0)) + tb.connect((dvbs_randomizer_bb_0, 0), (dvbs_reed_solomon_enc_bb_0, 0)) + tb.connect((dvbs_reed_solomon_enc_bb_0, 0), (dvbs_interleaver_bb_0, 0)) + tb.connect((fft_filter_xxx_0, 0), (osmosdr_sink_0, 0)) + tb.connect((trellis_encoder_xx_0, 0), (blocks_unpack_k_bits_bb_0, 0)) + + if options.out_file: + dst = blocks.file_sink(gr.sizeof_gr_complex, options.out_file) + tb.connect(fft_filter_xxx_0, dst) + + tb.run() + + except KeyboardInterrupt: + pass + +# ---------------------------------------------------------------------- +if __name__ == "__main__": + main() From 8faa434a38062b991c25c43119120e4b1cbb2217 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 May 2015 17:11:21 +0200 Subject: [PATCH 3/3] Added standard input and repetition options to DVB-T transmitter --- dvbs-tx.py | 2 +- dvbt-tx.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dvbs-tx.py b/dvbs-tx.py index a2d4f00..c9537c9 100755 --- a/dvbs-tx.py +++ b/dvbs-tx.py @@ -119,7 +119,7 @@ def main(): tb = gr.top_block() if options.stdin: - blocks_file_source_0 = blocks.file_descriptor_source(gr.sizeof_char, 0, options.repeat) + blocks_file_source_0 = blocks.file_descriptor_source(gr.sizeof_char, 0, False) else: blocks_file_source_0 = blocks.file_source(gr.sizeof_char, options.ts_file, options.repeat) diff --git a/dvbt-tx.py b/dvbt-tx.py index 0ecb740..e5974bd 100755 --- a/dvbt-tx.py +++ b/dvbt-tx.py @@ -57,6 +57,8 @@ def getInputOptions(): parser.add_option("-g", "--guard-interval", dest="guard_interval_str", help="Guard interval: %s (default 1/4)" % guard_intervals.keys(), metavar="GUARD_INTERVAL", type="string") parser.add_option("-c", "--constellation", dest="constellation_str", help="Constellations: %s (default QPSK)" % constellations.keys(), metavar="CONSTELLATION", type="string") parser.add_option("-G", "--txvga-gains", dest="txvga_gains_str", help="Comma separated TX VGA gains 1 and 2 (default: %s)" % default_txvga_gains_str, metavar="GAINS", type="string") + parser.add_option("-R", "--repeat", dest="repeat", help="Loop on input file indefinitely (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False) + parser.add_option("-I", "--stdin", dest="stdin", help="Input from stdin (delfault No)", metavar="CANCEL_LOCAL", action="store_true", default=False) (options, args) = parser.parse_args() @@ -121,6 +123,9 @@ def main(): try: options = getInputOptions() + ################################################## + # Variables + ################################################## channel_mhz = options.width / 1e6 symbol_rate = channel_mhz * 8000000.0 / 7 @@ -156,9 +161,16 @@ def main(): else: bandwidth = 8750000 + ################################################## + # Blocks + ################################################## + tb = gr.top_block() - src = blocks.file_source(gr.sizeof_char, options.ts_file, True) + if options.stdin: + src = blocks.file_descriptor_source(gr.sizeof_char, 0, False) + else: + src = blocks.file_source(gr.sizeof_char, options.ts_file, options.repeat) dvbt_energy_dispersal = dvbt.energy_dispersal(1 * factor) dvbt_reed_solomon_enc = dvbt.reed_solomon_enc(2, 8, 0x11d, 255, 239, 8, 51, (8 * factor)) @@ -180,6 +192,10 @@ def main(): out.set_bb_gain(txvga1_gain, 0) out.set_bandwidth(bandwidth, 0) + ################################################## + # Connections + ################################################## + tb.connect(src, dvbt_energy_dispersal) tb.connect(dvbt_energy_dispersal, dvbt_reed_solomon_enc) tb.connect(dvbt_reed_solomon_enc, dvbt_convolutional_interleaver)