demodulator updates

This commit is contained in:
Max 2017-12-22 18:02:18 -05:00
parent 5edfc1c463
commit 35da7d958a
1 changed files with 107 additions and 20 deletions

View File

@ -45,14 +45,35 @@ _def_costas_alpha = 0.04
_def_symbol_rate = 4800
_def_symbol_deviation = 600.0
_def_bb_gain = 1.0
_def_excess_bw = 0.2
# /////////////////////////////////////////////////////////////////////////////
# demodulator
# /////////////////////////////////////////////////////////////////////////////
def get_decim(speed):
s = int(speed)
if_freqs = [24000, 25000, 32000]
for i_f in if_freqs:
if s % i_f != 0:
continue
q = s / i_f
if q & 1:
continue
if q >= 40 and q & 3 == 0:
decim = q/4
decim2 = 4
else:
decim = q/2
decim2 = 2
return decim, decim2
return None
class p25_demod_base(gr.hier_block2):
def __init__(self,
if_rate = None,
filter_type = None,
excess_bw = _def_excess_bw,
symbol_rate = _def_symbol_rate):
"""
Hierarchical block for P25 demodulation base class
@ -66,6 +87,12 @@ class p25_demod_base(gr.hier_block2):
self.baseband_amp = blocks.multiply_const_ff(_def_bb_gain)
coeffs = op25_c4fm_mod.c4fm_taps(sample_rate=self.if_rate, span=9, generator=op25_c4fm_mod.transfer_function_rx).generate()
if filter_type == 'rrc':
sps = self.if_rate / 4800
ntaps = 7 * sps
if ntaps & 1 == 0:
ntaps += 1
coeffs = filter.firdes.root_raised_cosine(1.0, if_rate, symbol_rate, excess_bw, ntaps)
self.symbol_filter = filter.fir_filter_fff(1, coeffs)
autotuneq = gr.msg_queue(2)
self.fsk4_demod = op25.fsk4_demod_ff(autotuneq, self.if_rate, self.symbol_rate)
@ -73,6 +100,9 @@ class p25_demod_base(gr.hier_block2):
levels = [ -2.0, 0.0, 2.0, 4.0 ]
self.slicer = op25_repeater.fsk4_slicer_fb(levels)
def set_symbol_rate(self, rate):
self.symbol_rate = rate
def set_baseband_gain(self, k):
self.baseband_amp.set_k(k)
@ -97,6 +127,8 @@ class p25_demod_fb(p25_demod_base):
def __init__(self,
input_rate = None,
filter_type = None,
excess_bw = _def_excess_bw,
symbol_rate = _def_symbol_rate):
"""
Hierarchical block for P25 demodulation.
@ -110,7 +142,7 @@ class p25_demod_fb(p25_demod_base):
gr.io_signature(1, 1, gr.sizeof_float), # Input signature
gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
p25_demod_base.__init__(self, if_rate=input_rate, symbol_rate=symbol_rate)
p25_demod_base.__init__(self, if_rate=input_rate, symbol_rate=symbol_rate, filter_type=filter_type)
self.input_rate = input_rate
self.float_sink = None
@ -135,6 +167,8 @@ class p25_demod_cb(p25_demod_base):
def __init__(self,
input_rate = None,
demod_type = 'cqpsk',
filter_type = None,
excess_bw = _def_excess_bw,
relative_freq = 0,
offset = 0,
if_rate = _def_if_rate,
@ -153,7 +187,7 @@ class p25_demod_cb(p25_demod_base):
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
# gr.io_signature(0, 0, 0)) # Output signature
p25_demod_base.__init__(self, if_rate=if_rate, symbol_rate=symbol_rate)
p25_demod_base.__init__(self, if_rate=if_rate, symbol_rate=symbol_rate, filter_type=filter_type)
self.input_rate = input_rate
self.if_rate = if_rate
@ -164,22 +198,52 @@ class p25_demod_cb(p25_demod_base):
self.lo_freq = 0
self.float_sink = None
self.complex_sink = None
self.if1 = None
self.if2 = None
self.t_cache = {}
if filter_type == 'rrc':
self.set_baseband_gain(0.61)
# local osc
self.lo = analog.sig_source_c (input_rate, analog.GR_SIN_WAVE, 0, 1.0, 0)
self.mixer = blocks.multiply_cc()
lpf_coeffs = filter.firdes.low_pass(1.0, input_rate, 7250, 725, filter.firdes.WIN_HANN)
decimation = int(input_rate / if_rate)
self.lpf = filter.fir_filter_ccf(decimation, lpf_coeffs)
decimator_values = get_decim(input_rate)
if decimator_values:
self.decim, self.decim2 = decimator_values
self.if1 = input_rate / self.decim
self.if2 = self.if1 / self.decim2
sys.stderr.write( 'Using two-stage decimator for speed=%d, decim=%d/%d if1=%d if2=%d\n' % (input_rate, self.decim, self.decim2, self.if1, self.if2))
bpf_coeffs = filter.firdes.complex_band_pass(1.0, input_rate, -self.if1/2, self.if1/2, self.if1/2, filter.firdes.WIN_HAMMING)
self.t_cache[0] = bpf_coeffs
fa = 6250
fb = self.if2 / 2
lpf_coeffs = filter.firdes.low_pass(1.0, self.if1, (fb+fa)/2, fb-fa, filter.firdes.WIN_HAMMING)
self.bpf = filter.fir_filter_ccc(self.decim, bpf_coeffs)
self.lpf = filter.fir_filter_ccf(self.decim2, lpf_coeffs)
resampled_rate = self.if2
self.bfo = analog.sig_source_c (self.if1, analog.GR_SIN_WAVE, 0, 1.0, 0)
self.connect(self, self.bpf, (self.mixer, 0))
self.connect(self.bfo, (self.mixer, 1))
else:
sys.stderr.write( 'Unable to use two-stage decimator for speed=%d\n' % (input_rate))
# local osc
self.lo = analog.sig_source_c (input_rate, analog.GR_SIN_WAVE, 0, 1.0, 0)
lpf_coeffs = filter.firdes.low_pass(1.0, input_rate, 7250, 725, filter.firdes.WIN_HANN)
decimation = int(input_rate / if_rate)
self.lpf = filter.fir_filter_ccf(decimation, lpf_coeffs)
resampled_rate = float(input_rate) / float(decimation) # rate at output of self.lpf
self.connect(self, (self.mixer, 0))
self.connect(self.lo, (self.mixer, 1))
self.connect(self.mixer, self.lpf)
resampled_rate = float(input_rate) / float(decimation) # rate at output of self.lpf
if self.if_rate != resampled_rate:
self.if_out = filter.pfb.arb_resampler_ccf(float(self.if_rate) / resampled_rate)
self.connect(self.lpf, self.if_out)
else:
self.if_out = self.lpf
self.arb_resampler = filter.pfb.arb_resampler_ccf(
float(self.if_rate) / resampled_rate)
self.connect(self, (self.mixer, 0))
self.connect(self.lo, (self.mixer, 1))
self.connect(self.mixer, self.lpf, self.arb_resampler)
fa = 6250
fb = fa + 625
cutoff_coeffs = filter.firdes.low_pass(1.0, self.if_rate, (fb+fa)/2, fb-fa, filter.firdes.WIN_HANN)
self.cutoff = filter.fir_filter_ccf(1, cutoff_coeffs)
levels = [ -2.0, 0.0, 2.0, 4.0 ]
self.slicer = op25_repeater.fsk4_slicer_fb(levels)
@ -214,6 +278,9 @@ class p25_demod_cb(p25_demod_base):
self.set_relative_frequency(relative_freq)
def get_freq_error(self): # get error in Hz (approx).
return int(self.clock.get_freq_error() * self.symbol_rate)
def set_omega(self, omega):
sps = self.if_rate / float(omega)
if sps == self.sps:
@ -228,17 +295,28 @@ class p25_demod_cb(p25_demod_base):
return False
if freq == self.lo_freq:
return True
#print 'set_relative_frequency', freq
self.lo_freq = freq
self.lo.set_frequency(self.lo_freq)
if self.if1:
if freq not in self.t_cache.keys():
self.t_cache[freq] = filter.firdes.complex_band_pass(1.0, self.input_rate, -freq - self.if1/2, -freq + self.if1/2, self.if1/2, filter.firdes.WIN_HAMMING)
self.bpf.set_taps(self.t_cache[freq])
bfo_f = self.decim * -freq / float(self.input_rate)
bfo_f -= int(bfo_f)
if bfo_f < -0.5:
bfo_f += 1.0
if bfo_f > 0.5:
bfo_f -= 1.0
self.bfo.set_frequency(-bfo_f * self.if1)
else:
self.lo.set_frequency(self.lo_freq)
return True
# assumes lock held or init
def disconnect_chain(self):
if self.connect_state == 'cqpsk':
self.disconnect(self.arb_resampler, self.agc, self.clock, self.diffdec, self.to_float, self.rescale, self.slicer)
self.disconnect(self.if_out, self.cutoff, self.agc, self.clock, self.diffdec, self.to_float, self.rescale, self.slicer)
elif self.connect_state == 'fsk4':
self.disconnect(self.arb_resampler, self.fm_demod, self.baseband_amp, self.symbol_filter, self.fsk4_demod, self.slicer)
self.disconnect(self.if_out, self.cutoff, self.fm_demod, self.baseband_amp, self.symbol_filter, self.fsk4_demod, self.slicer)
self.connect_state = None
# assumes lock held or init
@ -248,9 +326,9 @@ class p25_demod_cb(p25_demod_base):
self.disconnect_chain()
self.connect_state = demod_type
if demod_type == 'fsk4':
self.connect(self.arb_resampler, self.fm_demod, self.baseband_amp, self.symbol_filter, self.fsk4_demod, self.slicer)
self.connect(self.if_out, self.cutoff, self.fm_demod, self.baseband_amp, self.symbol_filter, self.fsk4_demod, self.slicer)
elif demod_type == 'cqpsk':
self.connect(self.arb_resampler, self.agc, self.clock, self.diffdec, self.to_float, self.rescale, self.slicer)
self.connect(self.if_out, self.cutoff, self.agc, self.clock, self.diffdec, self.to_float, self.rescale, self.slicer)
else:
print 'connect_chain failed, type: %s' % demod_type
assert 0 == 1
@ -299,3 +377,12 @@ class p25_demod_cb(p25_demod_base):
elif src == 'src':
self.connect(self, sink)
self.complex_sink = [self, sink]
elif src == 'bpf':
self.connect(self.bpf, sink)
self.complex_sink = [self.bpf, sink]
elif src == 'if_out':
self.connect(self.if_out, sink)
self.complex_sink = [self.if_out, sink]
elif src == 'agc':
self.connect(self.agc, sink)
self.complex_sink = [self.agc, sink]