works with rtl sdr and gnuradio 3.8

This commit is contained in:
Bastian Bloessl 2013-11-17 20:00:18 +01:00
parent 6430bdeb5f
commit bf8a080c10
3 changed files with 43 additions and 92 deletions

View file

@ -27,7 +27,8 @@
differential PI/4 CQPSK modulation and demodulation. differential PI/4 CQPSK modulation and demodulation.
""" """
from gnuradio import gr, gru from gnuradio import gr, gru, blocks, analog, filter
from gnuradio.filter import firdes
from math import pi, sqrt from math import pi, sqrt
#import psk #import psk
import cmath import cmath
@ -110,14 +111,14 @@ class cqpsk_mod(gr.hier_block2):
self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]) self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity])
# pulse shaping filter # pulse shaping filter
self.rrc_taps = gr.firdes.root_raised_cosine( self.rrc_taps = firdes.root_raised_cosine(
self._samples_per_symbol, # gain (sps since we're interpolating by sps) self._samples_per_symbol, # gain (sps since we're interpolating by sps)
self._samples_per_symbol, # sampling rate self._samples_per_symbol, # sampling rate
1.0, # symbol rate 1.0, # symbol rate
self._excess_bw, # excess bandwidth (roll-off factor) self._excess_bw, # excess bandwidth (roll-off factor)
ntaps) ntaps)
self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps) self.rrc_filter = filter.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
if verbose: if verbose:
self._print_verbage() self._print_verbage()
@ -145,15 +146,15 @@ class cqpsk_mod(gr.hier_block2):
def _setup_logging(self): def _setup_logging(self):
print "Modulation logging turned on." print "Modulation logging turned on."
self.connect(self.bytes2chunks, self.connect(self.bytes2chunks,
gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat")) blocks.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
self.connect(self.symbol_mapper, self.connect(self.symbol_mapper,
gr.file_sink(gr.sizeof_char, "tx_graycoder.dat")) blocks.file_sink(gr.sizeof_char, "tx_graycoder.dat"))
self.connect(self.diffenc, self.connect(self.diffenc,
gr.file_sink(gr.sizeof_char, "tx_diffenc.dat")) blocks.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
self.connect(self.chunks2symbols, self.connect(self.chunks2symbols,
gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat")) blocks.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
self.connect(self.rrc_filter, self.connect(self.rrc_filter,
gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat")) blocks.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
def add_options(parser): def add_options(parser):
""" """
@ -238,19 +239,19 @@ class cqpsk_demod(gr.hier_block2):
# Automatic gain control # Automatic gain control
scale = (1.0/16384.0) scale = (1.0/16384.0)
self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1 self.pre_scaler = blocks.multiply_const_cc(scale) # scale the signal from full-range to +-1
#self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
self.agc = gr.feedforward_agc_cc(16, 2.0) self.agc = analog.feedforward_agc_cc(16, 2.0)
# RRC data filter # RRC data filter
ntaps = 11 * samples_per_symbol ntaps = 11 * samples_per_symbol
self.rrc_taps = gr.firdes.root_raised_cosine( self.rrc_taps = firdes.root_raised_cosine(
1.0, # gain 1.0, # gain
self._samples_per_symbol, # sampling rate self._samples_per_symbol, # sampling rate
1.0, # symbol rate 1.0, # symbol rate
self._excess_bw, # excess bandwidth (roll-off factor) self._excess_bw, # excess bandwidth (roll-off factor)
ntaps) ntaps)
self.rrc_filter=gr.interp_fir_filter_ccf(1, self.rrc_taps) self.rrc_filter=filter.interp_fir_filter_ccf(1, self.rrc_taps)
if not self._mm_gain_mu: if not self._mm_gain_mu:
sbs_to_mm = {2: 0.050, 3: 0.075, 4: 0.11, 5: 0.125, 6: 0.15, 7: 0.15} sbs_to_mm = {2: 0.050, 3: 0.075, 4: 0.11, 5: 0.125, 6: 0.15, 7: 0.15}
@ -277,17 +278,17 @@ class cqpsk_demod(gr.hier_block2):
self._mm_omega, self._mm_gain_omega, self._mm_omega, self._mm_gain_omega,
self._mm_omega_relative_limit) self._mm_omega_relative_limit)
self.receiver.set_alpha(self._costas_alpha) #self.receiver.set_alpha(self._costas_alpha)
self.receiver.set_beta(self._costas_beta) #self.receiver.set_beta(self._costas_beta)
# Perform Differential decoding on the constellation # Perform Differential decoding on the constellation
self.diffdec = gr.diff_phasor_cc() self.diffdec = digital.diff_phasor_cc()
# take angle of the difference (in radians) # take angle of the difference (in radians)
self.to_float = gr.complex_to_arg() self.to_float = blocks.complex_to_arg()
# convert from radians such that signal is in -3/-1/+1/+3 # convert from radians such that signal is in -3/-1/+1/+3
self.rescale = gr.multiply_const_ff( 1 / (pi / 4) ) self.rescale = blocks.multiply_const_ff( 1 / (pi / 4) )
if verbose: if verbose:
self._print_verbage() self._print_verbage()
@ -322,19 +323,19 @@ class cqpsk_demod(gr.hier_block2):
def _setup_logging(self): def _setup_logging(self):
print "Modulation logging turned on." print "Modulation logging turned on."
self.connect(self.pre_scaler, self.connect(self.pre_scaler,
gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat")) blocks.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat"))
self.connect(self.agc, self.connect(self.agc,
gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat")) blocks.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
self.connect(self.rrc_filter, self.connect(self.rrc_filter,
gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat")) blocks.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat"))
self.connect(self.receiver, self.connect(self.receiver,
gr.file_sink(gr.sizeof_gr_complex, "rx_receiver.dat")) blocks.file_sink(gr.sizeof_gr_complex, "rx_receiver.dat"))
self.connect(self.diffdec, self.connect(self.diffdec,
gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat")) blocks.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
self.connect(self.to_float, self.connect(self.to_float,
gr.file_sink(gr.sizeof_float, "rx_to_float.dat")) blocks.file_sink(gr.sizeof_float, "rx_to_float.dat"))
self.connect(self.rescale, self.connect(self.rescale,
gr.file_sink(gr.sizeof_float, "rx_rescale.dat")) blocks.file_sink(gr.sizeof_float, "rx_rescale.dat"))
def add_options(parser): def add_options(parser):
""" """

View file

@ -13,20 +13,18 @@
import sys import sys
import math import math
from gnuradio import gr, gru, eng_notation, blks2, optfir from gnuradio import gr, gru, eng_notation, blocks, filter
from gnuradio.eng_option import eng_option from gnuradio.eng_option import eng_option
from gnuradio.wxgui import fftsink2 from gnuradio.wxgui import fftsink2
from gnuradio.wxgui import scopesink2 from gnuradio.wxgui import scopesink2
from gnuradio.wxgui import forms from gnuradio.wxgui import forms
from gnuradio.filter import firdes
from grc_gnuradio import wxgui as grc_wxgui from grc_gnuradio import wxgui as grc_wxgui
from optparse import OptionParser from optparse import OptionParser
import osmosdr import osmosdr
import wx import wx
try: import cqpsk
import cqpsk
except:
from tetra_demod import cqpsk
# applies frequency translation, resampling and demodulation # applies frequency translation, resampling and demodulation
@ -39,18 +37,13 @@ class top_block(grc_wxgui.top_block_gui):
self.ifreq = options.frequency self.ifreq = options.frequency
self.rfgain = options.gain self.rfgain = options.gain
self.src = osmosdr.source_c(options.args) self.src = osmosdr.source(options.args)
self.src.set_center_freq(self.ifreq) self.src.set_center_freq(self.ifreq)
self.src.set_sample_rate(int(options.sample_rate)) self.src.set_sample_rate(int(options.sample_rate))
self.src.set_freq_corr(0, 0)
if self.rfgain is None: self.src.set_dc_offset_mode(2, 0)
self.src.set_gain_mode(1) self.src.set_iq_balance_mode(2, 0)
self.iagc = 1 self.src.set_gain_mode(1, 0)
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 # may differ from the requested rate
sample_rate = self.src.get_sample_rate() sample_rate = self.src.get_sample_rate()
@ -69,8 +62,8 @@ class top_block(grc_wxgui.top_block_gui):
self.offset = 0 self.offset = 0
taps = gr.firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.2, gr.firdes.WIN_HANN) taps = firdes.low_pass(1.0, sample_rate, options.low_pass, options.low_pass * 0.2, firdes.WIN_HANN)
self.tuner = gr.freq_xlating_fir_filter_ccf(first_decim, taps, self.offset, sample_rate) self.tuner = filter.freq_xlating_fir_filter_ccf(first_decim, taps, self.offset, sample_rate)
self.demod = cqpsk.cqpsk_demod( self.demod = cqpsk.cqpsk_demod(
samples_per_symbol = sps, samples_per_symbol = sps,
@ -82,17 +75,18 @@ class top_block(grc_wxgui.top_block_gui):
log=options.log, log=options.log,
verbose=options.verbose) verbose=options.verbose)
self.output = gr.file_sink(gr.sizeof_float, options.output_file) self.output = blocks.file_sink(gr.sizeof_float, options.output_file)
rerate = float(sample_rate / float(first_decim)) / float(out_sample_rate) rerate = float(sample_rate / float(first_decim)) / float(out_sample_rate)
sys.stderr.write("resampling factor: %f\n" % rerate) sys.stderr.write("resampling factor: %f\n" % rerate)
if rerate.is_integer(): if rerate.is_integer():
sys.stderr.write("using pfb decimator\n") sys.stderr.write("using pfb decimator\n")
self.resamp = blks2.pfb_decimator_ccf(int(rerate)) #self.resamp = filter.pfb_decimator_ccf(int(rerate), firdes.low_pass(1,int(sample_rate), 50000,5000), 1)
self.resamp = filter.fir_filter_ccf(int(rerate), firdes.low_pass(1,int(sample_rate/first_decim), 50000,5000))
else: else:
sys.stderr.write("using pfb resampler\n") sys.stderr.write("using pfb resampler\n")
self.resamp = blks2.pfb_arb_resampler_ccf(1 / rerate) self.resamp = filter.pfb_arb_resampler_ccf(1 / rerate,[], 0)
self.connect(self.src, self.tuner, self.resamp, self.demod, self.output) self.connect(self.src, self.tuner, self.resamp, self.demod, self.output)
@ -115,53 +109,6 @@ class top_block(grc_wxgui.top_block_gui):
) )
self.Add(self._ifreq_text_box) 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) self.Add(self.Main)
@ -220,7 +167,7 @@ class top_block(grc_wxgui.top_block_gui):
ac_couple=False, ac_couple=False,
xy_mode=False, xy_mode=False,
num_inputs=1, num_inputs=1,
trig_mode=gr.gr_TRIG_MODE_AUTO, #trig_mode=gr.gr_TRIG_MODE_AUTO,
y_axis_label="Counts", y_axis_label="Counts",
) )
self.Main.GetPage(2).Add(self.scope3.win) self.Main.GetPage(2).Add(self.scope3.win)

3
src/startme.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
./demod/python/osmosdr-tetra_demod_fft.py -f 390.912600M -o /dev/stdout | ./float_to_bits /dev/stdin /dev/stdout | ./tetra-rx /dev/stdin