diff options
Diffstat (limited to 'gnuradio-core/src')
7 files changed, 183 insertions, 116 deletions
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc index d4b14c594..48eb849ab 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc @@ -47,6 +47,8 @@ gr_pfb_arb_resampler_ccf::gr_pfb_arb_resampler_ccf (float rate, gr_make_io_signature (1, 1, sizeof(gr_complex))), d_updated (false) { + d_acc = 0; // start accumulator at 0 + /* The number of filters is specified by the user as the filter size; this is also the interpolation rate of the filter. We use it and the rate provided to determine the decimation rate. This acts as a @@ -131,23 +133,15 @@ void gr_pfb_arb_resampler_ccf::create_diff_taps(const std::vector<float> &newtaps, std::vector<float> &difftaps) { - float maxtap = 1e-20; + // Calculate the differential taps (derivative filter) by taking the difference + // between two taps. Duplicate the last one to make both filters the same length. + float tap; difftaps.clear(); - difftaps.push_back(0); //newtaps[0]); - for(unsigned int i = 1; i < newtaps.size()-1; i++) { - float tap = newtaps[i+1] - newtaps[i-1]; + for(unsigned int i = 0; i < newtaps.size()-1; i++) { + tap = newtaps[i+1] - newtaps[i]; difftaps.push_back(tap); - if(tap > maxtap) { - maxtap = tap; - } - } - difftaps.push_back(0);//-newtaps[newtaps.size()-1]); - - // Scale the differential taps; helps scale error term to better update state - // FIXME: should this be scaled this way or use the same gain as the taps? - for(unsigned int i = 0; i < difftaps.size(); i++) { - difftaps[i] /= maxtap; } + difftaps.push_back(tap); } void @@ -188,14 +182,17 @@ gr_pfb_arb_resampler_ccf::general_work (int noutput_items, // start j by wrapping around mod the number of channels while((j < d_int_rate) && (i < noutput_items)) { - // Take the current filter output + // Take the current filter and derivative filter output o0 = d_filters[j]->filter(&in[count]); o1 = d_diff_filters[j]->filter(&in[count]); - out[i] = o0 + o1*d_flt_rate; // linearly interpolate between samples + out[i] = o0 + o1*d_acc; // linearly interpolate between samples i++; - - j += d_dec_rate; + + // Adjust accumulator and index into filterbank + d_acc += d_flt_rate; + j += d_dec_rate + (int)floor(d_acc); + d_acc = fmodf(d_acc, 1.0); } if(i < noutput_items) { // keep state for next entry float ss = (int)(j / d_int_rate); // number of items to skip ahead by diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h index 531e9726f..b99ad286b 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h @@ -118,6 +118,7 @@ class gr_pfb_arb_resampler_ccf : public gr_block unsigned int d_int_rate; // the number of filters (interpolation rate) unsigned int d_dec_rate; // the stride through the filters (decimation rate) float d_flt_rate; // residual rate for the linear interpolation + float d_acc; unsigned int d_last_filter; int d_start_index; unsigned int d_taps_per_filter; diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc index 0f3d85c83..030e45ddf 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc @@ -53,11 +53,13 @@ gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float ro } +static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; +static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff, int filter_size, float alpha, float beta) : gr_sync_block ("fll_band_edge_cc", gr_make_io_signature (1, 1, sizeof(gr_complex)), - gr_make_io_signature (1, 1, sizeof(gr_complex))), + gr_make_io_signaturev (1, 4, iosig)), d_alpha(alpha), d_beta(beta), d_updated (false) { // base this on the number of samples per symbol @@ -67,6 +69,29 @@ gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff, d_freq = 0; d_phase = 0; + set_alpha(alpha); + + design_filter(samps_per_sym, rolloff, filter_size); +} + +gr_fll_band_edge_cc::~gr_fll_band_edge_cc () +{ + delete d_filter_lower; + delete d_filter_upper; +} + +void +gr_fll_band_edge_cc::set_alpha(float alpha) +{ + float eta = sqrt(2.0)/2.0; + float theta = alpha; + d_alpha = (4*eta*theta) / (1.0 + 2.0*eta*theta + theta*theta); + d_beta = (4*theta*theta) / (1.0 + 2.0*eta*theta + theta*theta); +} + +void +gr_fll_band_edge_cc::design_filter(float samps_per_sym, float rolloff, int filter_size) +{ int M = rint(filter_size / samps_per_sym); float power = 0; std::vector<float> bb_taps; @@ -81,11 +106,11 @@ gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff, int N = (bb_taps.size() - 1.0)/2.0; std::vector<gr_complex> taps_lower; std::vector<gr_complex> taps_upper; - for(int i = 0; i < bb_taps.size(); i++) { + for(unsigned int i = 0; i < bb_taps.size(); i++) { float tap = bb_taps[i] / power; - float k = (-N + i)/(2.0*samps_per_sym); //rng = scipy.arange(-nn2, nn2+1) / (2*spb); - + float k = (-N + (int)i)/(2.0*samps_per_sym); + gr_complex t1 = tap * gr_expj(-2*M_PI*(1+rolloff)*k); gr_complex t2 = tap * gr_expj(2*M_PI*(1+rolloff)*k); @@ -97,61 +122,32 @@ gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff, d_filter_upper = gr_fir_util::create_gr_fir_ccc(vtaps); d_filter_lower = gr_fir_util::create_gr_fir_ccc(vtaps); - set_taps_lower(taps_lower); - set_taps_upper(taps_upper); -} - -gr_fll_band_edge_cc::~gr_fll_band_edge_cc () -{ -} - -void -gr_fll_band_edge_cc::set_taps_lower (const std::vector<gr_complex> &taps) -{ - unsigned int i; - - for(i = 0; i < taps.size(); i++) { - d_taps_lower.push_back(taps[i]); - } - - d_filter_lower->set_taps(d_taps_lower); - - // Set the history to ensure enough input items for each filter - set_history(d_taps_lower.size()+1); + d_filter_lower->set_taps(taps_lower); + d_filter_upper->set_taps(taps_upper); d_updated = true; -} - -void -gr_fll_band_edge_cc::set_taps_upper (const std::vector<gr_complex> &taps) -{ - unsigned int i; - - for(i = 0; i < taps.size(); i++) { - d_taps_upper.push_back(taps[i]); - } - - d_filter_upper->set_taps(d_taps_upper); // Set the history to ensure enough input items for each filter - set_history(d_taps_upper.size()+1); + set_history(filter_size+1); - d_updated = true; } void gr_fll_band_edge_cc::print_taps() { unsigned int i; + std::vector<gr_complex> taps_upper = d_filter_upper->get_taps(); + std::vector<gr_complex> taps_lower = d_filter_lower->get_taps(); + printf("Upper Band-edge: ["); - for(i = 0; i < d_taps_upper.size(); i++) { - printf(" %.4e + %.4ej,", d_taps_upper[i].real(), d_taps_upper[i].imag()); + for(i = 0; i < taps_upper.size(); i++) { + printf(" %.4e + %.4ej,", taps_upper[i].real(), taps_upper[i].imag()); } printf("]\n\n"); printf("Lower Band-edge: ["); - for(i = 0; i < d_taps_lower.size(); i++) { - printf(" %.4e + %.4ej,", d_taps_lower[i].real(), d_taps_lower[i].imag()); + for(i = 0; i < taps_lower.size(); i++) { + printf(" %.4e + %.4ej,", taps_lower[i].real(), taps_lower[i].imag()); } printf("]\n\n"); } @@ -164,6 +160,13 @@ gr_fll_band_edge_cc::work (int noutput_items, const gr_complex *in = (const gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; + float *frq, *phs, *err; + if(output_items.size() > 2) { + frq = (float *) output_items[1]; + phs = (float *) output_items[2]; + err = (float *) output_items[3]; + } + if (d_updated) { d_updated = false; return 0; // history requirements may have changed. @@ -180,21 +183,28 @@ gr_fll_band_edge_cc::work (int noutput_items, out_upper = norm(d_filter_upper->filter(&out[i])); out_lower = norm(d_filter_lower->filter(&out[i])); error = out_lower - out_upper; - d_error = 0.1*error + 0.9*d_error; // average error + d_error = 0.01*error + 0.99*d_error; // average error - d_freq = d_freq + d_beta * error; - d_phase = d_phase + d_freq + d_alpha * error; + d_freq = d_freq + d_beta * d_error; + d_phase = d_phase + d_freq + d_alpha * d_error; if(d_phase > M_PI) d_phase -= M_TWOPI; else if(d_phase < -M_PI) d_phase += M_TWOPI; - + if (d_freq > d_max_freq) d_freq = d_max_freq; else if (d_freq < d_min_freq) d_freq = d_min_freq; + + if(output_items.size() > 2) { + frq[i] = d_freq; + phs[i] = d_phase; + err[i] = d_error; + } } + return noutput_items; } diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h index 86e69df16..09baf7fde 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h @@ -39,6 +39,26 @@ class gri_fft_complex; * \brief Frequency Lock Loop using band-edge filters * * \ingroup general + * + * The frequency lock loop derives a band-edge filter that covers the upper and lower bandwidths + * of a digitally-modulated signal. The bandwidth range is determined by the excess bandwidth + * (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges + * is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth. + * The size of the filters should be fairly large so as to average over a number of symbols. + * The FLL works by calculating the power in both the upper and lower bands and comparing them. The + * difference in power between the filters is proportional to the frequency offset. + * + * In theory, the band-edge filter is the derivative of the matched filter in frequency, + * (H_be(f) = \frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point + * of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine). + * Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent + * in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore + * derived from this sum of sincs. The band edge filters are then just the baseband signal + * modulated to the correct place in frequency. All of these calculations are done in the + * 'design_filter' function. + * + * Note: We use FIR filters here because the filters have to have a flat phase response over the + * entire frequency range to allow their comparisons to be valid. */ class gr_fll_band_edge_cc : public gr_sync_block @@ -46,7 +66,11 @@ class gr_fll_band_edge_cc : public gr_sync_block private: /*! * Build the FLL - * \param taps (vector/list of gr_complex) The taps of the band-edge filter + * \param samps_per_sym (float) Number of samples per symbol of signal + * \param rolloff (float) Rolloff factor of signal + * \param filter_size (int) Size (in taps) of the filter + * \param alpha (float) Loop gain 1 + * \param beta (float) Loop gain 2 */ friend gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff, int filter_size, float alpha, float beta); @@ -58,8 +82,6 @@ class gr_fll_band_edge_cc : public gr_sync_block gr_fir_ccc* d_filter_upper; gr_fir_ccc* d_filter_lower; - std::vector<gr_complex> d_taps_upper; - std::vector<gr_complex> d_taps_lower; bool d_updated; float d_error; float d_freq; @@ -76,17 +98,19 @@ public: ~gr_fll_band_edge_cc (); /*! - * Resets the filter taps with the new prototype filter - * \param taps (vector/list of gr_complex) The band-edge filter + * Design the band-edge filter based on the number of samples per symbol, + * filter rolloff factor, and the filter size + * \param samps_per_sym (float) Number of samples per symbol of signal + * \param rolloff (float) Rolloff factor of signal + * \param filter_size (int) Size (in taps) of the filter */ - void set_taps_lower (const std::vector<gr_complex> &taps); - void set_taps_upper (const std::vector<gr_complex> &taps); + void design_filter(float samps_per_sym, float rolloff, int filter_size); /*! * Set the alpha gainvalue * \param alpha (float) new gain value */ - void set_alpha(float alpha) { d_alpha = alpha; } + void set_alpha(float alpha); /*! * Set the beta gain value diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i index 545bad4f6..c9c792c8a 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i @@ -36,5 +36,6 @@ class gr_fll_band_edge_cc : public gr_sync_block void set_alpha (float alpha); void set_beta (float beta); + void design_filter(float samps_per_sym, float rolloff, int filter_size); void print_taps(); }; diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index cd9a207c8..e9fb3df89 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py @@ -26,7 +26,7 @@ differential BPSK modulation and demodulation. """ from gnuradio import gr, gru, modulation_utils -from math import pi, sqrt +from math import pi, sqrt, ceil import psk import cmath from pprint import pprint @@ -38,6 +38,7 @@ _def_gray_code = True _def_verbose = False _def_log = False +_def_freq_alpha = 4e-3 _def_costas_alpha = 0.1 _def_timing_alpha = 0.100 _def_timing_beta = 0.010 @@ -85,8 +86,6 @@ class dbpsk2_mod(gr.hier_block2): if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2: raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol) - ntaps = 11 * self._samples_per_symbol - arity = pow(2,self.bits_per_symbol()) # turn bytes into k-bit vectors @@ -103,15 +102,15 @@ class dbpsk2_mod(gr.hier_block2): self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]) # pulse shaping filter - self.rrc_taps = gr.firdes.root_raised_cosine( - self._samples_per_symbol, # gain (samples_per_symbol since we're - # interpolating by samples_per_symbol) - self._samples_per_symbol, # sampling rate - 1.0, # symbol rate - self._excess_bw, # excess bandwidth (roll-off factor) + nfilts = 32 + ntaps = nfilts * 11 * 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) # Connect self.connect(self, self.bytes2chunks, self.symbol_mapper, self.diffenc, @@ -182,6 +181,7 @@ class dbpsk2_demod(gr.hier_block2): def __init__(self, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, + freq_alpha=_def_freq_alpha, costas_alpha=_def_costas_alpha, timing_alpha=_def_timing_alpha, timing_max_dev=_def_timing_max_dev, @@ -199,9 +199,11 @@ class dbpsk2_demod(gr.hier_block2): @type samples_per_symbol: float @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float - @param costas_alpha: loop filter gain + @param freq_alpha: loop filter gain for frequency recovery + @type freq_alpha: float + @param costas_alpha: loop filter gain for phase/fine frequency recovery @type costas_alpha: float - @param timing_alpha: timing loop alpha gain + @param timing_alpha: loop alpha gain for timing recovery @type timing_alpha: float @param timing_max: timing loop maximum rate deviations @type timing_max: float @@ -223,6 +225,8 @@ class dbpsk2_demod(gr.hier_block2): self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw + self._freq_alpha = freq_alpha + self._freq_beta = 0.25*self._freq_alpha**2 self._costas_alpha = costas_alpha self._timing_alpha = timing_alpha self._timing_beta = _def_timing_beta @@ -238,24 +242,32 @@ class dbpsk2_demod(gr.hier_block2): self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) #self.agc = gr.feedforward_agc_cc(16, 1.0) + # 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) + + # symbol timing recovery with RRC data filter + nfilts = 32 + ntaps = 11 * int(self._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._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 - self.clock_recov = gr.costas_loop_cc(self._costas_alpha, + self.phase_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) - 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) - # Do differential decoding based on phase change of symbols self.diffdec = gr.diff_phasor_cc() @@ -280,8 +292,7 @@ class dbpsk2_demod(gr.hier_block2): # 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)) @@ -297,6 +308,7 @@ class dbpsk2_demod(gr.hier_block2): 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 "FLL gain: %.2f" % self._freq_alpha print "Costas Loop alpha: %.2f" % self._costas_alpha print "Costas Loop beta: %.2f" % self._costas_beta print "Timing alpha gain: %.2f" % self._timing_alpha @@ -333,6 +345,8 @@ class dbpsk2_demod(gr.hier_block2): 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("", "--freq-alpha", type="float", default=_def_freq_alpha, + help="set frequency lock loop alpha gain value [default=%default] (PSK)") parser.add_option("", "--costas-alpha", type="float", default=None, help="set Costas loop alpha value [default=%default] (PSK)") parser.add_option("", "--gain-alpha", type="float", default=_def_timing_alpha, diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py index fd1e9f0ef..9fae6acca 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py @@ -38,6 +38,7 @@ _def_gray_code = True _def_verbose = False _def_log = False +_def_freq_alpha = 4e-3 _def_costas_alpha = 0.01 _def_timing_alpha = 0.100 _def_timing_beta = 0.010 @@ -105,14 +106,15 @@ class dqpsk2_mod(gr.hier_block2): 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 = nfilts * 11 * 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() @@ -182,6 +184,7 @@ class dqpsk2_demod(gr.hier_block2): def __init__(self, samples_per_symbol=_def_samples_per_symbol, excess_bw=_def_excess_bw, + freq_alpha=_def_freq_alpha, costas_alpha=_def_costas_alpha, timing_alpha=_def_timing_alpha, timing_max_dev=_def_timing_max_dev, @@ -199,6 +202,8 @@ class dqpsk2_demod(gr.hier_block2): @type samples_per_symbol: float @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float + @param freq_alpha: loop filter gain for frequency recovery + @type freq_alpha: float @param costas_alpha: loop filter gain @type costas_alphas: float @param timing_alpha: timing loop alpha gain @@ -223,6 +228,8 @@ class dqpsk2_demod(gr.hier_block2): self._samples_per_symbol = samples_per_symbol self._excess_bw = excess_bw + self._freq_alpha = freq_alpha + self._freq_beta = 0.25*self._freq_alpha**2 self._costas_alpha = costas_alpha self._timing_alpha = timing_alpha self._timing_beta = _def_timing_beta @@ -238,24 +245,35 @@ class dqpsk2_demod(gr.hier_block2): 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._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 + + self.phase_recov = gr.costas_loop_cc(self._costas_alpha, + self._costas_beta, + fmax, fmin, arity) + + # Perform Differential decoding on the constellation self.diffdec = gr.diff_phasor_cc() @@ -280,8 +298,7 @@ class dqpsk2_demod(gr.hier_block2): # 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)) @@ -297,6 +314,7 @@ class dqpsk2_demod(gr.hier_block2): 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 "FLL gain: %.2f" % self._freq_alpha print "Costas Loop alpha: %.2e" % self._costas_alpha print "Costas Loop beta: %.2e" % self._costas_beta print "Timing alpha gain: %.2f" % self._timing_alpha @@ -333,6 +351,8 @@ class dqpsk2_demod(gr.hier_block2): 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("", "--freq-alpha", type="float", default=_def_freq_alpha, + help="set frequency lock loop alpha gain value [default=%default] (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, |