def __init__(self, center_freq, offset_freq, decimate_am=1, play_audio=False): """Configure the RTL-SDR and GNU Radio""" super(rtlsdr_am_stream, self).__init__() audio_rate = 44100 device_rate = audio_rate * 25 output_rate = audio_rate / float(decimate_am) self.rate = output_rate self.osmosdr_source = osmosdr.source("") self.osmosdr_source.set_center_freq(freq) self.osmosdr_source.set_sample_rate(device_rate) taps = filter.firdes_low_pass(1, device_rate, 40000, 5000, firdes.WIN_HAMMING, 6.76) self.freq_filter = freq_xlating_fir_filter_ccc(25, taps, -freq_offs, device_rate) self.am_demod = analog.am_demod_cf( channel_rate=audio_rate, audio_decim=1, audio_pass=5000, audio_stop=5500, ) self.resampler = filter.rational_resampler_fff( interpolation=1, decimation=decimate_am, ) self.sink = gr_queue.queue_sink_f() self.connect(self.osmosdr_source, self.freq_filter, self.am_demod) self.connect(self.am_demod, self.resampler, self.sink) if play_audio: self.audio_sink = audio.sink(audio_rate, "", True) self.connect(self.am_demod, self.audio_sink)
def __init__(self, samp_rate=4E6, audio_rate=8000, record=True): gr.hier_block2.__init__(self, "TunerDemod", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) # Default values self.center_freq = 0 squelch_db = -60 self.quad_demod_gain = 0.050 self.file_name = "/dev/null" self.record = record # Decimation values for four stages of decimation decims = (5, int(samp_rate / 1E6)) # Low pass filter taps for decimation by 5 low_pass_filter_taps_0 = \ grfilter.firdes_low_pass(1, 1, 0.090, 0.010, grfilter.firdes.WIN_HAMMING) # Frequency translating FIR filter decimating by 5 self.freq_xlating_fir_filter_ccc = \ grfilter.freq_xlating_fir_filter_ccc(decims[0], low_pass_filter_taps_0, self.center_freq, samp_rate) # FIR filter decimating by 5 fir_filter_ccc_0 = grfilter.fir_filter_ccc(decims[0], low_pass_filter_taps_0) # Low pass filter taps for decimation from samp_rate/25 to 40-79.9 ksps # In other words, decimation by int(samp_rate/1E6) # 12.5 kHz cutoff for NBFM channel bandwidth low_pass_filter_taps_1 = grfilter.firdes_low_pass( 1, samp_rate / decims[0]**2, 12.5E3, 1E3, grfilter.firdes.WIN_HAMMING) # FIR filter decimation by int(samp_rate/1E6) fir_filter_ccc_1 = grfilter.fir_filter_ccc(decims[1], low_pass_filter_taps_1) # Non blocking power squelch self.analog_pwr_squelch_cc = analog.pwr_squelch_cc( squelch_db, 1e-1, 0, False) # Quadrature demod with gain set for decent audio # This will be later multiplied by the volume self.analog_quadrature_demod_cf = \ analog.quadrature_demod_cf(self.quad_demod_gain) # 3.5 kHz cutoff for audio bandwidth low_pass_filter_taps_2 = grfilter.firdes_low_pass(1,\ samp_rate/(decims[1] * decims[0]**2),\ 3.5E3, 500, grfilter.firdes.WIN_HAMMING) # FIR filter decimating by 5 from 40-79.9 ksps to 8-15.98 ksps fir_filter_fff_0 = grfilter.fir_filter_fff(decims[0], low_pass_filter_taps_2) # Polyphase resampler allows arbitary RF sample rates # Takes 8-15.98 ksps to a constant 8 ksps for audio pfb_resamp = audio_rate / float(samp_rate / (decims[1] * decims[0]**3)) pfb_arb_resampler_fff = pfb.arb_resampler_fff(pfb_resamp, taps=None, flt_size=32) # Connect the blocks for the demod self.connect(self, self.freq_xlating_fir_filter_ccc) self.connect(self.freq_xlating_fir_filter_ccc, fir_filter_ccc_0) self.connect(fir_filter_ccc_0, fir_filter_ccc_1) self.connect(fir_filter_ccc_1, self.analog_pwr_squelch_cc) self.connect(self.analog_pwr_squelch_cc, self.analog_quadrature_demod_cf) self.connect(self.analog_quadrature_demod_cf, fir_filter_fff_0) self.connect(fir_filter_fff_0, pfb_arb_resampler_fff) self.connect(pfb_arb_resampler_fff, self) # Need to set this to a very low value of -200 since it is after demod # Only want it to gate when the previuos squelch has gone to zero analog_pwr_squelch_ff = analog.pwr_squelch_ff(-200, 1e-1, 0, True) # File sink with single channel and 8 bits/sample self.blocks_wavfile_sink = blocks.wavfile_sink(self.file_name, 1, audio_rate, 8) # Connect the blocks for recording self.connect(pfb_arb_resampler_fff, analog_pwr_squelch_ff) self.connect(analog_pwr_squelch_ff, self.blocks_wavfile_sink)
def __init__(self, dab_params, rx_params, verbose=False, debug=False): """ Hierarchical block for OFDM demodulation @param dab_params DAB parameter object (dab.parameters.dab_parameters) @param rx_params RX parameter object (dab.parameters.receiver_parameters) @param debug enables debug output to files @param verbose whether to produce verbose messages """ self.dp = dp = dab_params self.rp = rp = rx_params self.verbose = verbose if self.rp.softbits: gr.hier_block2.__init__(self,"ofdm_demod", gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_float*self.dp.num_carriers*2, gr.sizeof_char)) # output signature else: gr.hier_block2.__init__(self,"ofdm_demod", gr.io_signature (1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature2(2, 2, gr.sizeof_char*self.dp.num_carriers/4, gr.sizeof_char)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) #self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.input = blocks.multiply_const_cc(1.0) # FIXME self.connect(self, self.input) # input filtering if self.rp.input_fft_filter: if verbose: print "--> RX filter enabled" lowpass_taps = filter.firdes_low_pass(1.0, # gain dp.sample_rate, # sampling rate rp.filt_bw, # cutoff frequency rp.filt_tb, # width of transition band filter.firdes.WIN_HAMMING) # Hamming window self.fft_filter = filter.fft_filter_ccc(1, lowpass_taps) # correct sample rate offset, if enabled if self.rp.autocorrect_sample_rate: if verbose: print "--> dynamic sample rate correction enabled" self.rate_detect_ns = dab.detect_null(dp.ns_length, False) self.rate_estimator = dab.estimate_sample_rate_bf(dp.sample_rate, dp.frame_length) self.rate_prober = blocks.probe_signal_f() self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober) # self.resample = gr.fractional_interpolator_cc(0, 1) self.resample = dab.fractional_interpolator_triggered_update_cc(0,1) self.connect(self.rate_detect_ns, (self.resample,1)) self.updater = Timer(0.1,self.update_correction) # self.updater = threading.Thread(target=self.update_correction) self.run_interpolater_update_thread = True self.updater.setDaemon(True) self.updater.start() else: self.run_interpolater_update_thread = False if self.rp.sample_rate_correction_factor != 1: if verbose: print "--> static sample rate correction enabled" self.resample = gr.fractional_interpolator_cc(0, self.rp.sample_rate_correction_factor) # timing and fine frequency synchronisation self.sync = dab.ofdm_sync_dab2(self.dp, self.rp, debug) # ofdm symbol sampler self.sampler = dab.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap) # fft for symbol vectors self.fft = fft.fft_vcc(dp.fft_length, True, [], True) # coarse frequency synchronisation self.cfs = dab.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length) # diff phasor self.phase_diff = dab.diff_phasor_vcc(dp.num_carriers) # remove pilot symbol self.remove_pilot = dab.ofdm_remove_first_symbol_vcc(dp.num_carriers) # magnitude equalisation if self.rp.equalize_magnitude: if verbose: print "--> magnitude equalization enabled" self.equalizer = dab.magnitude_equalizer_vcc(dp.num_carriers, rp.symbols_for_magnitude_equalization) # frequency deinterleaving self.deinterleave = dab.frequency_interleaver_vcc(dp.frequency_deinterleaving_sequence_array) # symbol demapping self.demapper = dab.qpsk_demapper_vcb(dp.num_carriers) # # connect everything # if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1: self.connect(self.input, self.resample) self.input2 = self.resample else: self.input2 = self.input if self.rp.input_fft_filter: self.connect(self.input2, self.fft_filter, self.sync) else: self.connect(self.input2, self.sync) # data stream self.connect((self.sync, 0), (self.sampler, 0), self.fft, (self.cfs, 0), self.phase_diff, (self.remove_pilot,0)) if self.rp.equalize_magnitude: self.connect((self.remove_pilot,0), (self.equalizer,0), self.deinterleave) else: self.connect((self.remove_pilot,0), self.deinterleave) if self.rp.softbits: if verbose: print "--> using soft bits" self.softbit_interleaver = dab.complex_to_interleaved_float_vcf(self.dp.num_carriers) self.connect(self.deinterleave, self.softbit_interleaver, (self,0)) else: self.connect(self.deinterleave, self.demapper, (self,0)) # control stream self.connect((self.sync, 1), (self.sampler, 1), (self.cfs, 1), (self.remove_pilot,1)) if self.rp.equalize_magnitude: self.connect((self.remove_pilot,1), (self.equalizer,1), (self,1)) else: self.connect((self.remove_pilot,1), (self,1)) # calculate an estimate of the SNR self.phase_var_decim = blocks.keep_one_in_n(gr.sizeof_gr_complex*self.dp.num_carriers, self.rp.phase_var_estimate_downsample) self.phase_var_arg = blocks.complex_to_arg(dp.num_carriers) self.phase_var_v2s = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers) self.phase_var_mod = dab.modulo_ff(pi/2) self.phase_var_avg_mod = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) self.phase_var_sub_avg = blocks.sub_ff() self.phase_var_sqr = blocks.multiply_ff() self.phase_var_avg = filter.iir_filter_ffd([rp.phase_var_estimate_alpha], [0,1-rp.phase_var_estimate_alpha]) self.probe_phase_var = blocks.probe_signal_f() self.connect((self.remove_pilot,0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg,0), (self.phase_var_sqr,0)) self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg,1)) self.connect(self.phase_var_sub_avg, (self.phase_var_sqr,1)) self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var) # measure processing rate self.measure_rate = dab.measure_processing_rate(gr.sizeof_gr_complex, 2000000) self.connect(self.input, self.measure_rate) # debugging if debug: self.connect(self.fft, blocks.file_sink(gr.sizeof_gr_complex*dp.fft_length, "debug/ofdm_after_fft.dat")) self.connect((self.cfs,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_after_cfs.dat")) self.connect(self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_diff_phasor.dat")) self.connect((self.remove_pilot,0), blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_pilot_removed.dat")) self.connect((self.remove_pilot,1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat")) self.connect(self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_deinterleaved.dat")) if self.rp.equalize_magnitude: self.connect(self.equalizer, blocks.file_sink(gr.sizeof_gr_complex*dp.num_carriers, "debug/ofdm_equalizer.dat")) if self.rp.softbits: self.connect(self.softbit_interleaver, blocks.file_sink(gr.sizeof_float*dp.num_carriers*2, "debug/softbits.dat"))
def __init__(self, samp_rate=4E6, audio_rate=8000, record=True): gr.hier_block2.__init__(self, "TunerDemodNBFM", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) # Default values self.center_freq = 0 squelch_db = -60 self.quad_demod_gain = 0.050 self.file_name = "/dev/null" self.record = record # Decimation values for four stages of decimation decims = (5, int(samp_rate/1E6)) # Low pass filter taps for decimation by 5 low_pass_filter_taps_0 = \ grfilter.firdes_low_pass(1, 1, 0.090, 0.010, grfilter.firdes.WIN_HAMMING) # Frequency translating FIR filter decimating by 5 self.freq_xlating_fir_filter_ccc = \ grfilter.freq_xlating_fir_filter_ccc(decims[0], low_pass_filter_taps_0, self.center_freq, samp_rate) # FIR filter decimating by 5 fir_filter_ccc_0 = grfilter.fir_filter_ccc(decims[0], low_pass_filter_taps_0) # Low pass filter taps for decimation from samp_rate/25 to 40-79.9 ksps # In other words, decimation by int(samp_rate/1E6) # 12.5 kHz cutoff for NBFM channel bandwidth low_pass_filter_taps_1 = grfilter.firdes_low_pass( 1, samp_rate/decims[0]**2, 12.5E3, 1E3, grfilter.firdes.WIN_HAMMING) # FIR filter decimation by int(samp_rate/1E6) fir_filter_ccc_1 = grfilter.fir_filter_ccc(decims[1], low_pass_filter_taps_1) # Non blocking power squelch self.analog_pwr_squelch_cc = analog.pwr_squelch_cc(squelch_db, 1e-1, 0, False) # Quadrature demod with gain set for decent audio # The gain will be later multiplied by the 0 dB normalized volume self.analog_quadrature_demod_cf = \ analog.quadrature_demod_cf(self.quad_demod_gain) # 3.5 kHz cutoff for audio bandwidth low_pass_filter_taps_2 = grfilter.firdes_low_pass(1,\ samp_rate/(decims[1] * decims[0]**2),\ 3.5E3, 500, grfilter.firdes.WIN_HAMMING) # FIR filter decimating by 5 from 40-79.9 ksps to 8-15.98 ksps fir_filter_fff_0 = grfilter.fir_filter_fff(decims[0], low_pass_filter_taps_2) # Polyphase resampler allows arbitary RF sample rates # Takes 8-15.98 ksps to a constant 8 ksps for audio pfb_resamp = audio_rate/float(samp_rate/(decims[1] * decims[0]**3)) pfb_arb_resampler_fff = pfb.arb_resampler_fff(pfb_resamp, taps=None, flt_size=32) # Connect the blocks for the demod self.connect(self, self.freq_xlating_fir_filter_ccc) self.connect(self.freq_xlating_fir_filter_ccc, fir_filter_ccc_0) self.connect(fir_filter_ccc_0, fir_filter_ccc_1) self.connect(fir_filter_ccc_1, self.analog_pwr_squelch_cc) self.connect(self.analog_pwr_squelch_cc, self.analog_quadrature_demod_cf) self.connect(self.analog_quadrature_demod_cf, fir_filter_fff_0) self.connect(fir_filter_fff_0, pfb_arb_resampler_fff) self.connect(pfb_arb_resampler_fff, self) # Need to set this to a very low value of -200 since it is after demod # Only want it to gate when the previuos squelch has gone to zero analog_pwr_squelch_ff = analog.pwr_squelch_ff(-200, 1e-1, 0, True) # File sink with single channel and 8 bits/sample self.blocks_wavfile_sink = blocks.wavfile_sink(self.file_name, 1, audio_rate, 8) # Connect the blocks for recording self.connect(pfb_arb_resampler_fff, analog_pwr_squelch_ff) self.connect(analog_pwr_squelch_ff, self.blocks_wavfile_sink)
def __init__(self, samp_rate=4E6, audio_rate=8000, record=True): gr.hier_block2.__init__(self, "TunerDemodAM", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) # Default values self.center_freq = 0 squelch_db = -60 self.agc_ref = 0.1 self.file_name = "/dev/null" self.record = record # Decimation values for four stages of decimation decims = (5, int(samp_rate/1E6)) # Low pass filter taps for decimation by 5 low_pass_filter_taps_0 = \ grfilter.firdes_low_pass(1, 1, 0.090, 0.010, grfilter.firdes.WIN_HAMMING) # Frequency translating FIR filter decimating by 5 self.freq_xlating_fir_filter_ccc = \ grfilter.freq_xlating_fir_filter_ccc(decims[0], low_pass_filter_taps_0, self.center_freq, samp_rate) # FIR filter decimating by 5 fir_filter_ccc_0 = grfilter.fir_filter_ccc(decims[0], low_pass_filter_taps_0) # Low pass filter taps for decimation from samp_rate/25 to 40-79.9 ksps # In other words, decimation by int(samp_rate/1E6) # 12.5 kHz cutoff for NBFM channel bandwidth low_pass_filter_taps_1 = grfilter.firdes_low_pass( 1, samp_rate/decims[0]**2, 12.5E3, 1E3, grfilter.firdes.WIN_HAMMING) # FIR filter decimation by int(samp_rate/1E6) fir_filter_ccc_1 = grfilter.fir_filter_ccc(decims[1], low_pass_filter_taps_1) # Non blocking power squelch # Squelch level needs to be lower than NBFM or else choppy AM demod self.analog_pwr_squelch_cc = analog.pwr_squelch_cc(squelch_db, 1e-1, 0, False) # AGC with reference set for nomninal 0 dB volume # Paramaters tweaked to prevent impulse during squelching self.agc3_cc = analog.agc3_cc(1.0, 1E-4, self.agc_ref, 10, 1) self.agc3_cc.set_max_gain(65536) # AM demod with complex_to_mag() # Can't use analog.am_demod_cf() since it won't work with N>2 demods am_demod_cf = blocks.complex_to_mag(1) # 3.5 kHz cutoff for audio bandwidth low_pass_filter_taps_2 = grfilter.firdes_low_pass(1,\ samp_rate/(decims[1] * decims[0]**2),\ 3.5E3, 500, grfilter.firdes.WIN_HAMMING) # FIR filter decimating by 5 from 40-79.9 ksps to 8-15.98 ksps fir_filter_fff_0 = grfilter.fir_filter_fff(decims[0], low_pass_filter_taps_2) # Polyphase resampler allows arbitary RF sample rates # Takes 8-15.98 ksps to a constant 8 ksps for audio pfb_resamp = audio_rate/float(samp_rate/(decims[1] * decims[0]**3)) pfb_arb_resampler_fff = pfb.arb_resampler_fff(pfb_resamp, taps=None, flt_size=32) # Connect the blocks for the demod self.connect(self, self.freq_xlating_fir_filter_ccc) self.connect(self.freq_xlating_fir_filter_ccc, fir_filter_ccc_0) self.connect(fir_filter_ccc_0, fir_filter_ccc_1) self.connect(fir_filter_ccc_1, self.analog_pwr_squelch_cc) self.connect(self.analog_pwr_squelch_cc, self.agc3_cc) self.connect(self.agc3_cc, am_demod_cf) self.connect(am_demod_cf, fir_filter_fff_0) self.connect(fir_filter_fff_0, pfb_arb_resampler_fff) self.connect(pfb_arb_resampler_fff, self) # Need to set this to a very low value of -200 since it is after demod # Only want it to gate when the previuos squelch has gone to zero analog_pwr_squelch_ff = analog.pwr_squelch_ff(-200, 1e-1, 0, True) # File sink with single channel and 8 bits/sample self.blocks_wavfile_sink = blocks.wavfile_sink(self.file_name, 1, audio_rate, 8) # Connect the blocks for recording self.connect(pfb_arb_resampler_fff, analog_pwr_squelch_ff) self.connect(analog_pwr_squelch_ff, self.blocks_wavfile_sink)
def __init__(self, dab_params, rx_params, verbose=False, debug=False): """ Hierarchical block for OFDM demodulation @param dab_params DAB parameter object (grdab.parameters.dab_parameters) @param rx_params RX parameter object (grdab.parameters.receiver_parameters) @param debug enables debug output to files @param verbose whether to produce verbose messages """ self.dp = dp = dab_params self.rp = rp = rx_params self.verbose = verbose if self.rp.softbits: gr.hier_block2.__init__( self, "ofdm_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature(1, 1, gr.sizeof_float * self.dp.num_carriers * 2)) # output signature else: gr.hier_block2.__init__( self, "ofdm_demod", gr.io_signature(1, 1, gr.sizeof_gr_complex), # input signature gr.io_signature(1, 1, gr.sizeof_char * self.dp.num_carriers / 4)) # output signature # workaround for a problem that prevents connecting more than one block directly (see trac ticket #161) #self.input = gr.kludge_copy(gr.sizeof_gr_complex) self.input = blocks.multiply_const_cc(1.0) # FIXME self.connect(self, self.input) # input filtering if self.rp.input_fft_filter: if verbose: print("--> RX filter enabled") lowpass_taps = filter.firdes_low_pass( 1.0, # gain dp.sample_rate, # sampling rate rp.filt_bw, # cutoff frequency rp.filt_tb, # width of transition band filter.firdes.WIN_HAMMING) # Hamming window self.fft_filter = filter.fft_filter_ccc(1, lowpass_taps) # correct sample rate offset, if enabled if self.rp.autocorrect_sample_rate: if verbose: print("--> dynamic sample rate correction enabled") self.rate_detect_ns = grdab.detect_null(dp.ns_length, False) self.rate_estimator = grdab.estimate_sample_rate_bf( dp.sample_rate, dp.frame_length) self.rate_prober = blocks.probe_signal_f() self.connect(self.input, self.rate_detect_ns, self.rate_estimator, self.rate_prober) # self.resample = gr.fractional_interpolator_cc(0, 1) self.resample = grdab.fractional_interpolator_triggered_update_cc( 0, 1) self.connect(self.rate_detect_ns, (self.resample, 1)) self.updater = Timer(0.1, self.update_correction) # self.updater = threading.Thread(target=self.update_correction) self.run_interpolater_update_thread = True self.updater.setDaemon(True) self.updater.start() else: self.run_interpolater_update_thread = False if self.rp.sample_rate_correction_factor != 1 or self.rp.always_include_resample: if verbose: print("--> static sample rate correction enabled") self.resample = filter.mmse_resampler_cc( 0, self.rp.sample_rate_correction_factor) # timing and fine frequency synchronisation self.sync = grdab.ofdm_sync_dab2(self.dp, self.rp, debug) # ofdm symbol sampler self.sampler = grdab.ofdm_sampler(dp.fft_length, dp.cp_length, dp.symbols_per_frame, rp.cp_gap) # fft for symbol vectors self.fft = fft.fft_vcc(dp.fft_length, True, [], True) # coarse frequency synchronisation self.cfs = grdab.ofdm_coarse_frequency_correct(dp.fft_length, dp.num_carriers, dp.cp_length) # diff phasor self.phase_diff = grdab.diff_phasor_vcc(dp.num_carriers) # remove pilot symbol self.remove_pilot = grdab.ofdm_remove_first_symbol_vcc(dp.num_carriers) # magnitude equalisation if self.rp.equalize_magnitude: if verbose: print("--> magnitude equalization enabled") self.equalizer = grdab.magnitude_equalizer_vcc( dp.num_carriers, rp.symbols_for_magnitude_equalization) # frequency deinterleaving self.deinterleave = grdab.frequency_interleaver_vcc( dp.frequency_deinterleaving_sequence_array) # symbol demapping self.demapper = grdab.qpsk_demapper_vcb(dp.num_carriers) # # connect everything # if self.rp.autocorrect_sample_rate or self.rp.sample_rate_correction_factor != 1 or self.rp.always_include_resample: self.connect(self.input, self.resample) self.input2 = self.resample else: self.input2 = self.input if self.rp.input_fft_filter: self.connect(self.input2, self.fft_filter, self.sync) else: self.connect(self.input2, self.sync) # data stream self.connect(self.sync, self.sampler, self.fft, self.cfs, self.phase_diff, self.remove_pilot) if self.rp.equalize_magnitude: self.connect(self.remove_pilot, self.equalizer, self.deinterleave) else: self.connect(self.remove_pilot, self.deinterleave) if self.rp.softbits: if verbose: print("--> using soft bits") self.softbit_interleaver = grdab.complex_to_interleaved_float_vcf( self.dp.num_carriers) self.connect(self.deinterleave, self.softbit_interleaver, (self, 0)) else: self.connect(self.deinterleave, self.demapper, (self, 0)) # calculate an estimate of the SNR self.phase_var_decim = blocks.keep_one_in_n( gr.sizeof_gr_complex * self.dp.num_carriers, self.rp.phase_var_estimate_downsample) self.phase_var_arg = blocks.complex_to_arg(dp.num_carriers) self.phase_var_v2s = blocks.vector_to_stream(gr.sizeof_float, dp.num_carriers) self.phase_var_mod = grdab.modulo_ff(pi / 2) self.phase_var_avg_mod = filter.iir_filter_ffd( [rp.phase_var_estimate_alpha], [0, 1 - rp.phase_var_estimate_alpha]) self.phase_var_sub_avg = blocks.sub_ff() self.phase_var_sqr = blocks.multiply_ff() self.phase_var_avg = filter.iir_filter_ffd( [rp.phase_var_estimate_alpha], [0, 1 - rp.phase_var_estimate_alpha]) self.probe_phase_var = blocks.probe_signal_f() self.connect((self.remove_pilot, 0), self.phase_var_decim, self.phase_var_arg, self.phase_var_v2s, self.phase_var_mod, (self.phase_var_sub_avg, 0), (self.phase_var_sqr, 0)) self.connect(self.phase_var_mod, self.phase_var_avg_mod, (self.phase_var_sub_avg, 1)) self.connect(self.phase_var_sub_avg, (self.phase_var_sqr, 1)) self.connect(self.phase_var_sqr, self.phase_var_avg, self.probe_phase_var) # measure processing rate self.measure_rate = grdab.measure_processing_rate( gr.sizeof_gr_complex, 2000000) self.connect(self.input, self.measure_rate) # debugging if debug: self.connect( self.fft, blocks.file_sink(gr.sizeof_gr_complex * dp.fft_length, "debug/ofdm_after_fft.dat")) self.connect( (self.cfs, 0), blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/ofdm_after_cfs.dat")) self.connect( self.phase_diff, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/ofdm_diff_phasor.dat")) self.connect( (self.remove_pilot, 0), blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/ofdm_pilot_removed.dat")) self.connect((self.remove_pilot, 1), blocks.file_sink(gr.sizeof_char, "debug/ofdm_after_cfs_trigger.dat")) self.connect( self.deinterleave, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/ofdm_deinterleaved.dat")) if self.rp.equalize_magnitude: self.connect( self.equalizer, blocks.file_sink(gr.sizeof_gr_complex * dp.num_carriers, "debug/ofdm_equalizer.dat")) if self.rp.softbits: self.connect( self.softbit_interleaver, blocks.file_sink(gr.sizeof_float * dp.num_carriers * 2, "debug/softbits.dat"))
def __init__(self, samp_rate=4E6, audio_rate=8000, record=True, audio_bps=8): gr.hier_block2.__init__(self, "TunerDemodAM", gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_float)) # Default values self.center_freq = 0 squelch_db = -60 self.agc_ref = 0.1 self.file_name = "/dev/null" self.record = record # Decimation values for four stages of decimation decims = (5, int(samp_rate / 1E6)) # Low pass filter taps for decimation by 5 low_pass_filter_taps_0 = \ grfilter.firdes_low_pass(1, 1, 0.090, 0.010, grfilter.firdes.WIN_HAMMING) # Frequency translating FIR filter decimating by 5 self.freq_xlating_fir_filter_ccc = \ grfilter.freq_xlating_fir_filter_ccc(decims[0], low_pass_filter_taps_0, self.center_freq, samp_rate) # FIR filter decimating by 5 fir_filter_ccc_0 = grfilter.fir_filter_ccc(decims[0], low_pass_filter_taps_0) # Low pass filter taps for decimation from samp_rate/25 to 40-79.9 ksps # In other words, decimation by int(samp_rate/1E6) # 12.5 kHz cutoff for NBFM channel bandwidth low_pass_filter_taps_1 = grfilter.firdes_low_pass( 1, samp_rate / decims[0]**2, 12.5E3, 1E3, grfilter.firdes.WIN_HAMMING) # FIR filter decimation by int(samp_rate/1E6) fir_filter_ccc_1 = grfilter.fir_filter_ccc(decims[1], low_pass_filter_taps_1) # Non blocking power squelch # Squelch level needs to be lower than NBFM or else choppy AM demod self.analog_pwr_squelch_cc = analog.pwr_squelch_cc( squelch_db, 1e-1, 0, False) # AGC with reference set for nomninal 0 dB volume # Paramaters tweaked to prevent impulse during squelching self.agc3_cc = analog.agc3_cc(1.0, 1E-4, self.agc_ref, 10, 1) self.agc3_cc.set_max_gain(65536) # AM demod with complex_to_mag() # Can't use analog.am_demod_cf() since it won't work with N>2 demods am_demod_cf = blocks.complex_to_mag(1) # 3.5 kHz cutoff for audio bandwidth low_pass_filter_taps_2 = grfilter.firdes_low_pass(1,\ samp_rate/(decims[1] * decims[0]**2),\ 3.5E3, 500, grfilter.firdes.WIN_HAMMING) # FIR filter decimating by 5 from 40-79.9 ksps to 8-15.98 ksps fir_filter_fff_0 = grfilter.fir_filter_fff(decims[0], low_pass_filter_taps_2) # Polyphase resampler allows arbitary RF sample rates # Takes 8-15.98 ksps to a constant 8 ksps for audio pfb_resamp = audio_rate / float(samp_rate / (decims[1] * decims[0]**3)) pfb_arb_resampler_fff = pfb.arb_resampler_fff(pfb_resamp, taps=None, flt_size=32) # Connect the blocks for the demod self.connect(self, self.freq_xlating_fir_filter_ccc) self.connect(self.freq_xlating_fir_filter_ccc, fir_filter_ccc_0) self.connect(fir_filter_ccc_0, fir_filter_ccc_1) self.connect(fir_filter_ccc_1, self.analog_pwr_squelch_cc) self.connect(self.analog_pwr_squelch_cc, self.agc3_cc) self.connect(self.agc3_cc, am_demod_cf) self.connect(am_demod_cf, fir_filter_fff_0) self.connect(fir_filter_fff_0, pfb_arb_resampler_fff) self.connect(pfb_arb_resampler_fff, self) # Need to set this to a very low value of -200 since it is after demod # Only want it to gate when the previous squelch has gone to zero analog_pwr_squelch_ff = analog.pwr_squelch_ff(-200, 1e-1, 0, True) # File sink with single channel and 8 bits/sample self.blocks_wavfile_sink = blocks.wavfile_sink(self.file_name, 1, audio_rate, audio_bps) # Connect the blocks for recording self.connect(pfb_arb_resampler_fff, analog_pwr_squelch_ff) self.connect(analog_pwr_squelch_ff, self.blocks_wavfile_sink)