WIP: better access to setting FLL parameters and working on getting gain settings...
[debian/gnuradio] / gnuradio-core / src / lib / general / gr_fll_band_edge_cc.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
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)
10  * any later version.
11  * 
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.
16  * 
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_fll_band_edge_cc.h>
28 #include <gr_fir_ccc.h>
29 #include <gr_fir_util.h>
30 #include <gri_fft.h>
31 #include <gr_io_signature.h>
32 #include <gr_expj.h>
33 #include <gr_math.h>
34 #include <cstdio>
35
36 #define M_TWOPI (2*M_PI)
37
38 float sinc(float x)
39 {
40   if(x == 0)
41     return 1;
42   else
43     return sin(M_PI*x)/(M_PI*x);
44 }
45   
46
47
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)
50 {
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));
53 }
54
55
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)
64 {
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);
68
69   d_freq = 0;
70   d_phase = 0;
71
72   set_alpha(alpha);
73
74   design_filter(samps_per_sym, rolloff, filter_size);
75 }
76
77 gr_fll_band_edge_cc::~gr_fll_band_edge_cc ()
78 {
79   delete d_filter_lower;
80   delete d_filter_upper;
81 }
82
83 void
84 gr_fll_band_edge_cc::set_alpha(float alpha) 
85
86   float eta = sqrt(2.0)/2.0;
87   float theta = alpha;
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);
90 }
91
92 void
93 gr_fll_band_edge_cc::design_filter(float samps_per_sym, float rolloff, int filter_size)
94 {
95   int M = rint(filter_size / samps_per_sym);
96   float power = 0;
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);
101     power += tap;
102
103     bb_taps.push_back(tap);
104   }
105
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;
111
112     float k = (-N + (int)i)/(2.0*samps_per_sym);
113     
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);
116
117     taps_lower.push_back(t1);
118     taps_upper.push_back(t2);
119   }
120
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);
124
125   set_filter_taps(taps_lower, d_filter_lower);
126   set_filter_taps(taps_upper, d_filter_upper);
127 }
128
129 void
130 gr_fll_band_edge_cc::set_filter_taps(const std::vector<gr_complex> &taps, 
131                                      gr_fir_ccc *filter)
132 {
133   filter->set_taps(taps);
134
135   // Set the history to ensure enough input items for each filter
136   set_history(taps.size()+1);
137
138   d_updated = true;
139 }
140
141 void
142 gr_fll_band_edge_cc::print_taps()
143 {
144   unsigned int i;
145   std::vector<gr_complex> taps_upper = d_filter_upper->get_taps();
146   std::vector<gr_complex> taps_lower = d_filter_lower->get_taps();
147
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());
151   }
152   printf("]\n\n");
153
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());
157   }
158   printf("]\n\n");
159 }
160
161 int
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)
165 {
166   const gr_complex *in  = (const gr_complex *) input_items[0];
167   gr_complex *out = (gr_complex *) output_items[0];
168
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];
174   }
175
176   if (d_updated) {
177     d_updated = false;
178     return 0;                // history requirements may have changed.
179   }
180
181   int i;
182   gr_complex nco_out;
183   float out_upper, out_lower;
184   float error;
185   for(i = 0; i < noutput_items; i++) {
186     nco_out = gr_expj(d_phase);
187     out[i] = in[i] * nco_out;
188
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
193
194     d_freq = d_freq + d_beta * error;
195     d_phase = d_phase + d_freq + d_alpha * error;
196
197     if(d_phase > M_PI)
198       d_phase -= M_TWOPI;
199     else if(d_phase < -M_PI)
200       d_phase += M_TWOPI;
201
202     if (d_freq > d_max_freq)
203       d_freq = d_max_freq;
204     else if (d_freq < d_min_freq)
205       d_freq = d_min_freq;
206
207     if(output_items.size() > 2) {
208       frq[i] = d_freq;
209       phs[i] = d_phase;
210       err[i] = d_error;
211     }
212   }
213
214
215   return noutput_items;
216 }