def test_ccf_000(self): N = 1000 # number of samples to use fs = 1000 # baseband sampling rate rrate = 1.123 # resampling rate nfilts = 32 taps = filter.firdes.low_pass_2(nfilts, nfilts*fs, fs/2, fs/10, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) freq = 100 data = sig_source_c(fs, freq, 1, N) signal = blocks.vector_source_c(data) pfb = filter.pfb_arb_resampler_ccf(rrate, taps) snk = blocks.vector_sink_c() self.tb.connect(signal, pfb, snk) self.tb.run() Ntest = 50 L = len(snk.data()) t = map(lambda x: float(x)/(fs*rrate), xrange(L)) phase = 0.53013 expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \ 1j*math.sin(2.*math.pi*freq*x+phase), t) dst_data = snk.data() self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
def test_ccf_000(self): N = 1000 # number of samples to use fs = 1000 # baseband sampling rate rrate = 1.123 # resampling rate nfilts = 32 taps = filter.firdes.low_pass_2( nfilts, nfilts * fs, fs / 2, fs / 10, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) freq = 100 data = sig_source_c(fs, freq, 1, N) signal = blocks.vector_source_c(data) pfb = filter.pfb_arb_resampler_ccf(rrate, taps) snk = blocks.vector_sink_c() self.tb.connect(signal, pfb, snk) self.tb.run() Ntest = 50 L = len(snk.data()) t = map(lambda x: float(x) / (fs * rrate), xrange(L)) phase = 0.53013 expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \ 1j*math.sin(2.*math.pi*freq*x+phase), t) dst_data = snk.data() self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3)
def __init__(self, input_rate, sps): gr.hier_block2.__init__( self, "atsc_rx_filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # Create matched RX filter with RRC response for fractional # interpolator. nfilts = 16 output_rate = ATSC_SYMBOL_RATE * sps # Desired oversampled sample rate filter_rate = input_rate * nfilts symbol_rate = ATSC_SYMBOL_RATE / 2.0 # One-sided bandwidth of sideband excess_bw = 0.1152 #1.0-(0.5*ATSC_SYMBOL_RATE/ATSC_CHANNEL_BW) # ~10.3% ntaps = int((2 * ATSC_RRC_SYMS + 1) * sps * nfilts) interp = output_rate / input_rate gain = nfilts * symbol_rate / filter_rate rrc_taps = filter.firdes.root_raised_cosine( gain, # Filter gain filter_rate, # PFB filter prototype rate symbol_rate, # ATSC symbol rate excess_bw, # ATSC RRC excess bandwidth ntaps) # Length of filter pfb = filter.pfb_arb_resampler_ccf(interp, rrc_taps, nfilts) # Connect pipeline self.connect(self, pfb, self)
def __init__(self): gr.top_block.__init__(self) parser = OptionParser(option_class=eng_option) parser.add_option("-c", "--calibration", type="eng_float", default=0, help="freq offset") parser.add_option("-g", "--gain", type="eng_float", default=1) parser.add_option("-i", "--input-file", type="string", default="in.dat", help="specify the input file") parser.add_option("-o", "--output-file", type="string", default="out.dat", help="specify the output file") parser.add_option("-r", "--new-sample-rate", type="int", default=96000, help="output sample rate") parser.add_option("-s", "--sample-rate", type="int", default=48000, help="input sample rate") (options, args) = parser.parse_args() sample_rate = options.sample_rate new_sample_rate = options.new_sample_rate IN = blocks.file_source(gr.sizeof_gr_complex, options.input_file) OUT = blocks.file_sink(gr.sizeof_gr_complex, options.output_file) LO = analog.sig_source_c(sample_rate, analog.GR_COS_WAVE, options.calibration, 1.0, 0) MIXER = blocks.multiply_cc() AMP = blocks.multiply_const_cc(options.gain) nphases = 32 frac_bw = 0.05 p1 = frac_bw p2 = frac_bw rs_taps = filter.firdes.low_pass(nphases, nphases, p1, p2) RESAMP = filter.pfb_arb_resampler_ccf(float(new_sample_rate) / float(sample_rate), (rs_taps), nphases, ) self.connect(IN, (MIXER, 0)) self.connect(LO, (MIXER, 1)) self.connect(MIXER, AMP, RESAMP, OUT)
def __init__(self, input_rate, sps): gr.hier_block2.__init__(self, "atsc_rx_filter", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature # Create matched RX filter with RRC response for fractional # interpolator. nfilts = 16 output_rate = ATSC_SYMBOL_RATE*sps # Desired oversampled sample rate filter_rate = input_rate*nfilts symbol_rate = ATSC_SYMBOL_RATE / 2.0 # One-sided bandwidth of sideband excess_bw = 0.1152 #1.0-(0.5*ATSC_SYMBOL_RATE/ATSC_CHANNEL_BW) # ~10.3% ntaps = int((2*ATSC_RRC_SYMS+1)*sps*nfilts) interp = output_rate / input_rate gain = nfilts*symbol_rate/filter_rate rrc_taps = filter.firdes.root_raised_cosine(gain, # Filter gain filter_rate, # PFB filter prototype rate symbol_rate, # ATSC symbol rate excess_bw, # ATSC RRC excess bandwidth ntaps) # Length of filter pfb = filter.pfb_arb_resampler_ccf(interp, rrc_taps, nfilts) # Connect pipeline self.connect(self, pfb, self)
def test02(self): # Test QPSK sync M = 4 theta = 0 loop_bw = cmath.pi / 100.0 fmin = -0.5 fmax = 0.5 mu = 0.5 gain_mu = 0.01 omega = 2 gain_omega = 0.001 omega_rel = 0.001 self.test = digital.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) data = 10000 * [ complex(0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, -0.707), complex(0.707, -0.707) ] data = [0.5 * d for d in data] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() # pulse shaping interpolation filter nfilts = 32 excess_bw = 0.35 ntaps = 11 * int(omega * nfilts) rrc_taps0 = filter.firdes.root_raised_cosine(nfilts, nfilts, 1.0, excess_bw, ntaps) rrc_taps1 = filter.firdes.root_raised_cosine(1, omega, 1.0, excess_bw, 11 * omega) self.rrc0 = filter.pfb_arb_resampler_ccf(omega, rrc_taps0) self.rrc1 = filter.fir_filter_ccf(1, rrc_taps1) self.tb.connect(self.src, self.rrc0, self.rrc1, self.test, self.snk) self.tb.run() expected_result = 10000 * [ complex(-0.5, +0.0), complex(+0.0, -0.5), complex(+0.5, +0.0), complex(+0.0, +0.5) ] dst_data = self.snk.data() # Only compare last Ncmp samples Nstrt = 30000 Ncmp = 1000 expected_result = expected_result[Nstrt:Nstrt + Ncmp] dst_data = dst_data[Nstrt:Nstrt + Ncmp] #for e,d in zip(expected_result, dst_data): # print "{0:+.02f} {1:+.02f}".format(e, d) self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def test_001(self): # We're using a really simple preamble so that the correlation # is straight forward. preamble = [0, 0, 0, 1, 0, 0, 0] # Our pulse shape has this width (in units of symbols). pulse_width = 1.5 # The number of filters to use for resampling. n_filters = 12 sps = 3 data = [0]*10 + preamble + [0]*40 src = blocks.vector_source_c(data) # We want to generate taps with a sampling rate of sps=n_filters for resampling # purposes. pulse_shape = make_parabolic_pulse_shape(sps=n_filters, N=0.5, scale=35) # Create our resampling filter to generate the data for the correlator. shape = filter.pfb_arb_resampler_ccf(sps, pulse_shape, n_filters) # Generate the correlator block itself. correlator = digital.correlate_and_sync_cc(preamble, pulse_shape, sps, n_filters) # Connect it all up and go. snk = blocks.vector_sink_c() null = blocks.null_sink(gr.sizeof_gr_complex) tb = gr.top_block() tb.connect(src, shape, correlator, snk) tb.connect((correlator, 1), null) tb.run() # Look at the tags. Retrieve the timing offset. data = snk.data() offset = None timing_error = None for tag in snk.tags(): key = pmt.symbol_to_string(tag.key) if key == "time_est": offset = tag.offset timing_error = pmt.to_double(tag.value) if offset is None: raise ValueError("No tags found.") # Detect where the middle of the preamble is. # Assume we have only one peak and that it is symmetric. sum_id = 0 sum_d = 0 for i, d in enumerate(data): sum_id += i*abs(d) sum_d += abs(d) data_i = sum_id/sum_d if offset is not None: diff = data_i-offset remainder = -(diff%sps) if remainder < -sps/2.0: remainder += sps tol = 0.2 difference = timing_error - remainder difference = difference % sps if abs(difference) >= tol: print("Tag gives timing estimate of {0}. QA calculates it as {1}. Tolerance is {2}".format(timing_error, remainder, tol)) self.assertTrue(abs(difference) < tol)
def test02(self): # Test QPSK sync M = 4 theta = 0 loop_bw = cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.5 gain_mu = 0.01 omega = 2 gain_omega = 0.001 omega_rel = 0.001 self.test = digital.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) data = 10000*[complex( 0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, -0.707), complex( 0.707, -0.707)] data = [0.5*d for d in data] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() # pulse shaping interpolation filter nfilts = 32 excess_bw = 0.35 ntaps = 11 * int(omega*nfilts) rrc_taps0 = filter.firdes.root_raised_cosine( nfilts, nfilts, 1.0, excess_bw, ntaps) rrc_taps1 = filter.firdes.root_raised_cosine( 1, omega, 1.0, excess_bw, 11*omega) self.rrc0 = filter.pfb_arb_resampler_ccf(omega, rrc_taps0) self.rrc1 = filter.fir_filter_ccf(1, rrc_taps1) self.tb.connect(self.src, self.rrc0, self.rrc1, self.test, self.snk) self.tb.run() expected_result = 10000*[complex(-0.5, +0.0), complex(+0.0, -0.5), complex(+0.5, +0.0), complex(+0.0, +0.5)] # get data after a settling period dst_data = self.snk.data()[200:] # Only compare last Ncmp samples Ncmp = 1000 len_e = len(expected_result) len_d = len(dst_data) expected_result = expected_result[len_e - Ncmp - 1:-1] dst_data = dst_data[len_d - Ncmp:] #for e,d in zip(expected_result, dst_data): # print "{0:+.02f} {1:+.02f}".format(e, d) self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def test01(self): # Test BPSK sync excess_bw = 0.35 sps = 4 loop_bw = cmath.pi/100.0 nfilts = 32 init_phase = nfilts/2 max_rate_deviation = 0.5 osps = 1 ntaps = 11 * int(sps*nfilts) taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, 1.0, excess_bw, ntaps) self.test = digital.pfb_clock_sync_ccf(sps, loop_bw, taps, nfilts, init_phase, max_rate_deviation, osps) data = 10000*[complex(1,0), complex(-1,0)] self.src = blocks.vector_source_c(data, False) # pulse shaping interpolation filter rrc_taps = filter.firdes.root_raised_cosine( nfilts, # gain nfilts, # sampling rate based on 32 filters in resampler 1.0, # symbol rate excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf(sps, rrc_taps) self.snk = blocks.vector_sink_c() self.tb.connect(self.src, self.rrc_filter, self.test, self.snk) self.tb.run() expected_result = 10000*[complex(1,0), complex(-1,0)] dst_data = self.snk.data() # Only compare last Ncmp samples Ncmp = 1000 len_e = len(expected_result) len_d = len(dst_data) expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] #for e,d in zip(expected_result, dst_data): # print e, d self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def test01(self): # Test BPSK sync excess_bw = 0.35 sps = 4 loop_bw = cmath.pi/100.0 nfilts = 32 init_phase = nfilts/2 max_rate_deviation = 0.5 osps = 1 ntaps = 11 * int(sps*nfilts) taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, 1.0, excess_bw, ntaps) self.test = digital.pfb_clock_sync_ccf(sps, loop_bw, taps, nfilts, init_phase, max_rate_deviation, osps) data = 10000*[complex(1,0), complex(-1,0)] self.src = blocks.vector_source_c(data, False) # pulse shaping interpolation filter rrc_taps = filter.firdes.root_raised_cosine( nfilts, # gain nfilts, # sampling rate based on 32 filters in resampler 1.0, # symbol rate excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf(sps, rrc_taps) self.snk = blocks.vector_sink_c() self.tb.connect(self.src, self.rrc_filter, self.test, self.snk) self.tb.run() expected_result = 10000*[complex(1,0), complex(-1,0)] dst_data = self.snk.data() # Only compare last Ncmp samples Ncmp = 1000 len_e = len(expected_result) len_d = len(dst_data) expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] #for e,d in zip(expected_result, dst_data): # print e, d self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def test01(self): # Test BPSK sync M = 2 theta = 0 loop_bw = cmath.pi / 100.0 fmin = -0.5 fmax = 0.5 mu = 0.5 gain_mu = 0.01 omega = 2 gain_omega = 0.001 omega_rel = 0.001 self.test = digital.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) data = 10000 * [complex(1, 0), complex(-1, 0)] #data = [2*random.randint(0,1)-1 for x in xrange(10000)] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() # pulse shaping interpolation filter nfilts = 32 excess_bw = 0.35 ntaps = 11 * int(omega * nfilts) rrc_taps0 = filter.firdes.root_raised_cosine(nfilts, nfilts, 1.0, excess_bw, ntaps) rrc_taps1 = filter.firdes.root_raised_cosine(1, omega, 1.0, excess_bw, 11 * omega) self.rrc0 = filter.pfb_arb_resampler_ccf(omega, rrc_taps0) self.rrc1 = filter.fir_filter_ccf(1, rrc_taps1) self.tb.connect(self.src, self.rrc0, self.rrc1, self.test, self.snk) self.tb.run() expected_result = [0.5 * d for d in data] dst_data = self.snk.data() # Only compare last Ncmp samples Ncmp = 1000 len_e = len(expected_result) len_d = len(dst_data) expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] #for e,d in zip(expected_result, dst_data): # print "{0:+.02f} {1:+.02f}".format(e, d) self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def test01(self): # Test BPSK sync M = 2 theta = 0 loop_bw = cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.5 gain_mu = 0.01 omega = 2 gain_omega = 0.001 omega_rel = 0.001 self.test = digital.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) data = 10000*[complex(1,0), complex(-1,0)] #data = [2*random.randint(0,1)-1 for x in xrange(10000)] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() # pulse shaping interpolation filter nfilts = 32 excess_bw = 0.35 ntaps = 11 * int(omega*nfilts) rrc_taps0 = filter.firdes.root_raised_cosine( nfilts, nfilts, 1.0, excess_bw, ntaps) rrc_taps1 = filter.firdes.root_raised_cosine( 1, omega, 1.0, excess_bw, 11*omega) self.rrc0 = filter.pfb_arb_resampler_ccf(omega, rrc_taps0) self.rrc1 = filter.fir_filter_ccf(1, rrc_taps1) self.tb.connect(self.src, self.rrc0, self.rrc1, self.test, self.snk) self.tb.run() expected_result = [-0.5*d for d in data] dst_data = self.snk.data() # Only Ncmp samples after Nstrt samples Nstrt = 9000 Ncmp = 1000 expected_result = expected_result[Nstrt:Nstrt+Ncmp] dst_data = dst_data[Nstrt:Nstrt+Ncmp] #for e,d in zip(expected_result, dst_data): # print "{0:+.02f} {1:+.02f}".format(e, d) self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1)
def __init__(self,byte_size,mod_type,samples_per_symbol,blk_num=-1): gr.hier_block2.__init__(self, "transmit_path", gr.io_signature(0,0,0), gr.io_signature(1,1,gr.sizeof_gr_complex)) self.mod_type = mod_type # bpsk or qpsk if(self.mod_type == "bpsk"): self.block_size = (byte_size+9)*8 else: self.block_size = (byte_size+9)*4 self.cp_size = 32 self.db_num = 1 self.eb_num = 1 self.samples_per_symbol = samples_per_symbol self.excess_bw = 0.35 self.amp = 2.0 self.src = scfde.modulate_message_c(block_size=self.block_size, mod_type=self.mod_type, msgq_limit=4, block_num=blk_num) self.insert_esti = scfde.insert_esti_block_ccb( block_size=self.block_size, db_num=self.db_num, eb_num=self.eb_num) self.insert_sync = scfde.insert_sync_block_cbc(block_size=self.block_size) self.insert_cp = scfde.insert_cp_cc(block_size=self.block_size, cp_size=self.cp_size) self.p_to_s = scfde.parallel_to_serial_cc(ratio=self.block_size+self.cp_size) #pulse shaping nfilts = 32 ntaps = nfilts*11*int(self.samples_per_symbol) self.rrc_taps = filter.firdes.root_raised_cosine( nfilts,nfilts,1.0,self.excess_bw,ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf(self.samples_per_symbol, self.rrc_taps) self.amplifier = blocks.multiply_const_cc(self.amp) self.connect(self.src,self.insert_esti) self.connect((self.insert_esti,0),(self.insert_sync,0)) self.connect((self.insert_esti,1),(self.insert_sync,1)) self.connect(self.insert_sync,self.insert_cp) self.connect(self.insert_cp,self.p_to_s,self.rrc_filter,self.amplifier,self)
def __init__(self, mod_name="", samp_per_sym=2, excess_bw=.35): gr.hier_block2.__init__(self, mod_name, gr.io_signature(0, 0, 0), gr.io_signature(1, 1, gr.sizeof_gr_complex)) self.random_source = \ blocks.vector_source_b( map(int, np.random.randint(0, 255, int(1e6))), True ) num_filters = 32 num_taps = num_filters * 11 * int( samp_per_sym) # make nfilts filters of ntaps each rrc_taps = filter.firdes.root_raised_cosine( num_filters, # gain num_filters, # sampling rate based on 32 filters in resampler 1.0, # symbol rate excess_bw, # excess bandwidth (roll-off factor) num_taps) self.rrc_filter = filter.pfb_arb_resampler_ccf(samp_per_sym, rrc_taps) self.rrc_filter.declare_sample_delay(0)
def test_ccf_000(self): N = 5000 # number of samples to use fs = 5000.0 # baseband sampling rate rrate = 2.4321 # resampling rate nfilts = 32 taps = filter.firdes.low_pass_2(nfilts, nfilts*fs, fs/2, fs/10, attenuation_dB=80, window=filter.firdes.WIN_BLACKMAN_hARRIS) freq = 211.123 data = sig_source_c(fs, freq, 1, N) signal = blocks.vector_source_c(data) pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts) snk = blocks.vector_sink_c() self.tb.connect(signal, pfb, snk) self.tb.run() Ntest = 50 L = len(snk.data()) # Get group delay and estimate of phase offset from the filter itself. delay = pfb.group_delay() phase = pfb.phase_offset(freq, fs) # Create a timeline offset by the filter's group delay t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay)) # Data of the sinusoid at frequency freq with the delay and phase offset. expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \ 1j*math.sin(2.*math.pi*freq*x+phase), t) dst_data = snk.data() self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 2)
def __init__(self, frame_preamble, sync_word, append_crc, whitening, manchester, msb_first, ax25_format, dest_addr, dest_ssid, src_addr, src_ssid, settling_samples, samps_per_symbol, interpolation_taps, samp_rate, lo_offset, deviation, baud_rate): gr.hier_block2.__init__(self, "satnogs_upsat_transmitter", gr.io_signature(0 , 0 , 0), # Output 0: The complex TX signal for the SDR device # Output 1: The constellation output for the vector analyzer gr.io_signature(1, 1, sizeof_gr_complex)) self.frame_preamble = frame_preamble self.sync_word = sync_word self.append_crc = append_crc self.whitening = whitening self.manchester = manchester self.msb_first = msb_first self.ax25_format = ax25_format self.dest_addr = dest_addr self.dest_ssid = dest_ssid self.src_addr = src_addr self.src_ssid = src_ssid self.settling_samples = settling_samples self.samps_per_symbol = samps_per_symbol self.interpolation_taps = interpolation_taps self.samp_rate = samp_rate self.lo_offset = lo_offset self.deviation=deviation self.baud_rate=baud_rate self.message_port_register_hier_out("in") self.modulation_index = self.deviation/(self.baud_rate / 2.0) self.sensitivity = (math.pi*self.modulation_index) / self.samps_per_symbol self.resampling_rate = self.samp_rate / (self.baud_rate*self.samps_per_symbol ) self.par_taps = filter.firdes.low_pass_2(32, 32, 0.8, 0.1, 60) self.num_filters = 32 #================================================================= # TX Related blocks #================================================================= self.fsk_frame_encoder = satnogs_swig.upsat_fsk_frame_encoder(self.frame_preamble, self.sync_word, self.append_crc, self.whitening, self.manchester, self.msb_first, self.ax25_format, self.dest_addr, self.dest_ssid, self.src_addr, self.src_ssid, self.settling_samples ) self.interp_fir_filter = filter.interp_fir_filter_fff(self.samps_per_symbol, self.interpolation_taps ) self.frequency_modulator = analog.frequency_modulator_fc(self.sensitivity) self.signal_source = analog.sig_source_c(self.samp_rate, 102, self.lo_offset, 1, 0) self.polyphase_arbitrary_resampler = filter.pfb_arb_resampler_ccf(self.resampling_rate, self.par_taps, self.num_filters) self.multiply = blocks.multiply_cc(1) #================================================================= # Connections #================================================================= self.msg_connect((self, "in"), (self.fsk_frame_encoder, "pdu")) self.connect((self.fsk_frame_encoder, 0), (self.interp_fir_filter, 0)) self.connect((self.interp_fir_filter, 0), (self.frequency_modulator, 0)) self.connect((self.frequency_modulator, 0), (self.polyphase_arbitrary_resampler, 0)) self.connect((self.signal_source, 0) , (self.multiply, 0)) self.connect((self.polyphase_arbitrary_resampler, 0) , (self.multiply, 1)) self.connect((self.multiply, 0), self)
def __init__(self, frame_preamble, sync_word, append_crc, whitening, manchester, msb_first, ax25_format, dest_addr, dest_ssid, src_addr, src_ssid, settling_samples, samps_per_symbol, interpolation_taps, samp_rate, lo_offset, deviation, baud_rate): gr.hier_block2.__init__( self, "satnogs_upsat_transmitter", gr.io_signature(0, 0, 0), # Output 0: The complex TX signal for the SDR device # Output 1: The constellation output for the vector analyzer gr.io_signature(1, 1, sizeof_gr_complex)) self.frame_preamble = frame_preamble self.sync_word = sync_word self.append_crc = append_crc self.whitening = whitening self.manchester = manchester self.msb_first = msb_first self.ax25_format = ax25_format self.dest_addr = dest_addr self.dest_ssid = dest_ssid self.src_addr = src_addr self.src_ssid = src_ssid self.settling_samples = settling_samples self.samps_per_symbol = samps_per_symbol self.interpolation_taps = interpolation_taps self.samp_rate = samp_rate self.lo_offset = lo_offset self.deviation = deviation self.baud_rate = baud_rate self.message_port_register_hier_out("in") self.modulation_index = self.deviation / (self.baud_rate / 2.0) self.sensitivity = (math.pi * self.modulation_index) / self.samps_per_symbol self.resampling_rate = self.samp_rate / (self.baud_rate * self.samps_per_symbol) self.par_taps = filter.firdes.low_pass_2(32, 32, 0.8, 0.1, 60) self.num_filters = 32 #================================================================= # TX Related blocks #================================================================= self.fsk_frame_encoder = satnogs_swig.upsat_fsk_frame_encoder( self.frame_preamble, self.sync_word, self.append_crc, self.whitening, self.manchester, self.msb_first, self.ax25_format, self.dest_addr, self.dest_ssid, self.src_addr, self.src_ssid, self.settling_samples) self.interp_fir_filter = filter.interp_fir_filter_fff( self.samps_per_symbol, self.interpolation_taps) self.frequency_modulator = analog.frequency_modulator_fc( self.sensitivity) self.signal_source = analog.sig_source_c(self.samp_rate, 102, self.lo_offset, 1, 0) self.polyphase_arbitrary_resampler = filter.pfb_arb_resampler_ccf( self.resampling_rate, self.par_taps, self.num_filters) self.multiply = blocks.multiply_cc(1) #================================================================= # Connections #================================================================= self.msg_connect((self, "in"), (self.fsk_frame_encoder, "pdu")) self.connect((self.fsk_frame_encoder, 0), (self.interp_fir_filter, 0)) self.connect((self.interp_fir_filter, 0), (self.frequency_modulator, 0)) self.connect((self.frequency_modulator, 0), (self.polyphase_arbitrary_resampler, 0)) self.connect((self.signal_source, 0), (self.multiply, 0)) self.connect((self.polyphase_arbitrary_resampler, 0), (self.multiply, 1)) self.connect((self.multiply, 0), self)
def test_001(self): # We're using a really simple preamble so that the correlation # is straight forward. preamble = [0, 0, 0, 1, 0, 0, 0] # Our pulse shape has this width (in units of symbols). pulse_width = 1.5 # The number of filters to use for resampling. n_filters = 12 sps = 3 data = [0] * 10 + preamble + [0] * 40 src = blocks.vector_source_c(data) # We want to generate taps with a sampling rate of sps=n_filters for resampling # purposes. pulse_shape = make_parabolic_pulse_shape(sps=n_filters, N=0.5, scale=35) # Create our resampling filter to generate the data for the correlator. shape = filter.pfb_arb_resampler_ccf(sps, pulse_shape, n_filters) # Generate the correlator block itself. correlator = digital.correlate_and_sync_cc(preamble, pulse_shape, sps, n_filters) # Connect it all up and go. snk = blocks.vector_sink_c() null = blocks.null_sink(gr.sizeof_gr_complex) tb = gr.top_block() tb.connect(src, shape, correlator, snk) tb.connect((correlator, 1), null) tb.run() # Look at the tags. Retrieve the timing offset. data = snk.data() offset = None timing_error = None for tag in snk.tags(): key = pmt.symbol_to_string(tag.key) if key == "time_est": offset = tag.offset timing_error = pmt.to_double(tag.value) if offset is None: raise ValueError("No tags found.") # Detect where the middle of the preamble is. # Assume we have only one peak and that it is symmetric. sum_id = 0 sum_d = 0 for i, d in enumerate(data): sum_id += i * abs(d) sum_d += abs(d) data_i = sum_id / sum_d if offset is not None: diff = data_i - offset remainder = -(diff % sps) if remainder < -sps / 2.0: remainder += sps tol = 0.2 difference = timing_error - remainder difference = difference % sps if abs(difference) >= tol: print( "Tag gives timing estimate of {0}. QA calculates it as {1}. Tolerance is {2}" .format(timing_error, remainder, tol)) self.assertTrue(abs(difference) < tol)
def __init__(self, constellation, differential=_def_differential, samples_per_symbol=_def_samples_per_symbol, pre_diff_code=True, excess_bw=_def_excess_bw, verbose=_def_verbose, log=_def_log): gr.hier_block2.__init__(self, "generic_mod", gr.io_signature(1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._constellation = constellation self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw self._differential = differential # Only apply a predifferential coding if the constellation also supports it. self.pre_diff_code = pre_diff_code and self._constellation.apply_pre_diff_code() if self._samples_per_symbol < 2: raise TypeError, ("sbp must be >= 2, is %f" % self._samples_per_symbol) arity = pow(2,self.bits_per_symbol()) # turn bytes into k-bit vectors self.bytes2chunks = \ blocks.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) if self.pre_diff_code: self.symbol_mapper = digital.map_bb(self._constellation.pre_diff_code()) if differential: self.diffenc = digital.diff_encoder_bb(arity) self.chunks2symbols = digital.chunks_to_symbols_bc(self._constellation.points()) # pulse shaping filter nfilts = 32 ntaps = nfilts * 11 * int(self._samples_per_symbol) # make nfilts filters of ntaps each self.rrc_taps = filter.firdes.root_raised_cosine( nfilts, # gain nfilts, # sampling rate based on 32 filters in resampler 1.0, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps) # Connect self._blocks = [self, self.bytes2chunks] if self.pre_diff_code: self._blocks.append(self.symbol_mapper) if differential: self._blocks.append(self.diffenc) self._blocks += [self.chunks2symbols, self.rrc_filter, self] self.connect(*self._blocks) if verbose: self._print_verbage() if log: self._setup_logging()
def __init__(self, constellation, differential=_def_differential, samples_per_symbol=_def_samples_per_symbol, pre_diff_code=True, excess_bw=_def_excess_bw, verbose=_def_verbose, log=_def_log, truncate=_def_truncate): gr.hier_block2.__init__( self, "generic_mod", # Input signature gr.io_signature(1, 1, gr.sizeof_char), gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature self._constellation = constellation self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw self._differential = differential # Only apply a predifferential coding if the constellation also supports it. self.pre_diff_code = pre_diff_code and self._constellation.apply_pre_diff_code( ) if self._samples_per_symbol < 2: raise TypeError("sps must be >= 2, is %f" % self._samples_per_symbol) arity = pow(2, self.bits_per_symbol()) # turn bytes into k-bit vectors self.bytes2chunks = \ blocks.packed_to_unpacked_bb( self.bits_per_symbol(), gr.GR_MSB_FIRST) if self.pre_diff_code: self.symbol_mapper = digital.map_bb( self._constellation.pre_diff_code()) if differential: self.diffenc = digital.diff_encoder_bb(arity) self.chunks2symbols = digital.chunks_to_symbols_bc( self._constellation.points()) # pulse shaping filter nfilts = 32 ntaps_per_filt = 11 # make nfilts filters of ntaps each ntaps = nfilts * ntaps_per_filt * int(self._samples_per_symbol) self.rrc_taps = filter.firdes.root_raised_cosine( nfilts, # gain nfilts, # sampling rate based on 32 filters in resampler 1.0, # symbol rate self._excess_bw, # excess bandwidth (roll-off factor) ntaps) self.rrc_filter = filter.pfb_arb_resampler_ccf( self._samples_per_symbol, self.rrc_taps) # Remove the filter transient at the beginning of the transmission if truncate: fsps = float(self._samples_per_symbol) # Length of delay through rrc filter len_filt_delay = int((ntaps_per_filt * fsps * fsps - fsps) / 2.0) self.skiphead = blocks.skiphead(gr.sizeof_gr_complex * 1, len_filt_delay) # Connect self._blocks = [self, self.bytes2chunks] if self.pre_diff_code: self._blocks.append(self.symbol_mapper) if differential: self._blocks.append(self.diffenc) self._blocks += [self.chunks2symbols, self.rrc_filter] if truncate: self._blocks.append(self.skiphead) self._blocks.append(self) self.connect(*self._blocks) if verbose: self._print_verbage() if log: self._setup_logging()
def __init__(self): grc_wxgui.top_block_gui.__init__(self, title="Top Block") options = get_options() self.ifreq = options.frequency self.rfgain = options.gain self.src = osmosdr.source(options.args) self.src.set_center_freq(self.ifreq) self.src.set_sample_rate(int(options.sample_rate)) if self.rfgain is None: self.src.set_gain_mode(1) self.iagc = 1 self.rfgain = 0 else: self.iagc = 0 self.src.set_gain_mode(0) self.src.set_gain(self.rfgain) # may differ from the requested rate sample_rate = self.src.get_sample_rate() sys.stderr.write("sample rate: %d\n" % (sample_rate)) symbol_rate = 18000 sps = 2 # output rate will be 36,000 out_sample_rate = symbol_rate * sps options.low_pass = options.low_pass / 2.0 if sample_rate == 96000: # FunCube Dongle first_decim = 2 else: first_decim = 10 self.offset = 0 taps = firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.2, firdes.WIN_HANN) self.tuner = filter.freq_xlating_fir_filter_ccf(first_decim, taps, self.offset, sample_rate) self.demod = cqpsk.cqpsk_demod( samples_per_symbol = sps, excess_bw=0.35, costas_alpha=0.03, gain_mu=0.05, mu=0.05, omega_relative_limit=0.05, log=options.log, verbose=options.verbose) self.output = blocks.file_sink(gr.sizeof_float, options.output_file) rerate = float(sample_rate / float(first_decim)) / float(out_sample_rate) sys.stderr.write("resampling factor: %f\n" % rerate) if rerate.is_integer(): sys.stderr.write("using pfb decimator\n") self.resamp = filter.pfb.decimator_ccf(int(rerate), None, 0, 110) #self.resamp = filter.pfb_decimator_ccf(int(rerate), taps, 0, 110) else: sys.stderr.write("using pfb resampler\n") self.resamp = filter.pfb_arb_resampler_ccf(1 / rerate) self.connect(self.src, self.tuner, self.resamp, self.demod, self.output) self.Main = wx.Notebook(self.GetWin(), style=wx.NB_TOP) self.Main.AddPage(grc_wxgui.Panel(self.Main), "Wideband Spectrum") self.Main.AddPage(grc_wxgui.Panel(self.Main), "Channel Spectrum") self.Main.AddPage(grc_wxgui.Panel(self.Main), "Soft Bits") def set_ifreq(ifreq): self.ifreq = ifreq self._ifreq_text_box.set_value(self.ifreq) self.src.set_center_freq(self.ifreq) self._ifreq_text_box = forms.text_box( parent=self.GetWin(), value=self.ifreq, callback=set_ifreq, label="Center Frequency", converter=forms.float_converter(), ) self.Add(self._ifreq_text_box) def set_iagc(iagc): self.iagc = iagc self._agc_check_box.set_value(self.iagc) self.src.set_gain_mode(self.iagc, 0) self.src.set_gain(0 if self.iagc == 1 else self.rfgain, 0) self._agc_check_box = forms.check_box( parent=self.GetWin(), value=self.iagc, callback=set_iagc, label="Automatic Gain", true=1, false=0, ) self.Add(self._agc_check_box) def set_rfgain(rfgain): self.rfgain = rfgain self._rfgain_slider.set_value(self.rfgain) self._rfgain_text_box.set_value(self.rfgain) self.src.set_gain(0 if self.iagc == 1 else self.rfgain, 0) _rfgain_sizer = wx.BoxSizer(wx.VERTICAL) self._rfgain_text_box = forms.text_box( parent=self.GetWin(), sizer=_rfgain_sizer, value=self.rfgain, callback=set_rfgain, label="RF Gain", converter=forms.float_converter(), proportion=0, ) self._rfgain_slider = forms.slider( parent=self.GetWin(), sizer=_rfgain_sizer, value=self.rfgain, callback=set_rfgain, minimum=0, maximum=50, num_steps=200, style=wx.SL_HORIZONTAL, cast=float, proportion=1, ) self.Add(_rfgain_sizer) self.Add(self.Main) def fftsink2_callback(x, y): if abs(x / (sample_rate / 2)) > 0.9: set_ifreq(self.ifreq + x / 2) else: sys.stderr.write("coarse tuned to: %d Hz\n" % x) self.offset = -x self.tuner.set_center_freq(self.offset) self.scope = fftsink2.fft_sink_c(self.Main.GetPage(0).GetWin(), title="Wideband Spectrum (click to coarse tune)", fft_size=1024, sample_rate=sample_rate, ref_scale=2.0, ref_level=0, y_divs=10, fft_rate=10, average=False, avg_alpha=0.6) self.Main.GetPage(0).Add(self.scope.win) self.scope.set_callback(fftsink2_callback) self.connect(self.src, self.scope) def fftsink2_callback2(x, y): self.offset = self.offset - (x / 10) sys.stderr.write("fine tuned to: %d Hz\n" % self.offset) self.tuner.set_center_freq(self.offset) self.scope2 = fftsink2.fft_sink_c(self.Main.GetPage(1).GetWin(), title="Channel Spectrum (click to fine tune)", fft_size=1024, sample_rate=out_sample_rate, ref_scale=2.0, ref_level=-20, y_divs=10, fft_rate=10, average=False, avg_alpha=0.6) self.Main.GetPage(1).Add(self.scope2.win) self.scope2.set_callback(fftsink2_callback2) self.connect(self.resamp, self.scope2) self.scope3 = scopesink2.scope_sink_f( self.Main.GetPage(2).GetWin(), title="Soft Bits", sample_rate=out_sample_rate, v_scale=0, v_offset=0, t_scale=0.001, ac_couple=False, xy_mode=False, num_inputs=1, trig_mode=wxgui.TRIG_MODE_AUTO, y_axis_label="Counts", ) self.Main.GetPage(2).Add(self.scope3.win) self.connect(self.demod, self.scope3)