Exemplo n.º 1
0
	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)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
	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"))
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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"))
Exemplo n.º 8
0
    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)