3 * Copyright 2009 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
27 #include <gr_fll_band_edge_cc.h>
28 #include <gr_fir_ccc.h>
29 #include <gr_fir_util.h>
31 #include <gr_io_signature.h>
36 #define M_TWOPI (2*M_PI)
43 return sin(M_PI*x)/(M_PI*x);
48 gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
49 int filter_size, float gain_alpha, float gain_beta)
51 return gr_fll_band_edge_cc_sptr (new gr_fll_band_edge_cc (samps_per_sym, rolloff,
52 filter_size, gain_alpha, gain_beta));
56 static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)};
57 static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
58 gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff,
59 int filter_size, float alpha, float beta)
60 : gr_sync_block ("fll_band_edge_cc",
61 gr_make_io_signature (1, 1, sizeof(gr_complex)),
62 gr_make_io_signaturev (1, 4, iosig)),
63 d_alpha(alpha), d_beta(beta), d_updated (false)
65 // base this on the number of samples per symbol
66 d_max_freq = M_TWOPI * (2.0/samps_per_sym);
67 d_min_freq = -M_TWOPI * (2.0/samps_per_sym);
74 design_filter(samps_per_sym, rolloff, filter_size);
77 gr_fll_band_edge_cc::~gr_fll_band_edge_cc ()
79 delete d_filter_lower;
80 delete d_filter_upper;
84 gr_fll_band_edge_cc::set_alpha(float alpha)
86 float eta = sqrt(2.0)/2.0;
88 d_alpha = (4*eta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
89 d_beta = (4*theta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
93 gr_fll_band_edge_cc::design_filter(float samps_per_sym, float rolloff, int filter_size)
95 int M = rint(filter_size / samps_per_sym);
97 std::vector<float> bb_taps;
98 for(int i = 0; i < filter_size; i++) {
99 float k = -M + i*2.0/samps_per_sym;
100 float tap = sinc(rolloff*k - 0.5) + sinc(rolloff*k + 0.5);
103 bb_taps.push_back(tap);
106 int N = (bb_taps.size() - 1.0)/2.0;
107 std::vector<gr_complex> taps_lower;
108 std::vector<gr_complex> taps_upper;
109 for(unsigned int i = 0; i < bb_taps.size(); i++) {
110 float tap = bb_taps[i] / power;
112 float k = (-N + (int)i)/(2.0*samps_per_sym);
114 gr_complex t1 = tap * gr_expj(-2*M_PI*(1+rolloff)*k);
115 gr_complex t2 = tap * gr_expj(2*M_PI*(1+rolloff)*k);
117 taps_lower.push_back(t1);
118 taps_upper.push_back(t2);
121 std::vector<gr_complex> vtaps(0, taps_lower.size());
122 d_filter_upper = gr_fir_util::create_gr_fir_ccc(vtaps);
123 d_filter_lower = gr_fir_util::create_gr_fir_ccc(vtaps);
125 set_filter_taps(taps_lower, d_filter_lower);
126 set_filter_taps(taps_upper, d_filter_upper);
130 gr_fll_band_edge_cc::set_filter_taps(const std::vector<gr_complex> &taps,
133 filter->set_taps(taps);
135 // Set the history to ensure enough input items for each filter
136 set_history(taps.size()+1);
142 gr_fll_band_edge_cc::print_taps()
145 std::vector<gr_complex> taps_upper = d_filter_upper->get_taps();
146 std::vector<gr_complex> taps_lower = d_filter_lower->get_taps();
148 printf("Upper Band-edge: [");
149 for(i = 0; i < taps_upper.size(); i++) {
150 printf(" %.4e + %.4ej,", taps_upper[i].real(), taps_upper[i].imag());
154 printf("Lower Band-edge: [");
155 for(i = 0; i < taps_lower.size(); i++) {
156 printf(" %.4e + %.4ej,", taps_lower[i].real(), taps_lower[i].imag());
162 gr_fll_band_edge_cc::work (int noutput_items,
163 gr_vector_const_void_star &input_items,
164 gr_vector_void_star &output_items)
166 const gr_complex *in = (const gr_complex *) input_items[0];
167 gr_complex *out = (gr_complex *) output_items[0];
169 float *frq, *phs, *err;
170 if(output_items.size() > 2) {
171 frq = (float *) output_items[1];
172 phs = (float *) output_items[2];
173 err = (float *) output_items[3];
178 return 0; // history requirements may have changed.
183 float out_upper, out_lower;
185 for(i = 0; i < noutput_items; i++) {
186 nco_out = gr_expj(d_phase);
187 out[i] = in[i] * nco_out;
189 out_upper = norm(d_filter_upper->filter(&out[i]));
190 out_lower = norm(d_filter_lower->filter(&out[i]));
191 error = out_lower - out_upper;
192 d_error = 0.01*error + 0.99*d_error; // average error
194 d_freq = d_freq + d_beta * error;
195 d_phase = d_phase + d_freq + d_alpha * error;
199 else if(d_phase < -M_PI)
202 if (d_freq > d_max_freq)
204 else if (d_freq < d_min_freq)
207 if(output_items.size() > 2) {
215 return noutput_items;