Imported Upstream version 3.0
[debian/gnuradio] / gnuradio-core / src / lib / general / gr_lms_dfe_cc.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2005 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 2, 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_lms_dfe_cc.h>
28 #include <gr_io_signature.h>
29 #include <gr_misc.h>
30 #include <iostream>
31
32 gr_complex
33 gr_lms_dfe_cc::slicer_0deg (gr_complex sample)
34 {
35   gr_complex out;
36   if(fabs(real(sample))>fabs(imag(sample))) {
37     if(real(sample) > 0)
38       out = gr_complex(1,0);
39     else
40       out = gr_complex(-1,0);
41   }
42   else {
43     if(imag(sample) > 0)
44       out = gr_complex(0,1);
45     else
46       out = gr_complex(0,-1);
47   }
48   return out;
49 }
50
51 gr_complex
52 gr_lms_dfe_cc::slicer_45deg (gr_complex sample)
53 {
54   gr_complex out;
55   if(real(sample) > 0)
56     out = gr_complex(1,0);
57   else
58     out = gr_complex(-1,0);
59   if(imag(sample) > 0)
60     out += gr_complex(0,1);
61   else
62     out += gr_complex(0,-1);
63   return out;
64 }
65
66 gr_lms_dfe_cc_sptr
67 gr_make_lms_dfe_cc (float lambda_ff, float lambda_fb, 
68                     unsigned int num_fftaps, unsigned int num_fbtaps)
69 {
70   return gr_lms_dfe_cc_sptr (new gr_lms_dfe_cc (lambda_ff, lambda_fb,
71                                                 num_fftaps, num_fbtaps));
72 }
73
74 gr_lms_dfe_cc::gr_lms_dfe_cc (float lambda_ff, float lambda_fb , 
75                               unsigned int num_fftaps, unsigned int num_fbtaps)
76   : gr_sync_block ("lms_dfe_cc",
77                    gr_make_io_signature (1, 1, sizeof (gr_complex)),
78                    gr_make_io_signature (1, 1, sizeof (gr_complex))),
79     d_lambda_ff (lambda_ff), d_lambda_fb (lambda_fb), 
80     d_ff_delayline(gr_rounduppow2(num_fftaps)),
81     d_fb_delayline(gr_rounduppow2(num_fbtaps)),
82     d_ff_taps(num_fftaps),d_fb_taps(num_fbtaps),
83     d_ff_index(0), d_fb_index(0)
84 {
85   gr_zero_vector(d_ff_taps);
86   d_ff_taps [d_ff_taps.size()/2] = 1;
87
88   gr_zero_vector(d_fb_taps);
89   gr_zero_vector(d_ff_delayline);
90   gr_zero_vector(d_fb_delayline);
91 }
92
93 int
94 gr_lms_dfe_cc::work (int noutput_items,
95                    gr_vector_const_void_star &input_items,
96                    gr_vector_void_star &output_items)
97 {
98   const gr_complex *iptr = (const gr_complex *) input_items[0];
99   gr_complex *optr = (gr_complex *) output_items[0];
100   
101   gr_complex acc, decision, error;
102   unsigned int i;
103
104   unsigned int ff_mask = d_ff_delayline.size() - 1;     // size is power of 2
105   unsigned int fb_mask = d_fb_delayline.size() - 1;
106
107   int   size = noutput_items;
108   while (size-- > 0){
109     acc = 0; 
110     d_ff_delayline[d_ff_index] = *iptr++;
111
112     // Compute output
113     for (i=0; i < d_ff_taps.size(); i++) 
114       acc += conj(d_ff_delayline[(i+d_ff_index) & ff_mask]) * d_ff_taps[i];
115     
116     for (i=0; i < d_fb_taps.size(); i++)
117       acc -= conj(d_fb_delayline[(i+d_fb_index) & fb_mask]) * d_fb_taps[i];
118
119     decision = slicer_45deg(acc);
120     error = decision - acc;
121     
122     //  Update taps
123     for (i=0; i < d_ff_taps.size(); i++)
124       d_ff_taps[i] += d_lambda_ff * conj(error) * d_ff_delayline[(i+d_ff_index) & ff_mask];
125     
126     for (i=0; i < d_fb_taps.size(); i++)
127       d_fb_taps[i] -= d_lambda_fb * conj(error) * d_fb_delayline[(i+d_fb_index) & fb_mask];
128     
129     d_fb_index = (d_fb_index - 1) & fb_mask;    // Decrement index
130     d_ff_index = (d_ff_index - 1) & ff_mask;    // Decrement index
131
132     d_fb_delayline[d_fb_index] = decision;      // Save decision in feedback
133
134     *optr++ = acc;   // Output decision
135   }
136
137   if (0){
138     std::cout << "FF Taps\t";
139     for(i=0;i<d_ff_taps.size();i++)
140       std::cout << d_ff_taps[i] << "\t";
141     std::cout << std::endl << "FB Taps\t";
142     for(i=0;i<d_fb_taps.size();i++)
143       std::cout << d_fb_taps[i] << "\t";
144     std::cout << std::endl;
145   }
146
147   return noutput_items;
148 }