From 8cc51ce7749e5c5562d208a8efaf17828295c70d Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 20 Dec 2009 15:32:23 -0500 Subject: WIP: better access to setting FLL parameters and working on getting gain settings better. --- .../src/lib/general/gr_fll_band_edge_cc.cc | 100 ++++++++++++--------- .../src/lib/general/gr_fll_band_edge_cc.h | 17 ++-- .../src/lib/general/gr_fll_band_edge_cc.i | 1 + 3 files changed, 69 insertions(+), 49 deletions(-) (limited to 'gnuradio-core') 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..38d682020 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 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 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 taps_lower; std::vector 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,44 +122,18 @@ 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 () -{ + set_filter_taps(taps_lower, d_filter_lower); + set_filter_taps(taps_upper, d_filter_upper); } void -gr_fll_band_edge_cc::set_taps_lower (const std::vector &taps) +gr_fll_band_edge_cc::set_filter_taps(const std::vector &taps, + gr_fir_ccc *filter) { - 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_updated = true; -} - -void -gr_fll_band_edge_cc::set_taps_upper (const std::vector &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); + filter->set_taps(taps); // Set the history to ensure enough input items for each filter - set_history(d_taps_upper.size()+1); + set_history(taps.size()+1); d_updated = true; } @@ -143,15 +142,18 @@ void gr_fll_band_edge_cc::print_taps() { unsigned int i; + std::vector taps_upper = d_filter_upper->get_taps(); + std::vector 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 +166,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,7 +189,7 @@ 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; @@ -189,12 +198,19 @@ gr_fll_band_edge_cc::work (int noutput_items, 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..87bf39fd0 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 @@ -58,8 +58,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 d_taps_upper; - std::vector d_taps_lower; bool d_updated; float d_error; float d_freq; @@ -72,21 +70,26 @@ class gr_fll_band_edge_cc : public gr_sync_block gr_fll_band_edge_cc(float samps_per_sym, float rolloff, int filter_size, float alpha, float beta); + void set_filter_taps (const std::vector &taps, + gr_fir_ccc *filter); + 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 &taps); - void set_taps_upper (const std::vector &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(); }; -- cgit From 78809d52b0d28d4f8bb4aaecfe4115312b0e9ce5 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 20 Dec 2009 15:41:17 -0500 Subject: Cleaning up functions. --- gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc | 14 ++++---------- gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h | 3 --- 2 files changed, 4 insertions(+), 13 deletions(-) (limited to 'gnuradio-core') 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 38d682020..03ce16bd7 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 @@ -122,20 +122,14 @@ gr_fll_band_edge_cc::design_filter(float samps_per_sym, float rolloff, int filte d_filter_upper = gr_fir_util::create_gr_fir_ccc(vtaps); d_filter_lower = gr_fir_util::create_gr_fir_ccc(vtaps); - set_filter_taps(taps_lower, d_filter_lower); - set_filter_taps(taps_upper, d_filter_upper); -} + d_filter_lower->set_taps(taps_lower); + d_filter_upper->set_taps(taps_upper); -void -gr_fll_band_edge_cc::set_filter_taps(const std::vector &taps, - gr_fir_ccc *filter) -{ - filter->set_taps(taps); + d_updated = true; // Set the history to ensure enough input items for each filter - set_history(taps.size()+1); + set_history(filter_size+1); - d_updated = true; } void 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 87bf39fd0..584f62610 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 @@ -70,9 +70,6 @@ class gr_fll_band_edge_cc : public gr_sync_block gr_fll_band_edge_cc(float samps_per_sym, float rolloff, int filter_size, float alpha, float beta); - void set_filter_taps (const std::vector &taps, - gr_fir_ccc *filter); - public: ~gr_fll_band_edge_cc (); -- cgit From 3507e4e3d44a85db37737460aa13f86997acfbdb Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 20 Dec 2009 16:58:53 -0500 Subject: Adding some documentation. --- .../src/lib/general/gr_fll_band_edge_cc.h | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'gnuradio-core') 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 584f62610..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); -- cgit From e4c8d59714eff4ef571a43f7952a9af2f3d28a98 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 20 Dec 2009 21:57:40 -0500 Subject: Adding FLL to DBPSK demodulator block. Need OTA testing. --- .../src/python/gnuradio/blks2impl/dbpsk2.py | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'gnuradio-core') diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index cd9a207c8..07e1c945b 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py @@ -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 @@ -182,6 +183,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 +201,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 +227,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,14 +244,12 @@ 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) - 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._costas_beta, - fmax, fmin, arity) + + # Frequency correction + self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, + 11*self._samples_per_symbol, + self._freq_alpha, self._freq_beta) + # symbol timing recovery with RRC data filter nfilts = 32 @@ -255,7 +259,17 @@ class dbpsk2_demod(gr.hier_block2): 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) + # Do differential decoding based on phase change of symbols self.diffdec = gr.diff_phasor_cc() @@ -280,8 +294,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)) @@ -333,6 +346,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, -- cgit From a3418ea4a658cefb02e28b23a5462149aa9d05c3 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 2 Jan 2010 16:30:57 -0500 Subject: Since I'm bothering to average the error, I might as well use it. --- gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gnuradio-core') 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 03ce16bd7..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 @@ -185,8 +185,8 @@ gr_fll_band_edge_cc::work (int noutput_items, error = out_lower - out_upper; 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; -- cgit From 345434daf74cf642f7f7fd7ee28e51e020eadfab Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 2 Jan 2010 16:31:35 -0500 Subject: Printing FLL gain value in verbose mode. --- gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py | 1 + 1 file changed, 1 insertion(+) (limited to 'gnuradio-core') diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index 07e1c945b..e36e4f011 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py @@ -310,6 +310,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 -- cgit From 7fa4e9a1d1f1718991150ccbf3304c0bd1998e21 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 17 Jan 2010 18:14:08 -0500 Subject: Adding FLL correction to DQPSK2 block. --- .../src/python/gnuradio/blks2impl/dbpsk2.py | 4 ++- .../src/python/gnuradio/blks2impl/dqpsk2.py | 39 ++++++++++++++++------ 2 files changed, 32 insertions(+), 11 deletions(-) (limited to 'gnuradio-core') diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index e36e4f011..a692e7d1f 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py @@ -254,7 +254,9 @@ class dbpsk2_demod(gr.hier_block2): # 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) + 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) diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py index fd1e9f0ef..b1ffb0d24 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 @@ -182,6 +183,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 +201,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 +227,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 +244,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*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) + 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._costas_beta, + fmax, fmin, arity) + + # Perform Differential decoding on the constellation self.diffdec = gr.diff_phasor_cc() @@ -280,8 +297,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.clock_recov, self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self) if sync_out: self.connect(self.time_recov, (self, 1)) @@ -297,6 +313,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 +350,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, -- cgit From fd6fd94644330a29ae0598c3ff1e75ddc196e806 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 31 Jan 2010 17:03:36 -0500 Subject: Got this wrong before. Derivative filter taps are now calculated correctly which makes the rest of the code work. My previous test cases must have masked the problem. --- .../src/lib/filter/gr_pfb_arb_resampler_ccf.cc | 33 ++++++++++------------ .../src/lib/filter/gr_pfb_arb_resampler_ccf.h | 1 + 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'gnuradio-core') 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 &newtaps, std::vector &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; -- cgit From 98a0c00c7a922e1c5cbce155205b4e5de725bcf7 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 31 Jan 2010 17:08:03 -0500 Subject: Using PFB resampler to do the RRC filtering on the modulator. This along with the PFB clock recovery in the demod block allows arbitrary real numbers for the number of samples per symbol. We will have to chance the transmit and recieve path code in the examples to take advantage of this. --- .../src/python/gnuradio/blks2impl/dbpsk2.py | 27 +++++++++------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'gnuradio-core') diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index a692e7d1f..b2cc27854 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 @@ -86,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,16 +101,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, @@ -244,16 +241,14 @@ 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*self._samples_per_symbol, + 11*int(self._samples_per_symbol), self._freq_alpha, self._freq_beta) - # symbol timing recovery with RRC data filter nfilts = 32 - ntaps = 11 * samples_per_symbol*nfilts + 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) -- cgit From 3bac2fa547168ca52352892e5f9db3335724682e Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 1 Feb 2010 19:11:03 -0500 Subject: Fixing DQPSK block to work with any real value samples per symbol and getting object names the same as DBPSK block. --- .../src/python/gnuradio/blks2impl/dbpsk2.py | 1 + .../src/python/gnuradio/blks2impl/dqpsk2.py | 23 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'gnuradio-core') diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py index b2cc27854..e9fb3df89 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py @@ -101,6 +101,7 @@ class dbpsk2_mod(gr.hier_block2): self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]) + # pulse shaping filter nfilts = 32 ntaps = nfilts * 11 * self._samples_per_symbol # make nfilts filters of ntaps each self.rrc_taps = gr.firdes.root_raised_cosine( diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py index b1ffb0d24..9fae6acca 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py @@ -106,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() @@ -246,13 +247,13 @@ class dqpsk2_demod(gr.hier_block2): # Frequency correction self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - 11*self._samples_per_symbol, + 11*int(self._samples_per_symbol), self._freq_alpha, self._freq_beta) # symbol timing recovery with RRC data filter nfilts = 32 - ntaps = 11 * samples_per_symbol*nfilts + 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) @@ -268,7 +269,7 @@ class dqpsk2_demod(gr.hier_block2): 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) @@ -297,7 +298,7 @@ class dqpsk2_demod(gr.hier_block2): # Connect self.connect(self, self.agc, - self.freq_recov, self.time_recov, self.clock_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)) -- cgit