def __init__(self): gr.top_block.__init__(self) parser = OptionParser(option_class=eng_option) parser.add_option( "-O", "--audio-output", type="string", default="", help="pcm output device name. E.g., hw:0,0 or /dev/dsp") parser.add_option("-r", "--sample-rate", type="eng_float", default=48000, help="set sample rate to RATE (48000)") (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() raise SystemExit, 1 sample_rate = int(options.sample_rate) ampl = 0.1 src = gr.glfsr_source_b(32) # Pseudorandom noise source b2f = gr.chunks_to_symbols_bf([ampl, -ampl], 1) dst = audio.sink(sample_rate, options.audio_output) self.connect(src, b2f, dst)
def __init__(self, output_rate): gr.hier_block2.__init__(self, "p25_c4fm_mod_bf", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature symbol_rate = 4800 # P25 baseband symbol rate lcm = gru.lcm(symbol_rate, output_rate) self._interp_factor = int(lcm // symbol_rate) self._decimation = int(lcm // output_rate) self._excess_bw =0.2 mod_map = [1.0/3.0, 1.0, -(1.0/3.0), -1.0] self.C2S = gr.chunks_to_symbols_bf(mod_map) ntaps = 11 * self._interp_factor rrc_taps = gr.firdes.root_raised_cosine( self._interp_factor, # gain (since we're interpolating by sps) lcm, # sampling rate symbol_rate, self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = gr.interp_fir_filter_fff(self._interp_factor, rrc_taps) # FM pre-emphasis filter shaping_coeffs = [-0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018] self.shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) # generate output at appropriate rate self.decimator = blks2.rational_resampler_fff(1, self._decimation) self.connect(self, self.C2S, self.rrc_filter, self.shaping_filter, self.decimator, self)
def test_convolutional_encoder(self): """ Tests convolutional encoder """ src_data = make_transport_stream() constellation = [.7, .7, .7, -.7, -.7, .7, -.7, -.7] src = gr.vector_source_b(src_data) unpack = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) enc = dvb_convolutional_encoder_bb.convolutional_encoder_bb() repack1 = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) repack2 = gr.packed_to_unpacked_bb(2, gr.GR_MSB_FIRST) mapper = gr.chunks_to_symbols_bf(constellation, dvb_swig.dimensionality) viterbi = trellis.viterbi_combined_fb( trellis.fsm(dvb_swig.k, dvb_swig.n, dvb_convolutional_encoder_bb.G), dvb_swig.K, -1, -1, dvb_swig.dimensionality, constellation, digital.TRELLIS_EUCLIDEAN) pack = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) dst = gr.vector_sink_b() self.tb.connect(src, unpack, enc, repack1, repack2, mapper) self.tb.connect(mapper, viterbi, pack, dst) self.tb.run() result_data = dst.data() self.assertEqual(tuple(src_data[:len(result_data)]), result_data)
def test_002_correlation_b(self): for degree in range(1,11): # Higher degrees take too long to correlate src = gr.glfsr_source_b(degree, False) b2f = gr.chunks_to_symbols_bf((-1.0,1.0), 1) dst = gr.vector_sink_f() self.fg.connect(src, b2f, dst) self.fg.run() actual_result = dst.data() R = auto_correlate(actual_result) self.assertEqual(R[0], float(len(R))) # Auto-correlation peak at origin for i in range(len(R)-1): self.assertEqual(R[i+1], -1.0) # Auto-correlation minimum everywhere else
def test_002_correlation_b(self): for degree in range(1,11): # Higher degrees take too long to correlate src = gr.glfsr_source_b(degree, False) b2f = gr.chunks_to_symbols_bf((-1.0,1.0), 1) dst = gr.vector_sink_f() del self.tb # Discard existing top block self.tb = gr.top_block() self.tb.connect(src, b2f, dst) self.tb.run() self.tb.disconnect_all() actual_result = dst.data() R = auto_correlate(actual_result) self.assertEqual(R[0], float(len(R))) # Auto-correlation peak at origin for i in range(len(R)-1): self.assertEqual(R[i+1], -1.0) # Auto-correlation minimum everywhere else
def __init__(self, options, queue): gr.top_block.__init__(self, "mhp") sample_rate = options.sample_rate arity = 2 IN = gr.file_source(gr.sizeof_char, options.input_file, options.repeat) B2C = gr.packed_to_unpacked_bb(arity, gr.GR_MSB_FIRST) mod_map = [1.0, 3.0, -1.0, -3.0] C2S = gr.chunks_to_symbols_bf(mod_map) if options.reverse: polarity = gr.multiply_const_ff(-1) else: polarity = gr.multiply_const_ff( 1) symbol_rate = 4800 samples_per_symbol = sample_rate // symbol_rate excess_bw = 0.1 ntaps = 11 * samples_per_symbol rrc_taps = gr.firdes.root_raised_cosine( samples_per_symbol, # gain (sps since we're interpolating by sps samples_per_symbol, # sampling rate 1.0, # symbol rate excess_bw, # excess bandwidth (roll-off factor) ntaps) rrc_filter = gr.interp_fir_filter_fff(samples_per_symbol, rrc_taps) rrc_coeffs = [0, -0.003, -0.006, -0.009, -0.012, -0.014, -0.014, -0.013, -0.01, -0.006, 0, 0.007, 0.014, 0.02, 0.026, 0.029, 0.029, 0.027, 0.021, 0.012, 0, -0.013, -0.027, -0.039, -0.049, -0.054, -0.055, -0.049, -0.038, -0.021, 0, 0.024, 0.048, 0.071, 0.088, 0.098, 0.099, 0.09, 0.07, 0.039, 0, -0.045, -0.091, -0.134, -0.17, -0.193, -0.199, -0.184, -0.147, -0.085, 0, 0.105, 0.227, 0.36, 0.496, 0.629, 0.751, 0.854, 0.933, 0.983, 1, 0.983, 0.933, 0.854, 0.751, 0.629, 0.496, 0.36, 0.227, 0.105, 0, -0.085, -0.147, -0.184, -0.199, -0.193, -0.17, -0.134, -0.091, -0.045, 0, 0.039, 0.07, 0.09, 0.099, 0.098, 0.088, 0.071, 0.048, 0.024, 0, -0.021, -0.038, -0.049, -0.055, -0.054, -0.049, -0.039, -0.027, -0.013, 0, 0.012, 0.021, 0.027, 0.029, 0.029, 0.026, 0.02, 0.014, 0.007, 0, -0.006, -0.01, -0.013, -0.014, -0.014, -0.012, -0.009, -0.006, -0.003, 0] # rrc_coeffs work slightly differently: each input sample # (from mod_map above) at 4800 rate, then 9 zeros are inserted # to bring to a 48000 rate, then this filter is applied: # rrc_filter = gr.fir_filter_fff(1, rrc_coeffs) # FIXME: how to insert the 9 zero samples using gr ? # FM pre-emphasis filter shaping_coeffs = [-0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018] shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) OUT = audio.sink(sample_rate, options.audio_output) amp = gr.multiply_const_ff(options.factor) self.connect(IN, B2C, C2S, polarity, rrc_filter, shaping_filter, amp) # output to both L and R channels self.connect(amp, (OUT,0) ) self.connect(amp, (OUT,1) )
def __init__(self, output_rate): gr.hier_block2.__init__( self, "p25_c4fm_mod_bf", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature symbol_rate = 4800 # P25 baseband symbol rate lcm = gru.lcm(symbol_rate, output_rate) self._interp_factor = int(lcm // symbol_rate) self._decimation = int(lcm // output_rate) self._excess_bw = 0.2 mod_map = [1.0 / 3.0, 1.0, -(1.0 / 3.0), -1.0] self.C2S = gr.chunks_to_symbols_bf(mod_map) ntaps = 11 * self._interp_factor rrc_taps = gr.firdes.root_raised_cosine( self._interp_factor, # gain (since we're interpolating by sps) lcm, # sampling rate symbol_rate, self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = gr.interp_fir_filter_fff(self._interp_factor, rrc_taps) # FM pre-emphasis filter shaping_coeffs = [ -0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018 ] self.shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) # generate output at appropriate rate self.decimator = blks2.rational_resampler_fff(1, self._decimation) self.connect(self, self.C2S, self.rrc_filter, self.shaping_filter, self.decimator, self)
def __init__(self): gr.top_block.__init__(self) parser = OptionParser(option_class=eng_option) parser.add_option("-O", "--audio-output", type="string", default="", help="pcm output device name. E.g., hw:0,0 or /dev/dsp") parser.add_option("-r", "--sample-rate", type="eng_float", default=48000, help="set sample rate to RATE (48000)") (options, args) = parser.parse_args () if len(args) != 0: parser.print_help() raise SystemExit, 1 sample_rate = int(options.sample_rate) ampl = 0.1 src = gr.glfsr_source_b(32) # Pseudorandom noise source b2f = gr.chunks_to_symbols_bf([ampl, -ampl], 1) dst = audio.sink(sample_rate, options.audio_output) self.connect(src, b2f, dst)
def test_convolutional_encoder(self): """ Tests convolutional encoder """ src_data = make_transport_stream() constellation = [.7, .7,.7,-.7,-.7,.7,-.7,-.7] src = gr.vector_source_b(src_data) unpack = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) enc = dvb_convolutional_encoder_bb.convolutional_encoder_bb() repack1 = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) repack2 = gr.packed_to_unpacked_bb(2, gr.GR_MSB_FIRST) mapper = gr.chunks_to_symbols_bf(constellation, dvb_swig.dimensionality) viterbi = trellis.viterbi_combined_fb(trellis.fsm(dvb_swig.k, dvb_swig.n, dvb_convolutional_encoder_bb.G), dvb_swig.K, -1, -1, dvb_swig.dimensionality, constellation, trellis.TRELLIS_EUCLIDEAN) pack = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) dst = gr.vector_sink_b() self.tb.connect(src, unpack, enc, repack1, repack2, mapper) self.tb.connect(mapper, viterbi, pack, dst) self.tb.run() result_data = dst.data() self.assertEqual(tuple(src_data[:len(result_data)]), result_data)
def run_test(seed, blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0 * K) / P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P, M, L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT = 0.3 tt = numpy.arange(0, L * Q) / (1.0 * Q) - L / 2.0 #print tt p = (0.5 * scipy.stats.erfc(2 * math.pi * BT * (tt - 0.5) / math.sqrt( math.log(2.0)) / math.sqrt(2.0)) - 0.5 * scipy.stats.erfc( 2 * math.pi * BT * (tt + 0.5) / math.sqrt(math.log(2.0)) / math.sqrt(2.0))) / 2.0 p = p / sum(p) * Q / 2.0 #print p q = numpy.cumsum(p) / Q q = q / q[-1] / 2.0 #print q (f0T, SS, S, F, Sf, Ff, N) = fsm_utils.make_cpm_signals(K, P, M, L, q, frac) #print N #print Ff Ffa = numpy.insert(Ff, Q, numpy.zeros(N), axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2, axis=0) Es = numpy.sum(E) / f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf), N * f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0 * EsN0_db) / 10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed * 666) data = numpy.random.randint(0, M, head + blocksize + tail + 1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i] = 0 for i in range(tail + 1): data[-i] = 0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data.tolist(), False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2 * math.pi * h * (1.0 / Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0 / 2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex * 1, int(N)) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex * 1, int(N * (1 + 0))) viterbi = trellis.viterbi_combined_cb(f, head + blocksize + tail, 0, -1, int(N), constellation, digital.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head + i] != dataest[head + i]: #print i err += 1 if err != 0: perr = 1 return (err, perr)
def __init__(self, output_sample_rate=_def_output_sample_rate, excess_bw=_def_excess_bw, reverse=_def_reverse, verbose=_def_verbose, log=_def_log): """ Hierarchical block for RRC-filtered P25 FM modulation. The input is a dibit (P25 symbol) stream (char, not packed) and the output is the float "C4FM" signal at baseband, suitable for application to an FM modulator stage Input is at the base symbol rate (4800), output sample rate is typically either 32000 (USRP TX chain) or 48000 (sound card) @param output_sample_rate: output sample rate @type output_sample_rate: integer @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float @param reverse: reverse polarity flag @type reverse: bool @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__( self, "p25_c4fm_mod_bf", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature input_sample_rate = 4800 # P25 baseband symbol rate lcm = gru.lcm(input_sample_rate, output_sample_rate) self._interp_factor = int(lcm // input_sample_rate) self._decimation = int(lcm // output_sample_rate) self._excess_bw = excess_bw mod_map = [1.0 / 3.0, 1.0, -(1.0 / 3.0), -1.0] self.C2S = gr.chunks_to_symbols_bf(mod_map) if reverse: self.polarity = gr.multiply_const_ff(-1) else: self.polarity = gr.multiply_const_ff(1) ntaps = 11 * self._interp_factor rrc_taps = gr.firdes.root_raised_cosine( self._interp_factor, # gain (since we're interpolating by sps) lcm, # sampling rate input_sample_rate, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) # rrc_coeffs work slightly differently: each input sample # (from mod_map above) at 4800 rate, then 9 zeros are inserted # to bring to 48000 rate, then this filter is applied: # rrc_filter = gr.fir_filter_fff(1, rrc_coeffs) # FIXME: how to insert the 9 zero samples using gr ? # rrc_coeffs = [0, -0.003, -0.006, -0.009, -0.012, -0.014, -0.014, -0.013, -0.01, -0.006, 0, 0.007, 0.014, 0.02, 0.026, 0.029, 0.029, 0.027, 0.021, 0.012, 0, -0.013, -0.027, -0.039, -0.049, -0.054, -0.055, -0.049, -0.038, -0.021, 0, 0.024, 0.048, 0.071, 0.088, 0.098, 0.099, 0.09, 0.07, 0.039, 0, -0.045, -0.091, -0.134, -0.17, -0.193, -0.199, -0.184, -0.147, -0.085, 0, 0.105, 0.227, 0.36, 0.496, 0.629, 0.751, 0.854, 0.933, 0.983, 1, 0.983, 0.933, 0.854, 0.751, 0.629, 0.496, 0.36, 0.227, 0.105, 0, -0.085, -0.147, -0.184, -0.199, -0.193, -0.17, -0.134, -0.091, -0.045, 0, 0.039, 0.07, 0.09, 0.099, 0.098, 0.088, 0.071, 0.048, 0.024, 0, -0.021, -0.038, -0.049, -0.055, -0.054, -0.049, -0.039, -0.027, -0.013, 0, 0.012, 0.021, 0.027, 0.029, 0.029, 0.026, 0.02, 0.014, 0.007, 0, -0.006, -0.01, -0.013, -0.014, -0.014, -0.012, -0.009, -0.006, -0.003, 0] self.rrc_filter = gr.interp_fir_filter_fff(self._interp_factor, rrc_taps) # FM pre-emphasis filter shaping_coeffs = [ -0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018 ] self.shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) if verbose: self._print_verbage() if log: self._setup_logging() self.connect(self, self.C2S, self.polarity, self.rrc_filter, self.shaping_filter) if (self._decimation > 1): self.decimator = blks2.rational_resampler_fff(1, self._decimation) self.connect(self.shaping_filter, self.decimator, self) else: self.connect(self.shaping_filter, self)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bits_per_symbol=_def_bits_per_symbol, h_numerator=_def_h_numerator, h_denominator=_def_h_denominator, cpm_type=_def_cpm_type, bt=_def_bt, symbols_per_pulse=_def_symbols_per_pulse, generic_taps=_def_generic_taps, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Continuous Phase modulation. The input is a byte stream (unsigned char) representing packed bits and the output is the complex modulated signal at baseband. See Proakis for definition of generic CPM signals: s(t)=exp(j phi(t)) phi(t)= 2 pi h int_0^t f(t') dt' f(t)=sum_k a_k g(t-kT) (normalizing assumption: int_0^infty g(t) dt = 1/2) @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bits_per_symbol: bits per symbol @type bits_per_symbol: integer @param h_numerator: numerator of modulation index @type h_numerator: integer @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes) @type h_denominator: integer @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL @type cpm_type: integer @param bt: bandwidth symbol time product for GMSK @type bt: float @param symbols_per_pulse: shaping pulse duration in symbols @type symbols_per_pulse: integer @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2) @type generic_taps: array of floats @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__("cpm_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._samples_per_symbol = samples_per_symbol self._bits_per_symbol = bits_per_symbol self._h_numerator = h_numerator self._h_denominator = h_denominator self._cpm_type = cpm_type self._bt=bt if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic self._symbols_per_pulse = symbols_per_pulse elif cpm_type == 1: # GMSK self._symbols_per_pulse = 4 else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self._generic_taps=numpy.array(generic_taps) if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,)) self.nsymbols = 2**bits_per_symbol self.sym_alphabet=numpy.arange(-(self.nsymbols-1),self.nsymbols,2) self.ntaps = self._symbols_per_pulse * samples_per_symbol sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol # Unpack Bytes into bits_per_symbol groups self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol,gr.GR_MSB_FIRST) # Turn it into symmetric PAM data. self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet,1) # Generate pulse (sum of taps = samples_per_symbol/2) if cpm_type == 0: # CPFSK self.taps= (1.0/self._symbols_per_pulse/2,) * self.ntaps elif cpm_type == 1: # GMSK gaussian_taps = gr.firdes.gaussian( 1.0/2, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time self.ntaps # number of taps ) sqwave = (1,) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(gaussian_taps),numpy.array(sqwave)) elif cpm_type == 2: # Raised Cosine # generalize it for arbitrary roll-off factor self.taps = (1-numpy.cos(2*pi*numpy.arange(0,self.ntaps)/samples_per_symbol/self._symbols_per_pulse))/(2*self._symbols_per_pulse) elif cpm_type == 3: # Generic CPM self.taps = generic_taps else: raise TypeError, ("cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type,)) self.filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
def run_test(seed,blocksize): tb = gr.top_block() ################################################## # Variables ################################################## M = 2 K = 1 P = 2 h = (1.0*K)/P L = 3 Q = 4 frac = 0.99 f = trellis.fsm(P,M,L) # CPFSK signals #p = numpy.ones(Q)/(2.0) #q = numpy.cumsum(p)/(1.0*Q) # GMSK signals BT=0.3; tt=numpy.arange(0,L*Q)/(1.0*Q)-L/2.0; #print tt p=(0.5*scipy.stats.erfc(2*math.pi*BT*(tt-0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0))-0.5*scipy.stats.erfc(2*math.pi*BT*(tt+0.5)/math.sqrt(math.log(2.0))/math.sqrt(2.0)))/2.0; p=p/sum(p)*Q/2.0; #print p q=numpy.cumsum(p)/Q; q=q/q[-1]/2.0; #print q (f0T,SS,S,F,Sf,Ff,N) = fsm_utils.make_cpm_signals(K,P,M,L,q,frac) #print N #print Ff Ffa = numpy.insert(Ff,Q,numpy.zeros(N),axis=0) #print Ffa MF = numpy.fliplr(numpy.transpose(Ffa)) #print MF E = numpy.sum(numpy.abs(Sf)**2,axis=0) Es = numpy.sum(E)/f.O() #print Es constellation = numpy.reshape(numpy.transpose(Sf),N*f.O()) #print Ff #print Sf #print constellation #print numpy.max(numpy.abs(SS - numpy.dot(Ff , Sf))) EsN0_db = 10.0 N0 = Es * 10.0**(-(1.0*EsN0_db)/10.0) #N0 = 0.0 #print N0 head = 4 tail = 4 numpy.random.seed(seed*666) data = numpy.random.randint(0, M, head+blocksize+tail+1) #data = numpy.zeros(blocksize+1+head+tail,'int') for i in range(head): data[i]=0 for i in range(tail+1): data[-i]=0 ################################################## # Blocks ################################################## random_source_x_0 = gr.vector_source_b(data, False) gr_chunks_to_symbols_xx_0 = gr.chunks_to_symbols_bf((-1, 1), 1) gr_interp_fir_filter_xxx_0 = gr.interp_fir_filter_fff(Q, p) gr_frequency_modulator_fc_0 = gr.frequency_modulator_fc(2*math.pi*h*(1.0/Q)) gr_add_vxx_0 = gr.add_vcc(1) gr_noise_source_x_0 = gr.noise_source_c(gr.GR_GAUSSIAN, (N0/2.0)**0.5, -long(seed)) gr_multiply_vxx_0 = gr.multiply_vcc(1) gr_sig_source_x_0 = gr.sig_source_c(Q, gr.GR_COS_WAVE, -f0T, 1, 0) # only works for N=2, do it manually for N>2... gr_fir_filter_xxx_0_0 = gr.fir_filter_ccc(Q, MF[0].conjugate()) gr_fir_filter_xxx_0_0_0 = gr.fir_filter_ccc(Q, MF[1].conjugate()) gr_streams_to_stream_0 = gr.streams_to_stream(gr.sizeof_gr_complex*1, N) gr_skiphead_0 = gr.skiphead(gr.sizeof_gr_complex*1, N*(1+0)) viterbi = trellis.viterbi_combined_cb(f, head+blocksize+tail, 0, -1, N, constellation, trellis.TRELLIS_EUCLIDEAN) gr_vector_sink_x_0 = gr.vector_sink_b() ################################################## # Connections ################################################## tb.connect((random_source_x_0, 0), (gr_chunks_to_symbols_xx_0, 0)) tb.connect((gr_chunks_to_symbols_xx_0, 0), (gr_interp_fir_filter_xxx_0, 0)) tb.connect((gr_interp_fir_filter_xxx_0, 0), (gr_frequency_modulator_fc_0, 0)) tb.connect((gr_frequency_modulator_fc_0, 0), (gr_add_vxx_0, 0)) tb.connect((gr_noise_source_x_0, 0), (gr_add_vxx_0, 1)) tb.connect((gr_add_vxx_0, 0), (gr_multiply_vxx_0, 0)) tb.connect((gr_sig_source_x_0, 0), (gr_multiply_vxx_0, 1)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0, 0)) tb.connect((gr_multiply_vxx_0, 0), (gr_fir_filter_xxx_0_0_0, 0)) tb.connect((gr_fir_filter_xxx_0_0, 0), (gr_streams_to_stream_0, 0)) tb.connect((gr_fir_filter_xxx_0_0_0, 0), (gr_streams_to_stream_0, 1)) tb.connect((gr_streams_to_stream_0, 0), (gr_skiphead_0, 0)) tb.connect((gr_skiphead_0, 0), (viterbi, 0)) tb.connect((viterbi, 0), (gr_vector_sink_x_0, 0)) tb.run() dataest = gr_vector_sink_x_0.data() #print data #print numpy.array(dataest) perr = 0 err = 0 for i in range(blocksize): if data[head+i] != dataest[head+i]: #print i err += 1 if err != 0 : perr = 1 return (err,perr)
def __init__(self, samples_per_symbol=_def_samples_per_symbol, bits_per_symbol=_def_bits_per_symbol, h_numerator=_def_h_numerator, h_denominator=_def_h_denominator, cpm_type=_def_cpm_type, bt=_def_bt, symbols_per_pulse=_def_symbols_per_pulse, generic_taps=_def_generic_taps, verbose=_def_verbose, log=_def_log): """ Hierarchical block for Continuous Phase modulation. The input is a byte stream (unsigned char) representing packed bits and the output is the complex modulated signal at baseband. See Proakis for definition of generic CPM signals: s(t)=exp(j phi(t)) phi(t)= 2 pi h int_0^t f(t') dt' f(t)=sum_k a_k g(t-kT) (normalizing assumption: int_0^infty g(t) dt = 1/2) @param samples_per_symbol: samples per baud >= 2 @type samples_per_symbol: integer @param bits_per_symbol: bits per symbol @type bits_per_symbol: integer @param h_numerator: numerator of modulation index @type h_numerator: integer @param h_denominator: denominator of modulation index (numerator and denominator must be relative primes) @type h_denominator: integer @param cpm_type: supported types are: 0=CPFSK, 1=GMSK, 2=RC, 3=GENERAL @type cpm_type: integer @param bt: bandwidth symbol time product for GMSK @type bt: float @param symbols_per_pulse: shaping pulse duration in symbols @type symbols_per_pulse: integer @param generic_taps: define a generic CPM pulse shape (sum = samples_per_symbol/2) @type generic_taps: array of floats @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__( self, "cpm_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._samples_per_symbol = samples_per_symbol self._bits_per_symbol = bits_per_symbol self._h_numerator = h_numerator self._h_denominator = h_denominator self._cpm_type = cpm_type self._bt = bt if cpm_type == 0 or cpm_type == 2 or cpm_type == 3: # CPFSK, RC, Generic self._symbols_per_pulse = symbols_per_pulse elif cpm_type == 1: # GMSK self._symbols_per_pulse = 4 else: raise TypeError, ( "cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type, )) self._generic_taps = numpy.array(generic_taps) if samples_per_symbol < 2: raise TypeError, ("samples_per_symbol must be >= 2, is %r" % (samples_per_symbol, )) self.nsymbols = 2**bits_per_symbol self.sym_alphabet = numpy.arange(-(self.nsymbols - 1), self.nsymbols, 2).tolist() self.ntaps = int(self._symbols_per_pulse * samples_per_symbol) sensitivity = 2 * pi * h_numerator / h_denominator / samples_per_symbol # Unpack Bytes into bits_per_symbol groups self.B2s = gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) # Turn it into symmetric PAM data. self.pam = gr.chunks_to_symbols_bf(self.sym_alphabet, 1) # Generate pulse (sum of taps = samples_per_symbol/2) if cpm_type == 0: # CPFSK self.taps = (1.0 / self._symbols_per_pulse / 2, ) * self.ntaps elif cpm_type == 1: # GMSK gaussian_taps = gr.firdes.gaussian( 1.0 / 2, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time self.ntaps # number of taps ) sqwave = (1, ) * samples_per_symbol # rectangular window self.taps = numpy.convolve(numpy.array(gaussian_taps), numpy.array(sqwave)) elif cpm_type == 2: # Raised Cosine # generalize it for arbitrary roll-off factor self.taps = (1 - numpy.cos( 2 * pi * numpy.arange(0, self.ntaps) / samples_per_symbol / self._symbols_per_pulse)) / (2 * self._symbols_per_pulse) elif cpm_type == 3: # Generic CPM self.taps = generic_taps else: raise TypeError, ( "cpm_type must be an integer in {0,1,2,3}, is %r" % (cpm_type, )) self.filter = blks2.pfb_arb_resampler_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) if verbose: self._print_verbage() if log: self._setup_logging() # Connect self.connect(self, self.B2s, self.pam, self.filter, self.fmmod, self)
def __init__(self, output_sample_rate=_def_output_sample_rate, excess_bw=_def_excess_bw, reverse=_def_reverse, verbose=_def_verbose, log=_def_log): """ Hierarchical block for RRC-filtered P25 FM modulation. The input is a dibit (P25 symbol) stream (char, not packed) and the output is the float "C4FM" signal at baseband, suitable for application to an FM modulator stage Input is at the base symbol rate (4800), output sample rate is typically either 32000 (USRP TX chain) or 48000 (sound card) @param output_sample_rate: output sample rate @type output_sample_rate: integer @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float @param reverse: reverse polarity flag @type reverse: bool @param verbose: Print information about modulator? @type verbose: bool @param debug: Print modulation data to files? @type debug: bool """ gr.hier_block2.__init__(self, "p25_c4fm_mod_bf", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_float)) # Output signature input_sample_rate = 4800 # P25 baseband symbol rate lcm = gru.lcm(input_sample_rate, output_sample_rate) self._interp_factor = int(lcm // input_sample_rate) self._decimation = int(lcm // output_sample_rate) self._excess_bw = excess_bw mod_map = [1.0/3.0, 1.0, -(1.0/3.0), -1.0] self.C2S = gr.chunks_to_symbols_bf(mod_map) if reverse: self.polarity = gr.multiply_const_ff(-1) else: self.polarity = gr.multiply_const_ff( 1) ntaps = 11 * self._interp_factor rrc_taps = gr.firdes.root_raised_cosine( self._interp_factor, # gain (since we're interpolating by sps) lcm, # sampling rate input_sample_rate, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) # rrc_coeffs work slightly differently: each input sample # (from mod_map above) at 4800 rate, then 9 zeros are inserted # to bring to 48000 rate, then this filter is applied: # rrc_filter = gr.fir_filter_fff(1, rrc_coeffs) # FIXME: how to insert the 9 zero samples using gr ? # rrc_coeffs = [0, -0.003, -0.006, -0.009, -0.012, -0.014, -0.014, -0.013, -0.01, -0.006, 0, 0.007, 0.014, 0.02, 0.026, 0.029, 0.029, 0.027, 0.021, 0.012, 0, -0.013, -0.027, -0.039, -0.049, -0.054, -0.055, -0.049, -0.038, -0.021, 0, 0.024, 0.048, 0.071, 0.088, 0.098, 0.099, 0.09, 0.07, 0.039, 0, -0.045, -0.091, -0.134, -0.17, -0.193, -0.199, -0.184, -0.147, -0.085, 0, 0.105, 0.227, 0.36, 0.496, 0.629, 0.751, 0.854, 0.933, 0.983, 1, 0.983, 0.933, 0.854, 0.751, 0.629, 0.496, 0.36, 0.227, 0.105, 0, -0.085, -0.147, -0.184, -0.199, -0.193, -0.17, -0.134, -0.091, -0.045, 0, 0.039, 0.07, 0.09, 0.099, 0.098, 0.088, 0.071, 0.048, 0.024, 0, -0.021, -0.038, -0.049, -0.055, -0.054, -0.049, -0.039, -0.027, -0.013, 0, 0.012, 0.021, 0.027, 0.029, 0.029, 0.026, 0.02, 0.014, 0.007, 0, -0.006, -0.01, -0.013, -0.014, -0.014, -0.012, -0.009, -0.006, -0.003, 0] self.rrc_filter = gr.interp_fir_filter_fff(self._interp_factor, rrc_taps) # FM pre-emphasis filter shaping_coeffs = [-0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018] self.shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) if verbose: self._print_verbage() if log: self._setup_logging() self.connect(self, self.C2S, self.polarity, self.rrc_filter, self.shaping_filter) if (self._decimation > 1): self.decimator = blks2.rational_resampler_fff(1, self._decimation) self.connect(self.shaping_filter, self.decimator, self) else: self.connect(self.shaping_filter, self)
def __init__(self, options, queue): gr.top_block.__init__(self, "mhp") sample_rate = options.sample_rate arity = 2 IN = gr.file_source(gr.sizeof_char, options.input_file, options.repeat) B2C = gr.packed_to_unpacked_bb(arity, gr.GR_MSB_FIRST) mod_map = [1.0, 3.0, -1.0, -3.0] C2S = gr.chunks_to_symbols_bf(mod_map) if options.reverse: polarity = gr.multiply_const_ff(-1) else: polarity = gr.multiply_const_ff(1) symbol_rate = 4800 samples_per_symbol = sample_rate // symbol_rate excess_bw = 0.1 ntaps = 11 * samples_per_symbol rrc_taps = gr.firdes.root_raised_cosine( samples_per_symbol, # gain (sps since we're interpolating by sps samples_per_symbol, # sampling rate 1.0, # symbol rate excess_bw, # excess bandwidth (roll-off factor) ntaps) rrc_filter = gr.interp_fir_filter_fff(samples_per_symbol, rrc_taps) rrc_coeffs = [ 0, -0.003, -0.006, -0.009, -0.012, -0.014, -0.014, -0.013, -0.01, -0.006, 0, 0.007, 0.014, 0.02, 0.026, 0.029, 0.029, 0.027, 0.021, 0.012, 0, -0.013, -0.027, -0.039, -0.049, -0.054, -0.055, -0.049, -0.038, -0.021, 0, 0.024, 0.048, 0.071, 0.088, 0.098, 0.099, 0.09, 0.07, 0.039, 0, -0.045, -0.091, -0.134, -0.17, -0.193, -0.199, -0.184, -0.147, -0.085, 0, 0.105, 0.227, 0.36, 0.496, 0.629, 0.751, 0.854, 0.933, 0.983, 1, 0.983, 0.933, 0.854, 0.751, 0.629, 0.496, 0.36, 0.227, 0.105, 0, -0.085, -0.147, -0.184, -0.199, -0.193, -0.17, -0.134, -0.091, -0.045, 0, 0.039, 0.07, 0.09, 0.099, 0.098, 0.088, 0.071, 0.048, 0.024, 0, -0.021, -0.038, -0.049, -0.055, -0.054, -0.049, -0.039, -0.027, -0.013, 0, 0.012, 0.021, 0.027, 0.029, 0.029, 0.026, 0.02, 0.014, 0.007, 0, -0.006, -0.01, -0.013, -0.014, -0.014, -0.012, -0.009, -0.006, -0.003, 0 ] # rrc_coeffs work slightly differently: each input sample # (from mod_map above) at 4800 rate, then 9 zeros are inserted # to bring to a 48000 rate, then this filter is applied: # rrc_filter = gr.fir_filter_fff(1, rrc_coeffs) # FIXME: how to insert the 9 zero samples using gr ? # FM pre-emphasis filter shaping_coeffs = [ -0.018, 0.0347, 0.0164, -0.0064, -0.0344, -0.0522, -0.0398, 0.0099, 0.0798, 0.1311, 0.121, 0.0322, -0.113, -0.2499, -0.3007, -0.2137, -0.0043, 0.2825, 0.514, 0.604, 0.514, 0.2825, -0.0043, -0.2137, -0.3007, -0.2499, -0.113, 0.0322, 0.121, 0.1311, 0.0798, 0.0099, -0.0398, -0.0522, -0.0344, -0.0064, 0.0164, 0.0347, -0.018 ] shaping_filter = gr.fir_filter_fff(1, shaping_coeffs) OUT = audio.sink(sample_rate, options.audio_output) amp = gr.multiply_const_ff(options.factor) self.connect(IN, B2C, C2S, polarity, rrc_filter, shaping_filter, amp) # output to both L and R channels self.connect(amp, (OUT, 0)) self.connect(amp, (OUT, 1))