aboutsummaryrefslogtreecommitdiffstats
path: root/op25/gr-op25_repeater
diff options
context:
space:
mode:
authorMax <ikj1234i@yahoo.com>2017-12-22 18:02:18 -0500
committerMax <ikj1234i@yahoo.com>2017-12-22 18:02:18 -0500
commit35da7d958a894eb998c2f6fbaf7bb313567076ab (patch)
treea2584c7b4ed258fe298efafa0e18ad1cd16d9c3b /op25/gr-op25_repeater
parent5edfc1c4638c4f56481dbe633438a76fb6beeb0e (diff)
demodulator updates
Diffstat (limited to 'op25/gr-op25_repeater')
-rw-r--r--op25/gr-op25_repeater/apps/p25_demodulator.py129
1 files changed, 108 insertions, 21 deletions
diff --git a/op25/gr-op25_repeater/apps/p25_demodulator.py b/op25/gr-op25_repeater/apps/p25_demodulator.py
index 646d621..805746a 100644
--- a/op25/gr-op25_repeater/apps/p25_demodulator.py
+++ b/op25/gr-op25_repeater/apps/p25_demodulator.py
@@ -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)
-
- resampled_rate = float(input_rate) / float(decimation) # rate at output of self.lpf
-
- self.arb_resampler = filter.pfb.arb_resampler_ccf(
- float(self.if_rate) / resampled_rate)
+ 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)
+
+ 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.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]