#
-# Copyright 2005,2006,2007,2009 Free Software Foundation, Inc.
+# Copyright 2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
differential QPSK modulation and demodulation.
"""
-from gnuradio import gr, gru, modulation_utils
+from gnuradio import gr, gru, modulation_utils2
from math import pi, sqrt
import psk
import cmath
_def_verbose = False
_def_log = False
-_def_costas_alpha = 0.01
+_def_freq_alpha = 0.010
+_def_phase_alpha = 0.01
_def_timing_alpha = 0.100
_def_timing_beta = 0.010
_def_timing_max_dev = 1.5
self._excess_bw = excess_bw
self._gray_code = gray_code
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
+ if samples_per_symbol < 2:
+ raise TypeError, ("sbp must be >= 2, is %f" % samples_per_symbol)
ntaps = 11 * samples_per_symbol
self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const)
# pulse shaping filter
- self.rrc_taps = gr.firdes.root_raised_cosine(
- self._samples_per_symbol, # gain (sps since we're interpolating by sps)
- self._samples_per_symbol, # sampling rate
- 1.0, # symbol rate
- self._excess_bw, # excess bandwidth (roll-off factor)
+ nfilts = 32
+ ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each
+ self.rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ self._excess_bw, # excess bandwidth (roll-off factor)
ntaps)
-
- self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps)
+ self.rrc_filter = gr.pfb_arb_resampler_ccf(self._samples_per_symbol, self.rrc_taps)
if verbose:
self._print_verbage()
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(dqpsk2_mod.__init__,
+ return modulation_utils2.extract_kwargs_from_options(dqpsk2_mod.__init__,
('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
def __init__(self,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
- costas_alpha=_def_costas_alpha,
+ freq_alpha=_def_freq_alpha,
+ phase_alpha=_def_phase_alpha,
timing_alpha=_def_timing_alpha,
timing_max_dev=_def_timing_max_dev,
gray_code=_def_gray_code,
verbose=_def_verbose,
- log=_def_log):
+ log=_def_log,
+ sync_out=False):
"""
Hierarchical block for RRC-filtered DQPSK demodulation
@type samples_per_symbol: float
@param excess_bw: Root-raised cosine filter excess bandwidth
@type excess_bw: float
- @param costas_alpha: loop filter gain
- @type costas_alphas: float
+ @param freq_alpha: loop filter gain for frequency recovery
+ @type freq_alpha: float
+ @param phase_alpha: loop filter gain
+ @type phase_alphas: float
@param timing_alpha: timing loop alpha gain
@type timing_alpha: float
@param timing_max: timing loop maximum rate deviations
@type gray_code: bool
@param verbose: Print information about modulator?
@type verbose: bool
- @param debug: Print modualtion data to files?
- @type debug: bool
+ @param log: Print modualtion data to files?
+ @type log: bool
+ @param sync_out: Output a sync signal on :1?
+ @type sync_out: bool
"""
+ if sync_out: io_sig_out = gr.io_signaturev(2, 2, (gr.sizeof_char, gr.sizeof_gr_complex))
+ else: io_sig_out = gr.io_signature(1, 1, gr.sizeof_char)
gr.hier_block2.__init__(self, "dqpsk2_demod",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
- gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+ io_sig_out) # Output signature
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
- self._costas_alpha = costas_alpha
+ self._freq_alpha = freq_alpha
+ self._freq_beta = 0.25*self._freq_alpha**2
+ self._phase_alpha = phase_alpha
self._timing_alpha = timing_alpha
self._timing_beta = _def_timing_beta
self._timing_max_dev=timing_max_dev
self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
#self.agc = gr.feedforward_agc_cc(16, 2.0)
- self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha
- # Allow a frequency swing of +/- half of the sample rate
- fmin = -0.5
- fmax = 0.5
+ # Frequency correction
+ self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ 11*int(self._samples_per_symbol),
+ self._freq_alpha, self._freq_beta)
- self.clock_recov = gr.costas_loop_cc(self._costas_alpha,
- self._costas_beta,
- fmax, fmin, arity)
# symbol timing recovery with RRC data filter
nfilts = 32
- ntaps = 11 * samples_per_symbol*nfilts
- taps = gr.firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(self._samples_per_symbol), self._excess_bw, ntaps)
+ ntaps = 11 * int(samples_per_symbol*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
+ 1.0/float(self._samples_per_symbol),
+ self._excess_bw, ntaps)
self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
self._timing_alpha,
taps, nfilts, nfilts/2, self._timing_max_dev)
self.time_recov.set_beta(self._timing_beta)
+
+ # Perform phase / fine frequency correction
+ self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
+ # Allow a frequency swing of +/- half of the sample rate
+ fmin = -0.5
+ fmax = 0.5
+
+ self.phase_recov = gr.costas_loop_cc(self._phase_alpha,
+ self._phase_beta,
+ fmax, fmin, arity)
+
+
# Perform Differential decoding on the constellation
self.diffdec = gr.diff_phasor_cc()
# Connect
self.connect(self, self.agc,
- self.clock_recov,
- self.time_recov,
+ self.freq_recov, self.time_recov, self.phase_recov,
self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
+ if sync_out: self.connect(self.time_recov, (self, 1))
def samples_per_symbol(self):
return self._samples_per_symbol
print "bits per symbol: %d" % self.bits_per_symbol()
print "Gray code: %s" % self._gray_code
print "RRC roll-off factor: %.2f" % self._excess_bw
- print "Costas Loop alpha: %.2e" % self._costas_alpha
- print "Costas Loop beta: %.2e" % self._costas_beta
+ print "FLL gain: %.2f" % self._freq_alpha
print "Timing alpha gain: %.2f" % self._timing_alpha
print "Timing beta gain: %.2f" % self._timing_beta
print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
def _setup_logging(self):
print "Modulation logging turned on."
- self.connect(self.pre_scaler,
- gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat"))
self.connect(self.agc,
gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat"))
- self.connect(self.clock_recov,
- gr.file_sink(gr.sizeof_gr_complex, "rx_clock_recov.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
self.connect(self.time_recov,
gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
self.connect(self.diffdec,
gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
self.connect(self.slicer,
def add_options(parser):
"""
- Adds modulation-specific options to the standard parser
+ Adds DQPSK demodulation-specific options to the standard parser
"""
parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
help="set RRC excess bandwith factor [default=%default] (PSK)")
parser.add_option("", "--no-gray-code", dest="gray_code",
action="store_false", default=_def_gray_code,
help="disable gray coding on modulated bits (PSK)")
- parser.add_option("", "--costas-alpha", type="float", default=_def_costas_alpha,
- help="set Costas loop alpha value [default=%default] (PSK)")
- parser.add_option("", "--gain-alpha", type="float", default=_def_timing_alpha,
+ parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
+ help="set frequency lock loop alpha gain value [default=%default] (PSK)")
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
- parser.add_option("", "--gain-beta", type="float", default=_def_timing_beta,
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(
+ return modulation_utils2.extract_kwargs_from_options(
dqpsk2_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
#
# Add these to the mod/demod registry
#
-modulation_utils.add_type_1_mod('dqpsk2', dqpsk2_mod)
-modulation_utils.add_type_1_demod('dqpsk2', dqpsk2_demod)
+modulation_utils2.add_type_1_mod('dqpsk2', dqpsk2_mod)
+modulation_utils2.add_type_1_demod('dqpsk2', dqpsk2_demod)