1 /* -*- c++ -*- */
2 /*
3  * Copyright 2014 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 "atsc_equalizer_impl.h"
28 #include "atsc_pnXXX_impl.h"
29 #include "atsc_types.h"
30 #include <gnuradio/io_signature.h>
31 #include <volk/volk.h>
32 
33 namespace gr {
34 namespace dtv {
35 
make()36 atsc_equalizer::sptr atsc_equalizer::make()
37 {
38     return gnuradio::get_initial_sptr(new atsc_equalizer_impl());
39 }
40 
bin_map(int bit)41 static float bin_map(int bit) { return bit ? +5 : -5; }
42 
init_field_sync_common(float * p,int mask)43 static void init_field_sync_common(float* p, int mask)
44 {
45     int i = 0;
46 
47     p[i++] = bin_map(1); // data segment sync pulse
48     p[i++] = bin_map(0);
49     p[i++] = bin_map(0);
50     p[i++] = bin_map(1);
51 
52     for (int j = 0; j < 511; j++) // PN511
53         p[i++] = bin_map(atsc_pn511[j]);
54 
55     for (int j = 0; j < 63; j++) // PN63
56         p[i++] = bin_map(atsc_pn63[j]);
57 
58     for (int j = 0; j < 63; j++) // PN63, toggled on field 2
59         p[i++] = bin_map(atsc_pn63[j] ^ mask);
60 
61     for (int j = 0; j < 63; j++) // PN63
62         p[i++] = bin_map(atsc_pn63[j]);
63 }
64 
atsc_equalizer_impl()65 atsc_equalizer_impl::atsc_equalizer_impl()
66     : gr::block("dtv_atsc_equalizer",
67                 io_signature::make(1, 1, sizeof(atsc_soft_data_segment)),
68                 io_signature::make(1, 1, sizeof(atsc_soft_data_segment)))
69 {
70     init_field_sync_common(training_sequence1, 0);
71     init_field_sync_common(training_sequence2, 1);
72 
73     d_taps.resize(NTAPS, 0.0f);
74 
75     d_buff_not_filled = true;
76 
77     const int alignment_multiple = volk_get_alignment() / sizeof(float);
78     set_alignment(std::max(1, alignment_multiple));
79 }
80 
~atsc_equalizer_impl()81 atsc_equalizer_impl::~atsc_equalizer_impl() {}
82 
taps() const83 std::vector<float> atsc_equalizer_impl::taps() const { return d_taps; }
84 
data() const85 std::vector<float> atsc_equalizer_impl::data() const
86 {
87     std::vector<float> ret(&data_mem2[0], &data_mem2[ATSC_DATA_SEGMENT_LENGTH - 1]);
88     return ret;
89 }
90 
filterN(const float * input_samples,float * output_samples,int nsamples)91 void atsc_equalizer_impl::filterN(const float* input_samples,
92                                   float* output_samples,
93                                   int nsamples)
94 {
95     for (int j = 0; j < nsamples; j++) {
96         output_samples[j] = 0;
97         volk_32f_x2_dot_prod_32f(
98             &output_samples[j], &input_samples[j], &d_taps[0], NTAPS);
99     }
100 }
101 
adaptN(const float * input_samples,const float * training_pattern,float * output_samples,int nsamples)102 void atsc_equalizer_impl::adaptN(const float* input_samples,
103                                  const float* training_pattern,
104                                  float* output_samples,
105                                  int nsamples)
106 {
107     static const double BETA = 0.00005; // FIXME figure out what this ought to be
108                                         // FIXME add gear-shifting
109 
110     for (int j = 0; j < nsamples; j++) {
111         output_samples[j] = 0;
112         volk_32f_x2_dot_prod_32f(
113             &output_samples[j], &input_samples[j], &d_taps[0], NTAPS);
114 
115         float e = output_samples[j] - training_pattern[j];
116 
117         // update taps...
118         float tmp_taps[NTAPS];
119         volk_32f_s32f_multiply_32f(tmp_taps, &input_samples[j], BETA * e, NTAPS);
120         volk_32f_x2_subtract_32f(&d_taps[0], &d_taps[0], tmp_taps, NTAPS);
121     }
122 }
123 
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)124 int atsc_equalizer_impl::general_work(int noutput_items,
125                                       gr_vector_int& ninput_items,
126                                       gr_vector_const_void_star& input_items,
127                                       gr_vector_void_star& output_items)
128 {
129     const atsc_soft_data_segment* in = (const atsc_soft_data_segment*)input_items[0];
130     atsc_soft_data_segment* out = (atsc_soft_data_segment*)output_items[0];
131 
132     int output_produced = 0;
133     int i = 0;
134 
135     if (d_buff_not_filled) {
136         memset(&data_mem[0], 0, NPRETAPS * sizeof(float));
137         memcpy(&data_mem[NPRETAPS], in[i].data, ATSC_DATA_SEGMENT_LENGTH * sizeof(float));
138         d_flags = in[i].pli._flags;
139         d_segno = in[i].pli._segno;
140         d_buff_not_filled = false;
141         i++;
142     }
143 
144     for (; i < noutput_items; i++) {
145 
146         memcpy(&data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS],
147                in[i].data,
148                (NTAPS - NPRETAPS) * sizeof(float));
149 
150         if (d_segno == -1) {
151             if (d_flags & 0x0010) {
152                 adaptN(data_mem, training_sequence2, data_mem2, KNOWN_FIELD_SYNC_LENGTH);
153                 // filterN(&data_mem[KNOWN_FIELD_SYNC_LENGTH], data_mem2,
154                 // ATSC_DATA_SEGMENT_LENGTH - KNOWN_FIELD_SYNC_LENGTH);
155             } else if (!(d_flags & 0x0010)) {
156                 adaptN(data_mem, training_sequence1, data_mem2, KNOWN_FIELD_SYNC_LENGTH);
157                 // filterN(&data_mem[KNOWN_FIELD_SYNC_LENGTH], data_mem2,
158                 // ATSC_DATA_SEGMENT_LENGTH - KNOWN_FIELD_SYNC_LENGTH);
159             }
160         } else {
161             filterN(data_mem, data_mem2, ATSC_DATA_SEGMENT_LENGTH);
162 
163             memcpy(out[output_produced].data,
164                    data_mem2,
165                    ATSC_DATA_SEGMENT_LENGTH * sizeof(float));
166 
167             out[output_produced].pli._flags = d_flags;
168             out[output_produced].pli._segno = d_segno;
169             output_produced++;
170         }
171 
172         memcpy(data_mem, &data_mem[ATSC_DATA_SEGMENT_LENGTH], NPRETAPS * sizeof(float));
173         memcpy(&data_mem[NPRETAPS], in[i].data, ATSC_DATA_SEGMENT_LENGTH * sizeof(float));
174 
175         d_flags = in[i].pli._flags;
176         d_segno = in[i].pli._segno;
177     }
178 
179     consume_each(noutput_items);
180     return output_produced;
181 }
182 
setup_rpc()183 void atsc_equalizer_impl::setup_rpc()
184 {
185 #ifdef GR_CTRLPORT
186     add_rpc_variable(
187         rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float>>(
188             alias(),
189             "taps",
190             &atsc_equalizer::taps,
191             pmt::make_f32vector(1, -10),
192             pmt::make_f32vector(1, 10),
193             pmt::make_f32vector(1, 0),
194             "",
195             "Equalizer Taps",
196             RPC_PRIVLVL_MIN,
197             DISPTIME)));
198 
199     add_rpc_variable(
200         rpcbasic_sptr(new rpcbasic_register_get<atsc_equalizer, std::vector<float>>(
201             alias(),
202             "data",
203             &atsc_equalizer::data,
204             pmt::make_f32vector(1, -10),
205             pmt::make_f32vector(1, 10),
206             pmt::make_f32vector(1, 0),
207             "",
208             "Post-equalizer Data",
209             RPC_PRIVLVL_MIN,
210             DISPTIME)));
211 #endif /* GR_CTRLPORT */
212 }
213 
214 } /* namespace dtv */
215 } /* namespace gr */
216