1 /* -*- c++ -*- */
2 /*
3 * Copyright 2015,2016,2018,2019 Free Software Foundation, Inc.
4 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "dvbt_reference_signals_impl.h"
26 #include <gnuradio/expj.h>
27 #include <gnuradio/io_signature.h>
28 #include <gnuradio/math.h>
29 #include <algorithm>
30 #include <complex>
31
32 namespace gr {
33 namespace dtv {
34
35 // Number of symbols in a frame
36 const int dvbt_pilot_gen::d_symbols_per_frame = SYMBOLS_PER_FRAME;
37 // Number of frames in a superframe
38 const int dvbt_pilot_gen::d_frames_per_superframe = FRAMES_PER_SUPERFRAME;
39
40 // 2k mode
41 // Scattered pilots # of carriers
42 const int dvbt_pilot_gen::d_spilot_carriers_size_2k = SCATTERED_PILOT_SIZE_2k;
43 // Continual pilots # of carriers and positions
44 const int dvbt_pilot_gen::d_cpilot_carriers_size_2k = CONTINUAL_PILOT_SIZE_2k;
45 const int
46 dvbt_pilot_gen::d_cpilot_carriers_2k[dvbt_pilot_gen::d_cpilot_carriers_size_2k] = {
47 0, 48, 54, 87, 141, 156, 192, 201, 255, 279, 282, 333,
48 432, 450, 483, 525, 531, 618, 636, 714, 759, 765, 780, 804,
49 873, 888, 918, 939, 942, 969, 984, 1050, 1101, 1107, 1110, 1137,
50 1140, 1146, 1206, 1269, 1323, 1377, 1491, 1683, 1704
51 };
52 // TPS pilots # of carriers and positions
53 const int dvbt_pilot_gen::d_tps_carriers_size_2k = TPS_PILOT_SIZE_2k;
54 const int dvbt_pilot_gen::d_tps_carriers_2k[dvbt_pilot_gen::d_tps_carriers_size_2k] = {
55 34, 50, 209, 346, 413, 569, 595, 688, 790,
56 901, 1073, 1219, 1262, 1286, 1469, 1594, 1687
57 };
58
59 // 8k mode
60 // Scattered pilots # of carriers
61 const int dvbt_pilot_gen::d_spilot_carriers_size_8k = SCATTERED_PILOT_SIZE_8k;
62 // Continual pilots # of carriers and positions
63 const int dvbt_pilot_gen::d_cpilot_carriers_size_8k = CONTINUAL_PILOT_SIZE_8k;
64 const int
65 dvbt_pilot_gen::d_cpilot_carriers_8k[dvbt_pilot_gen::d_cpilot_carriers_size_8k] = {
66 0, 48, 54, 87, 141, 156, 192, 201, 255, 279, 282, 333, 432,
67 450, 483, 525, 531, 618, 636, 714, 759, 765, 780, 804, 873, 888,
68 918, 939, 942, 969, 984, 1050, 1101, 1107, 1110, 1137, 1140, 1146, 1206,
69 1269, 1323, 1377, 1491, 1683, 1704, 1752, 1758, 1791, 1845, 1860, 1896, 1905,
70 1959, 1983, 1986, 2037, 2136, 2154, 2187, 2229, 2235, 2322, 2340, 2418, 2463,
71 2469, 2484, 2508, 2577, 2592, 2622, 2643, 2646, 2673, 2688, 2754, 2805, 2811,
72 2814, 2841, 2844, 2850, 2910, 2973, 3027, 3081, 3195, 3387, 3408, 3456, 3462,
73 3495, 3549, 3564, 3600, 3609, 3663, 3687, 3690, 3741, 3840, 3858, 3891, 3933,
74 3939, 4026, 4044, 4122, 4167, 4173, 4188, 4212, 4281, 4296, 4326, 4347, 4350,
75 4377, 4392, 4458, 4509, 4515, 4518, 4545, 4548, 4554, 4614, 4677, 4731, 4785,
76 4899, 5091, 5112, 5160, 5166, 5199, 5253, 5268, 5304, 5313, 5367, 5391, 5394,
77 5445, 5544, 5562, 5595, 5637, 5643, 5730, 5748, 5826, 5871, 5877, 5892, 5916,
78 5985, 6000, 6030, 6051, 6054, 6081, 6096, 6162, 6213, 6219, 6222, 6249, 6252,
79 6258, 6318, 6381, 6435, 6489, 6603, 6795, 6816
80 };
81 // TPS pilots # of carriers and positions
82 const int dvbt_pilot_gen::d_tps_carriers_size_8k = TPS_PILOT_SIZE_8k;
83 const int dvbt_pilot_gen::d_tps_carriers_8k[dvbt_pilot_gen::d_tps_carriers_size_8k] = {
84 34, 50, 209, 346, 413, 569, 595, 688, 790, 901, 1073, 1219, 1262, 1286,
85 1469, 1594, 1687, 1738, 1754, 1913, 2050, 2117, 2273, 2299, 2392, 2494, 2605, 2777,
86 2923, 2966, 2990, 3173, 3298, 3391, 3442, 3458, 3617, 3754, 3821, 3977, 4003, 4096,
87 4198, 4309, 4481, 4627, 4670, 4694, 4877, 5002, 5095, 5146, 5162, 5321, 5458, 5525,
88 5681, 5707, 5800, 5902, 6013, 6185, 6331, 6374, 6398, 6581, 6706, 6799
89 };
90
91 // TPS sync sequence for odd and even frames
92 const int dvbt_pilot_gen::d_tps_sync_size = 16; // TODO
93 const int dvbt_pilot_gen::d_tps_sync_even[d_tps_sync_size] = { 0, 0, 1, 1, 0, 1, 0, 1,
94 1, 1, 1, 0, 1, 1, 1, 0 };
95 const int dvbt_pilot_gen::d_tps_sync_odd[d_tps_sync_size] = { 1, 1, 0, 0, 1, 0, 1, 0,
96 0, 0, 0, 1, 0, 0, 0, 1 };
97
98 /*
99 * Constructor of class
100 */
dvbt_pilot_gen(const dvbt_configure & c)101 dvbt_pilot_gen::dvbt_pilot_gen(const dvbt_configure& c)
102 : config(c),
103 d_spilot_index(0),
104 d_cpilot_index(0),
105 d_tpilot_index(0),
106 d_symbol_index(0),
107 d_symbol_index_known(0),
108 d_frame_index(0),
109 d_superframe_index(0),
110 d_freq_offset_max(8),
111 d_trigger_index(0),
112 d_payload_index(0),
113 d_chanestim_index(0),
114 d_prev_mod_symbol_index(0),
115 d_mod_symbol_index(0)
116 {
117 // Determine parameters from config file
118 d_Kmin = config.d_Kmin;
119 d_Kmax = config.d_Kmax;
120 d_fft_length = config.d_fft_length;
121 d_payload_length = config.d_payload_length;
122 d_zeros_on_left = config.d_zeros_on_left;
123 d_zeros_on_right = config.d_zeros_on_right;
124 d_cp_length = config.d_cp_length;
125
126 // Set-up pilot data depending on transmission mode
127 if (config.d_transmission_mode == T2k) {
128 d_spilot_carriers_size = d_spilot_carriers_size_2k;
129 d_cpilot_carriers_size = d_cpilot_carriers_size_2k;
130 d_cpilot_carriers = d_cpilot_carriers_2k;
131 d_tps_carriers_size = d_tps_carriers_size_2k;
132 d_tps_carriers = d_tps_carriers_2k;
133 } else if (config.d_transmission_mode == T8k) {
134 d_spilot_carriers_size = d_spilot_carriers_size_8k;
135 d_cpilot_carriers_size = d_cpilot_carriers_size_8k;
136 d_cpilot_carriers = d_cpilot_carriers_8k;
137 d_tps_carriers_size = d_tps_carriers_size_8k;
138 d_tps_carriers = d_tps_carriers_8k;
139 } else {
140 d_spilot_carriers_size = d_spilot_carriers_size_2k;
141 d_cpilot_carriers_size = d_cpilot_carriers_size_2k;
142 d_cpilot_carriers = d_cpilot_carriers_2k;
143 d_tps_carriers_size = d_tps_carriers_size_2k;
144 d_tps_carriers = d_tps_carriers_2k;
145 }
146
147 d_freq_offset = 0;
148 d_carrier_freq_correction = 0.0;
149 d_sampling_freq_correction = 0.0;
150
151 // allocate PRBS buffer
152 d_wk = new char[d_Kmax - d_Kmin + 1];
153 if (d_wk == NULL) {
154 std::cerr << "Reference Signals, cannot allocate memory for d_wk." << std::endl;
155 throw std::bad_alloc();
156 }
157 // Generate wk sequence
158 generate_prbs();
159
160 // allocate buffer for scattered pilots
161 d_spilot_carriers_val = new (std::nothrow) gr_complex[d_Kmax - d_Kmin + 1];
162 if (d_spilot_carriers_val == NULL) {
163 std::cerr
164 << "Reference Signals, cannot allocate memory for d_spilot_carriers_val."
165 << std::endl;
166 delete[] d_wk;
167 throw std::bad_alloc();
168 }
169
170 // allocate buffer for channel gains (for each useful carrier)
171 d_channel_gain = new (std::nothrow) gr_complex[d_Kmax - d_Kmin + 1];
172 if (d_channel_gain == NULL) {
173 std::cerr << "Reference Signals, cannot allocate memory for d_channel_gain."
174 << std::endl;
175 delete[] d_spilot_carriers_val;
176 delete[] d_wk;
177 throw std::bad_alloc();
178 }
179
180 // Allocate buffer for continual pilots phase diffs
181 d_known_phase_diff = new (std::nothrow) float[d_cpilot_carriers_size - 1];
182 if (d_known_phase_diff == NULL) {
183 std::cerr << "Reference Signals, cannot allocate memory for d_known_phase_diff."
184 << std::endl;
185 delete[] d_channel_gain;
186 delete[] d_spilot_carriers_val;
187 delete[] d_wk;
188 throw std::bad_alloc();
189 }
190
191 // Obtain phase diff for all continual pilots
192 for (int i = 0; i < (d_cpilot_carriers_size - 1); i++) {
193 d_known_phase_diff[i] = norm(get_cpilot_value(d_cpilot_carriers[i + 1]) -
194 get_cpilot_value(d_cpilot_carriers[i]));
195 }
196
197 d_cpilot_phase_diff = new (std::nothrow) float[d_cpilot_carriers_size - 1];
198 if (d_cpilot_phase_diff == NULL) {
199 std::cerr << "Reference Signals, cannot allocate memory for d_cpilot_phase_diff."
200 << std::endl;
201 delete[] d_known_phase_diff;
202 delete[] d_channel_gain;
203 delete[] d_spilot_carriers_val;
204 delete[] d_wk;
205 throw std::bad_alloc();
206 }
207
208 // Allocate buffer for derotated input symbol
209 d_derot_in = new (std::nothrow) gr_complex[d_fft_length];
210 if (d_derot_in == NULL) {
211 std::cerr << "Reference Signals, cannot allocate memory for d_derot_in."
212 << std::endl;
213 delete[] d_cpilot_phase_diff;
214 delete[] d_known_phase_diff;
215 delete[] d_channel_gain;
216 delete[] d_spilot_carriers_val;
217 delete[] d_wk;
218 throw std::bad_alloc();
219 }
220
221 // allocate buffer for first tps symbol constellation
222 d_tps_carriers_val = new (std::nothrow) gr_complex[d_tps_carriers_size];
223 if (d_tps_carriers_val == NULL) {
224 std::cerr << "Reference Signals, cannot allocate memory for d_tps_carriers_val."
225 << std::endl;
226 delete[] d_derot_in;
227 delete[] d_cpilot_phase_diff;
228 delete[] d_known_phase_diff;
229 delete[] d_channel_gain;
230 delete[] d_spilot_carriers_val;
231 delete[] d_wk;
232 throw std::bad_alloc();
233 }
234
235 // allocate tps data buffer
236 d_tps_data = new (std::nothrow) unsigned char[d_symbols_per_frame];
237 if (d_tps_data == NULL) {
238 std::cerr << "Reference Signals, cannot allocate memory for d_tps_data."
239 << std::endl;
240 delete[] d_tps_carriers_val;
241 delete[] d_derot_in;
242 delete[] d_cpilot_phase_diff;
243 delete[] d_known_phase_diff;
244 delete[] d_channel_gain;
245 delete[] d_spilot_carriers_val;
246 delete[] d_wk;
247 throw std::bad_alloc();
248 }
249
250 d_prev_tps_symbol = new (std::nothrow) gr_complex[d_tps_carriers_size];
251 if (d_prev_tps_symbol == NULL) {
252 std::cerr << "Reference Signals, cannot allocate memory for d_prev_tps_symbol."
253 << std::endl;
254 delete[] d_tps_data;
255 delete[] d_tps_carriers_val;
256 delete[] d_derot_in;
257 delete[] d_cpilot_phase_diff;
258 delete[] d_known_phase_diff;
259 delete[] d_channel_gain;
260 delete[] d_spilot_carriers_val;
261 delete[] d_wk;
262 throw std::bad_alloc();
263 }
264 std::fill_n(d_prev_tps_symbol, d_tps_carriers_size, 0);
265
266 d_tps_symbol = new (std::nothrow) gr_complex[d_tps_carriers_size];
267 if (d_tps_symbol == NULL) {
268 std::cerr << "Reference Signals, cannot allocate memory for d_tps_symbol."
269 << std::endl;
270 delete[] d_prev_tps_symbol;
271 delete[] d_tps_data;
272 delete[] d_tps_carriers_val;
273 delete[] d_derot_in;
274 delete[] d_cpilot_phase_diff;
275 delete[] d_known_phase_diff;
276 delete[] d_channel_gain;
277 delete[] d_spilot_carriers_val;
278 delete[] d_wk;
279 throw std::bad_alloc();
280 }
281 std::fill_n(d_tps_symbol, d_tps_carriers_size, 0);
282
283 // Init receive TPS data vector
284 for (int i = 0; i < d_symbols_per_frame; i++) {
285 d_rcv_tps_data.push_back(0);
286 }
287
288 // Init TPS sync sequence
289 for (int i = 0; i < d_tps_sync_size; i++) {
290 d_tps_sync_evenv.push_back(d_tps_sync_even[i]);
291 d_tps_sync_oddv.push_back(d_tps_sync_odd[i]);
292 }
293
294 // Allocate buffer for channel estimation carriers
295 d_chanestim_carriers = new (std::nothrow) int[d_Kmax - d_Kmin + 1];
296 if (d_chanestim_carriers == NULL) {
297 std::cerr << "Reference Signals, cannot allocate memory for d_chanestim_carriers."
298 << std::endl;
299 delete[] d_tps_symbol;
300 delete[] d_prev_tps_symbol;
301 delete[] d_tps_data;
302 delete[] d_tps_carriers_val;
303 delete[] d_derot_in;
304 delete[] d_cpilot_phase_diff;
305 delete[] d_known_phase_diff;
306 delete[] d_channel_gain;
307 delete[] d_spilot_carriers_val;
308 delete[] d_wk;
309 throw std::bad_alloc();
310 }
311
312 // Allocate buffer for payload carriers
313 d_payload_carriers = new (std::nothrow) int[d_Kmax - d_Kmin + 1];
314 if (d_payload_carriers == NULL) {
315 std::cerr << "Reference Signals, cannot allocate memory for d_payload_carriers."
316 << std::endl;
317 delete[] d_chanestim_carriers;
318 delete[] d_tps_symbol;
319 delete[] d_prev_tps_symbol;
320 delete[] d_tps_data;
321 delete[] d_tps_carriers_val;
322 delete[] d_derot_in;
323 delete[] d_cpilot_phase_diff;
324 delete[] d_known_phase_diff;
325 delete[] d_channel_gain;
326 delete[] d_spilot_carriers_val;
327 delete[] d_wk;
328 throw std::bad_alloc();
329 }
330
331 // Reset the pilot generator
332 reset_pilot_generator();
333 // Format TPS data with current values
334 format_tps_data();
335 }
336
337 /*
338 * Destructor of class
339 */
~dvbt_pilot_gen()340 dvbt_pilot_gen::~dvbt_pilot_gen()
341 {
342 delete[] d_payload_carriers;
343 delete[] d_chanestim_carriers;
344 delete[] d_tps_symbol;
345 delete[] d_prev_tps_symbol;
346 delete[] d_tps_data;
347 delete[] d_tps_carriers_val;
348 delete[] d_derot_in;
349 delete[] d_cpilot_phase_diff;
350 delete[] d_known_phase_diff;
351 delete[] d_channel_gain;
352 delete[] d_spilot_carriers_val;
353 delete[] d_wk;
354 }
355
356 /*
357 * Generate PRBS sequence
358 * X^11 + X^2 + 1
359 * en 300 744 - section 4.5.2
360 */
generate_prbs()361 void dvbt_pilot_gen::generate_prbs()
362 {
363 // init PRBS register with 1s
364 unsigned int reg_prbs = (1 << 11) - 1;
365
366 for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) {
367 d_wk[k] = (char)(reg_prbs & 0x01);
368 int new_bit = ((reg_prbs >> 2) ^ (reg_prbs >> 0)) & 0x01;
369 reg_prbs = (reg_prbs >> 1) | (new_bit << 10);
370 }
371 }
372
373 /*
374 * Generate shortened BCH(67, 53) codes from TPS data
375 * Extend the code with 60 bits and use BCH(127, 113)
376 */
generate_bch_code()377 void dvbt_pilot_gen::generate_bch_code()
378 {
379 // TODO
380 // DO other way: if (feedback == 1) reg = reg ^ polymomial
381 // else nothing
382
383 //(n, k) = (127, 113) = (60+67, 60+53)
384 unsigned int reg_bch = 0;
385 unsigned char data_in[113];
386
387 // fill in 60 zeros
388 memset(&data_in[0], 0, 60);
389 // fill in TPS data - start bit not included
390 memcpy(&data_in[60], &d_tps_data[1], 53);
391
392 // X^14+X^9+X^8+X^6+X^5+X^4+X^2+X+1
393 for (int i = 0; i < 113; i++) {
394 int feedback = 0x1 & (data_in[i] ^ reg_bch);
395 reg_bch = reg_bch >> 1;
396 reg_bch |= feedback << 13;
397 reg_bch = reg_bch ^ (feedback << 12) ^ (feedback << 11) ^ (feedback << 9) ^
398 (feedback << 8) ^ (feedback << 7) ^ (feedback << 5) ^ (feedback << 4);
399 }
400
401 for (int i = 0; i < 14; i++) {
402 d_tps_data[i + 54] = 0x1 & (reg_bch >> i);
403 }
404 }
405
verify_bch_code(std::deque<char> data)406 int dvbt_pilot_gen::verify_bch_code(std::deque<char> data)
407 {
408 int ret = 0;
409
410 // TODO
411 // DO other way: if (feedback == 1) reg = reg ^ polymomial
412 // else nothing
413
414 //(n, k) = (127, 113) = (60+67, 60+53)
415 unsigned int reg_bch = 0;
416 unsigned char data_in[113];
417
418 // fill in 60 zeros
419 memset(&data_in[0], 0, 60);
420 // fill in TPS data - start bit not included
421 // memcpy(&data_in[60], &data[1], 53);
422 for (int i = 0; i < 53; i++) {
423 data_in[60 + i] = data[1 + i];
424 }
425
426 // X^14+X^9+X^8+X^6+X^5+X^4+X^2+X+1
427 for (int i = 0; i < 113; i++) {
428 int feedback = 0x1 & (data_in[i] ^ reg_bch);
429 reg_bch = reg_bch >> 1;
430 reg_bch |= feedback << 13;
431 reg_bch = reg_bch ^ (feedback << 12) ^ (feedback << 11) ^ (feedback << 9) ^
432 (feedback << 8) ^ (feedback << 7) ^ (feedback << 5) ^ (feedback << 4);
433 }
434
435 for (int i = 0; i < 14; i++) {
436 if ((unsigned int)data[i + 54] != (0x1 & (reg_bch >> i))) {
437 ret = -1;
438 break;
439 }
440 }
441
442 return ret;
443 }
444
set_symbol_index(int sindex)445 void dvbt_pilot_gen::set_symbol_index(int sindex) { d_symbol_index = sindex; }
446
get_symbol_index()447 int dvbt_pilot_gen::get_symbol_index() { return d_symbol_index; }
448
set_tps_data()449 void dvbt_pilot_gen::set_tps_data() {}
450
get_tps_data()451 void dvbt_pilot_gen::get_tps_data() {}
452
453 /*
454 * Reset pilot generator
455 */
reset_pilot_generator()456 void dvbt_pilot_gen::reset_pilot_generator()
457 {
458 d_spilot_index = 0;
459 d_cpilot_index = 0;
460 d_tpilot_index = 0;
461 d_payload_index = 0;
462 d_chanestim_index = 0;
463 d_symbol_index = 0;
464 d_frame_index = 0;
465 d_superframe_index = 0;
466 d_symbol_index_known = 0;
467 d_equalizer_ready = 0;
468 }
469
470 /*
471 * Init scattered pilot generator
472 */
get_current_spilot(int sindex) const473 int dvbt_pilot_gen::get_current_spilot(int sindex) const
474 {
475 // TODO - can be optimized for same symbol_index
476 return (d_Kmin + 3 * (sindex % 4) + 12 * d_spilot_index);
477 }
478
get_spilot_value(int spilot)479 gr_complex dvbt_pilot_gen::get_spilot_value(int spilot)
480 {
481 // TODO - can be calculated at the beginning
482 return gr_complex(4 * 2 * (0.5 - d_wk[spilot]) / 3, 0);
483 }
484
set_spilot_value(int spilot,gr_complex val)485 void dvbt_pilot_gen::set_spilot_value(int spilot, gr_complex val)
486 {
487 d_spilot_carriers_val[spilot] = val;
488 }
489
set_channel_gain(int spilot,gr_complex val)490 void dvbt_pilot_gen::set_channel_gain(int spilot, gr_complex val)
491 {
492 // Gain gval=rxval/txval
493 d_channel_gain[spilot] = gr_complex((4 * 2 * (0.5 - d_wk[spilot]) / 3), 0) / val;
494 }
advance_spilot(int sindex)495 void dvbt_pilot_gen::advance_spilot(int sindex)
496 {
497 // TODO - do in a simpler way?
498 int size = d_spilot_carriers_size;
499
500 if (sindex == 0) {
501 size = d_spilot_carriers_size + 1;
502 }
503
504 // TODO - fix this - what value should we use?
505 ++d_spilot_index;
506 d_spilot_index = d_spilot_index % size;
507 }
508
get_first_spilot()509 int dvbt_pilot_gen::get_first_spilot()
510 {
511 d_spilot_index = 0;
512
513 return (d_Kmin + 3 * (d_symbol_index % 4));
514 }
515
get_last_spilot() const516 int dvbt_pilot_gen::get_last_spilot() const
517 {
518 int size = d_spilot_carriers_size - 1;
519
520 if (d_symbol_index == 0) {
521 size = d_spilot_carriers_size;
522 }
523
524 return (d_Kmin + 3 * (d_symbol_index % 4) + 12 * size);
525 }
526
get_next_spilot()527 int dvbt_pilot_gen::get_next_spilot()
528 {
529 int pilot = (d_Kmin + 3 * (d_symbol_index % 4) + 12 * (++d_spilot_index));
530
531 if (pilot > d_Kmax) {
532 pilot = d_Kmax;
533 }
534
535 return pilot;
536 }
537
process_spilot_data(const gr_complex * in)538 int dvbt_pilot_gen::process_spilot_data(const gr_complex* in)
539 {
540 // This is channel estimator
541 // Interpolate the gain between carriers to obtain
542 // gain for non pilot carriers - we use linear interpolation
543
544 /*************************************************************/
545 // Find out the OFDM symbol index (value 0 to 3) sent
546 // in current block by correlating scattered symbols with
547 // current block - result is (symbol index % 4)
548 /*************************************************************/
549 float max = 0;
550 float sum = 0;
551
552 for (int scount = 0; scount < 4; scount++) {
553 d_spilot_index = 0;
554 d_cpilot_index = 0;
555 d_chanestim_index = 0;
556
557 for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) {
558 // Keep data for channel estimation
559 if (k == get_current_spilot(scount)) {
560 set_chanestim_carrier(k);
561 advance_spilot(scount);
562 advance_chanestim();
563 }
564 }
565
566 gr_complex c = gr_complex(0.0, 0.0);
567
568 // This should be of range 0 to d_chanestim_index bit for now we use just a
569 // small number of spilots to obtain the symbol index
570 for (int j = 0; j < 10; j++) {
571 c += get_spilot_value(d_chanestim_carriers[j]) *
572 conj(in[d_zeros_on_left + d_chanestim_carriers[j]]);
573 }
574 sum = norm(c);
575
576 if (sum > max) {
577 max = sum;
578 d_mod_symbol_index = scount;
579 }
580 }
581
582 /*************************************************************/
583 // Keep data for channel estimator
584 // This method interpolates scattered measurements across one OFDM symbol
585 // It does not use measurements from the previous OFDM symbols (does not use history)
586 // as it may have encountered a phase change for the current phase only
587 /*************************************************************/
588
589 d_spilot_index = 0;
590 d_cpilot_index = 0;
591 d_chanestim_index = 0;
592
593 for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) {
594 // Keep data for channel estimation
595 if (k == get_current_spilot(d_mod_symbol_index)) {
596 set_chanestim_carrier(k);
597 advance_spilot(d_mod_symbol_index);
598 advance_chanestim();
599 }
600
601 // Keep data for channel estimation
602 if (k == get_current_cpilot()) {
603 set_chanestim_carrier(k);
604 advance_cpilot();
605 advance_chanestim();
606 }
607 }
608
609 // We use both scattered pilots and continual pilots
610 for (int i = 0, startk = d_chanestim_carriers[0]; i < d_chanestim_index; i++) {
611 // Get a carrier from the list of carriers
612 // used for channel estimation
613 int k = d_chanestim_carriers[i];
614
615 set_channel_gain(k, in[k + d_zeros_on_left]);
616
617 // Calculate tg(alpha) due to linear interpolation
618 gr_complex tg_alpha =
619 (d_channel_gain[k] - d_channel_gain[startk]) / gr_complex(11.0, 0.0);
620
621 // Calculate interpolation for all intermediate values
622 for (int j = 1; j < (k - startk); j++) {
623 gr_complex current = d_channel_gain[startk] + tg_alpha * gr_complex(j, 0.0);
624 d_channel_gain[startk + j] = current;
625 }
626
627 startk = k;
628 }
629
630 // Signal that equalizer is ready
631 d_equalizer_ready = 1;
632
633 int diff_sindex = (d_mod_symbol_index - d_prev_mod_symbol_index + 4) % 4;
634
635 d_prev_mod_symbol_index = d_mod_symbol_index;
636
637 return diff_sindex;
638 }
639
640 /*
641 * Init continual pilot generator
642 */
get_current_cpilot() const643 int dvbt_pilot_gen::get_current_cpilot() const
644 {
645 return d_cpilot_carriers[d_cpilot_index];
646 }
647
get_cpilot_value(int cpilot)648 gr_complex dvbt_pilot_gen::get_cpilot_value(int cpilot)
649 {
650 // TODO - can be calculated at the beginning
651 return gr_complex((float)(4 * 2 * (0.5 - d_wk[cpilot])) / 3, 0);
652 }
653
advance_cpilot()654 void dvbt_pilot_gen::advance_cpilot()
655 {
656 ++d_cpilot_index;
657 d_cpilot_index = d_cpilot_index % d_cpilot_carriers_size;
658 }
659
process_cpilot_data(const gr_complex * in)660 void dvbt_pilot_gen::process_cpilot_data(const gr_complex* in)
661 {
662 // Look for maximum correlation for cpilots
663 // in order to obtain post FFT integer frequency correction
664
665 float max = 0;
666 float sum = 0;
667 int start = 0;
668 float phase;
669
670 for (int i = d_zeros_on_left - d_freq_offset_max;
671 i < d_zeros_on_left + d_freq_offset_max;
672 i++) {
673 sum = 0;
674 for (int j = 0; j < (d_cpilot_carriers_size - 1); j++) {
675 phase = norm(in[i + d_cpilot_carriers[j + 1]] - in[i + d_cpilot_carriers[j]]);
676 sum += d_known_phase_diff[j] * phase;
677 }
678
679 if (sum > max) {
680 max = sum;
681 start = i;
682 }
683 }
684
685 d_freq_offset = start - d_zeros_on_left;
686 }
687
compute_oneshot_csft(const gr_complex * in)688 void dvbt_pilot_gen::compute_oneshot_csft(const gr_complex* in)
689 {
690 gr_complex left_corr_sum = 0.0;
691 gr_complex right_corr_sum = 0.0;
692 int half_size = (d_cpilot_carriers_size - 1) / 2;
693
694 // TODO init this in constructor
695 float carrier_coeff =
696 1.0 / (2 * GR_M_PI * (1 + float(d_cp_length) / float(d_fft_length)) * 2);
697 float sampling_coeff = 1.0 / (2 * GR_M_PI *
698 ((1 + float(d_cp_length) / float(d_fft_length)) *
699 ((float)d_cpilot_carriers_size / 2.0)));
700
701 float left_angle, right_angle;
702
703 // Compute cpilots correlation between previous symbol and current symbol
704 // in both halves of the cpilots. The cpilots are distributed evenly
705 // on left and right sides of the center frequency.
706
707 for (int j = 0; j < half_size; j++) {
708 left_corr_sum += in[d_freq_offset + d_zeros_on_left + d_cpilot_carriers[j]] *
709 std::conj(in[d_freq_offset + d_fft_length + d_zeros_on_left +
710 d_cpilot_carriers[j]]);
711 }
712
713 for (int j = half_size + 1; j < d_cpilot_carriers_size; j++) {
714 right_corr_sum += in[d_freq_offset + d_zeros_on_left + d_cpilot_carriers[j]] *
715 std::conj(in[d_freq_offset + d_fft_length + d_zeros_on_left +
716 d_cpilot_carriers[j]]);
717 }
718
719 left_angle = std::arg(left_corr_sum);
720 right_angle = std::arg(right_corr_sum);
721
722 d_carrier_freq_correction = (right_angle + left_angle) * carrier_coeff;
723 d_sampling_freq_correction = (right_angle - left_angle) * sampling_coeff;
724 }
725
frequency_correction(const gr_complex * in,gr_complex * out)726 gr_complex* dvbt_pilot_gen::frequency_correction(const gr_complex* in, gr_complex* out)
727 {
728 // TODO - use PI control loop to calculate tracking corrections
729 int symbol_count = 1;
730
731 for (int k = 0; k < d_fft_length; k++) {
732 // TODO - for 2k mode the continuous pilots are not split evenly
733 // between left/right center frequency. Probably the scattered
734 // pilots needs to be added.
735
736 float correction = (float)d_freq_offset + d_carrier_freq_correction;
737
738 gr_complex c = gr_expj(-2 * GR_M_PI * correction * (d_fft_length + d_cp_length) /
739 d_fft_length * symbol_count);
740
741 // TODO - vectorize this operation
742 out[k] = c * in[k + d_freq_offset];
743 }
744
745 return (out);
746 }
747
748 /*
749 * Init tps sequence, return values for first position
750 * If first symbol then init tps DBPSK data
751 */
get_current_tpilot() const752 int dvbt_pilot_gen::get_current_tpilot() const { return d_tps_carriers[d_tpilot_index]; }
753
get_tpilot_value(int tpilot)754 gr_complex dvbt_pilot_gen::get_tpilot_value(int tpilot)
755 {
756 // TODO - it can be calculated at the beginnning
757 if (d_symbol_index == 0) {
758 d_tps_carriers_val[d_tpilot_index] = gr_complex(2 * (0.5 - d_wk[tpilot]), 0);
759 } else {
760 if (d_tps_data[d_symbol_index] == 1) {
761 d_tps_carriers_val[d_tpilot_index] =
762 gr_complex(-d_tps_carriers_val[d_tpilot_index].real(), 0);
763 }
764 }
765
766 return d_tps_carriers_val[d_tpilot_index];
767 }
768
advance_tpilot()769 void dvbt_pilot_gen::advance_tpilot()
770 {
771 ++d_tpilot_index;
772 d_tpilot_index = d_tpilot_index % d_tps_carriers_size;
773 }
774
775 /*
776 * Set a number of bits to a specified value
777 */
set_tps_bits(int start,int stop,unsigned int data)778 void dvbt_pilot_gen::set_tps_bits(int start, int stop, unsigned int data)
779 {
780 for (int i = start; i >= stop; i--) {
781 d_tps_data[i] = data & 0x1;
782 data = data >> 1;
783 }
784 }
785
786 /*
787 * Clause 4.6
788 * Format data that will be sent with TPS signals
789 * en 300 744 - section 4.6.2
790 * s0 Initialization
791 * s1-s16 Synchronization word
792 * s17-s22 Length Indicator
793 * s23-s24 Frame Number
794 * S25-s26 Constellation
795 * s27, s28, s29 Hierarchy information
796 * s30, s31, s32 Code rate, HP stream
797 * s33, s34, s35 Code rate, LP stream
798 * s36, s37 Guard interval
799 * s38, s39 Transmission mode
800 * s40, s47 Cell identifier
801 * s48-s53 All set to "0"
802 * s54-s67 Error protection (BCH code)
803 */
format_tps_data()804 void dvbt_pilot_gen::format_tps_data()
805 {
806 // Clause 4.6.3
807 set_tps_bits(0, 0, d_wk[0]);
808 // Clause 4.6.2.2
809 if (d_frame_index % 2) {
810 set_tps_bits(16, 1, 0xca11);
811 } else {
812 set_tps_bits(16, 1, 0x35ee);
813 }
814 // Clause 4.6.2.3
815 if (config.d_include_cell_id) {
816 set_tps_bits(22, 17, 0x1f);
817 } else {
818 set_tps_bits(22, 17, 0x17);
819 }
820 // Clause 4.6.2.4
821 set_tps_bits(24, 23, d_frame_index);
822 // Clause 4.6.2.5
823 set_tps_bits(26, 25, config.d_constellation);
824 // Clause 4.6.2.6
825 set_tps_bits(29, 27, config.d_hierarchy);
826 // Clause 4.6.2.7
827 switch (config.d_code_rate_HP) {
828 case C1_2:
829 set_tps_bits(32, 30, 0);
830 break;
831 case C2_3:
832 set_tps_bits(32, 30, 1);
833 break;
834 case C3_4:
835 set_tps_bits(32, 30, 2);
836 break;
837 case C5_6:
838 set_tps_bits(32, 30, 3);
839 break;
840 case C7_8:
841 set_tps_bits(32, 30, 4);
842 break;
843 default:
844 set_tps_bits(32, 30, 0);
845 break;
846 }
847 switch (config.d_code_rate_LP) {
848 case C1_2:
849 set_tps_bits(35, 33, 0);
850 break;
851 case C2_3:
852 set_tps_bits(35, 33, 1);
853 break;
854 case C3_4:
855 set_tps_bits(35, 33, 2);
856 break;
857 case C5_6:
858 set_tps_bits(35, 33, 3);
859 break;
860 case C7_8:
861 set_tps_bits(35, 33, 4);
862 break;
863 default:
864 set_tps_bits(35, 33, 0);
865 break;
866 }
867 // Clause 4.6.2.8
868 set_tps_bits(37, 36, config.d_guard_interval);
869 // Clause 4.6.2.9
870 set_tps_bits(39, 38, config.d_transmission_mode);
871 // Clause 4.6.2.10
872 if (d_frame_index % 2) {
873 set_tps_bits(47, 40, config.d_cell_id & 0xff);
874 } else {
875 set_tps_bits(47, 40, (config.d_cell_id >> 8) & 0xff);
876 }
877 // These bits are set to zero
878 set_tps_bits(53, 48, 0);
879 // Clause 4.6.2.11
880 generate_bch_code();
881 }
882
process_tps_data(const gr_complex * in,const int diff_symbol_index)883 int dvbt_pilot_gen::process_tps_data(const gr_complex* in, const int diff_symbol_index)
884 {
885 int end_frame = 0;
886
887 // Look for TPS data only - demodulate DBPSK
888 // Calculate phase difference between previous symbol
889 // and current one to determine the current bit.
890 // Use majority voting for decision
891 int tps_majority_zero = 0;
892
893 for (int k = 0; k < d_tps_carriers_size; k++) {
894 // Use equalizer to correct data and frequency correction
895 gr_complex val =
896 in[d_zeros_on_left + d_tps_carriers[k]] * d_channel_gain[d_tps_carriers[k]];
897
898 if (!d_symbol_index_known || (d_symbol_index != 0)) {
899 gr_complex phdiff = val * conj(d_prev_tps_symbol[k]);
900
901 if (phdiff.real() >= 0.0) {
902 tps_majority_zero++;
903 } else {
904 tps_majority_zero--;
905 }
906 }
907
908 d_prev_tps_symbol[k] = val;
909 }
910
911 // Insert obtained TPS bit into FIFO
912 // Insert the same bit into FIFO in the case
913 // diff_symbol_index is more than one. This will happen
914 // in the case of losing 1 to 3 symbols.
915 // This could be corrected by BCH decoder afterwards.
916
917 for (int i = 0; i < diff_symbol_index; i++) {
918 // Take out the front entry first
919 d_rcv_tps_data.pop_front();
920
921 // Add data at tail
922 if (!d_symbol_index_known || (d_symbol_index != 0)) {
923 if (tps_majority_zero >= 0) {
924 d_rcv_tps_data.push_back(0);
925 } else {
926 d_rcv_tps_data.push_back(1);
927 }
928 } else {
929 d_rcv_tps_data.push_back(0);
930 }
931 }
932
933 // Match synchronization signatures
934 if (std::equal(d_rcv_tps_data.begin() + 1,
935 d_rcv_tps_data.begin() + d_tps_sync_evenv.size(),
936 d_tps_sync_evenv.begin())) {
937 // Verify parity for TPS data
938 if (!verify_bch_code(d_rcv_tps_data)) {
939 d_frame_index = (d_rcv_tps_data[23] << 1) | (d_rcv_tps_data[24]);
940
941 d_symbol_index_known = 1;
942 end_frame = 1;
943 } else {
944 d_symbol_index_known = 0;
945 end_frame = 0;
946 }
947
948 // Clear up FIFO
949 for (int i = 0; i < d_symbols_per_frame; i++) {
950 d_rcv_tps_data[i] = 0;
951 }
952 } else if (std::equal(d_rcv_tps_data.begin() + 1,
953 d_rcv_tps_data.begin() + d_tps_sync_oddv.size(),
954 d_tps_sync_oddv.begin())) {
955 // Verify parity for TPS data
956 if (!verify_bch_code(d_rcv_tps_data)) {
957 d_frame_index = (d_rcv_tps_data[23] << 1) | (d_rcv_tps_data[24]);
958
959 d_symbol_index_known = 1;
960 end_frame = 1;
961 } else {
962 d_symbol_index_known = 0;
963 end_frame = 0;
964 }
965
966 // Clear up FIFO
967 for (int i = 0; i < d_symbols_per_frame; i++) {
968 d_rcv_tps_data[i] = 0;
969 }
970 }
971
972 return end_frame;
973 }
974
set_chanestim_carrier(int k)975 void dvbt_pilot_gen::set_chanestim_carrier(int k)
976 {
977 d_chanestim_carriers[d_chanestim_index] = k;
978 }
979
advance_chanestim()980 void dvbt_pilot_gen::advance_chanestim() { d_chanestim_index++; }
981
get_current_payload()982 int dvbt_pilot_gen::get_current_payload() { return d_payload_carriers[d_payload_index]; }
983
set_payload_carrier(int k)984 void dvbt_pilot_gen::set_payload_carrier(int k)
985 {
986 d_payload_carriers[d_payload_index] = k;
987 }
988
advance_payload()989 void dvbt_pilot_gen::advance_payload() { d_payload_index++; }
990
process_payload_data(const gr_complex * in,gr_complex * out)991 void dvbt_pilot_gen::process_payload_data(const gr_complex* in, gr_complex* out)
992 {
993 // reset indexes
994 d_spilot_index = 0;
995 d_cpilot_index = 0;
996 d_tpilot_index = 0;
997 d_payload_index = 0;
998 d_chanestim_index = 0;
999 int is_payload = 1;
1000
1001 // process one block - one symbol
1002 for (int k = 0; k < (d_Kmax - d_Kmin + 1); k++) {
1003 is_payload = 1;
1004
1005 // Keep data for channel estimation
1006 // This depends on the symbol index
1007 if (k == get_current_spilot(d_mod_symbol_index)) {
1008 advance_spilot(d_mod_symbol_index);
1009 is_payload = 0;
1010 }
1011
1012 // Keep data for frequency correction
1013 // and channel estimation
1014 if (k == get_current_cpilot()) {
1015 advance_cpilot();
1016 is_payload = 0;
1017 }
1018
1019 if (k == get_current_tpilot()) {
1020 advance_tpilot();
1021 is_payload = 0;
1022 }
1023
1024 // Keep payload carrier number
1025 // This depends on the symbol index
1026 if (is_payload) {
1027 set_payload_carrier(k);
1028 advance_payload();
1029 }
1030 }
1031
1032 if (d_equalizer_ready) {
1033 // Equalize payload data according to channel estimator
1034 for (int i = 0; i < d_payload_index; i++) {
1035 out[i] = in[d_zeros_on_left + d_payload_carriers[i]] *
1036 d_channel_gain[d_payload_carriers[i]];
1037 }
1038 } else {
1039 // If equ not ready, return 0
1040 for (int i = 0; i < d_payload_length; i++) {
1041 out[0] = gr_complex(0.0, 0.0);
1042 }
1043 }
1044 }
1045
update_output(const gr_complex * in,gr_complex * out)1046 void dvbt_pilot_gen::update_output(const gr_complex* in, gr_complex* out)
1047 {
1048 int is_payload = 1;
1049 int payload_count = 0;
1050
1051 // move to the next symbol
1052 // re-genereate TPS data
1053 format_tps_data();
1054
1055 // reset indexes
1056 payload_count = 0;
1057 d_spilot_index = 0;
1058 d_cpilot_index = 0;
1059 d_tpilot_index = 0;
1060
1061 for (int i = 0; i < d_zeros_on_left; i++) {
1062 out[i] = gr_complex(0.0, 0.0);
1063 }
1064
1065 // process one block - one symbol
1066 for (int k = d_Kmin; k < (d_Kmax - d_Kmin + 1); k++) {
1067 is_payload = 1;
1068 if (k == get_current_spilot(d_symbol_index)) {
1069 out[d_zeros_on_left + k] = get_spilot_value(k);
1070 advance_spilot(d_symbol_index);
1071 is_payload = 0;
1072 }
1073
1074 if (k == get_current_cpilot()) {
1075 out[d_zeros_on_left + k] = get_cpilot_value(k);
1076 advance_cpilot();
1077 is_payload = 0;
1078 }
1079
1080 if (k == get_current_tpilot()) {
1081 out[d_zeros_on_left + k] = get_tpilot_value(k);
1082 advance_tpilot();
1083 is_payload = 0;
1084 }
1085
1086 if (is_payload == 1) {
1087 out[d_zeros_on_left + k] = in[payload_count++];
1088 }
1089 }
1090
1091 // update indexes
1092 if (++d_symbol_index == d_symbols_per_frame) {
1093 d_symbol_index = 0;
1094 if (++d_frame_index == d_frames_per_superframe) {
1095 d_frame_index = 0;
1096 d_superframe_index++;
1097 }
1098 }
1099
1100 for (int i = (d_fft_length - d_zeros_on_right); i < d_fft_length; i++) {
1101 out[i] = gr_complex(0.0, 0.0);
1102 }
1103 }
1104
parse_input(const gr_complex * in,gr_complex * out,int * symbol_index,int * frame_index)1105 int dvbt_pilot_gen::parse_input(const gr_complex* in,
1106 gr_complex* out,
1107 int* symbol_index,
1108 int* frame_index)
1109 {
1110 d_trigger_index++;
1111
1112 // Obtain frequency correction based on cpilots.
1113 // Obtain channel estimation based on both
1114 // cpilots and spilots.
1115 // We use spilot correlation for finding the symbol index modulo 4
1116 // The diff between previous sym index and current index is used
1117 // to advance the symbol index inside a frame (0 to 67)
1118 // Then based on the TPS data we find out the start of a frame
1119
1120 // Process cpilot data
1121 // This is post FFT integer frequency offset estimation
1122 // This is called before all other processing
1123 process_cpilot_data(in);
1124
1125 // Compute one shot Post-FFT Carrier and Sampling Frequency Tracking
1126 // Obtain fractional Carrer and Sampling frequency corrections
1127 // Before this moment it is assumed to have corrected this:
1128 // - symbol timing (pre-FFT)
1129 // - symbol frequency correction (pre-FFT)
1130 // - integer frequency correction (post-FFT)
1131 // TODO - call this just in the acquisition mode
1132 compute_oneshot_csft(in);
1133
1134 // Gather all corrections and obtain a corrected OFDM symbol:
1135 // - input symbol shift (post-FFT)
1136 // - integer frequency correction (post-FFT)
1137 // - fractional frequency (carrier and sampling) corrections (post-FFT)
1138 // TODO - use PI to update the corrections
1139 frequency_correction(in, d_derot_in);
1140
1141 // Process spilot data
1142 // This is channel estimation function
1143 int diff_symbol_index = process_spilot_data(d_derot_in);
1144
1145 // Correct symbol index so that all subsequent processing
1146 // use correct symbol index
1147 d_symbol_index = (d_symbol_index + diff_symbol_index) % d_symbols_per_frame;
1148
1149 // Symbol index is used in other modules too
1150 *symbol_index = d_symbol_index;
1151 // Frame index is used in other modules too
1152 *frame_index = d_frame_index;
1153
1154 // Process TPS data
1155 // If a frame is recognized then signal end of frame
1156 int frame_end = process_tps_data(d_derot_in, diff_symbol_index);
1157
1158 // We are just at the end of a frame
1159 if (frame_end) {
1160 d_symbol_index = d_symbols_per_frame - 1;
1161 }
1162
1163 // Process payload data with correct symbol index
1164 process_payload_data(d_derot_in, out);
1165
1166 // noutput_items should be 1 in this case
1167 return 1;
1168 }
1169
1170 dvbt_reference_signals::sptr
make(int itemsize,int ninput,int noutput,dvb_constellation_t constellation,dvbt_hierarchy_t hierarchy,dvb_code_rate_t code_rate_HP,dvb_code_rate_t code_rate_LP,dvb_guardinterval_t guard_interval,dvbt_transmission_mode_t transmission_mode,int include_cell_id,int cell_id)1171 dvbt_reference_signals::make(int itemsize,
1172 int ninput,
1173 int noutput,
1174 dvb_constellation_t constellation,
1175 dvbt_hierarchy_t hierarchy,
1176 dvb_code_rate_t code_rate_HP,
1177 dvb_code_rate_t code_rate_LP,
1178 dvb_guardinterval_t guard_interval,
1179 dvbt_transmission_mode_t transmission_mode,
1180 int include_cell_id,
1181 int cell_id)
1182 {
1183 return gnuradio::get_initial_sptr(new dvbt_reference_signals_impl(itemsize,
1184 ninput,
1185 noutput,
1186 constellation,
1187 hierarchy,
1188 code_rate_HP,
1189 code_rate_LP,
1190 guard_interval,
1191 transmission_mode,
1192 include_cell_id,
1193 cell_id));
1194 }
1195
1196 /*
1197 * The private constructor
1198 */
dvbt_reference_signals_impl(int itemsize,int ninput,int noutput,dvb_constellation_t constellation,dvbt_hierarchy_t hierarchy,dvb_code_rate_t code_rate_HP,dvb_code_rate_t code_rate_LP,dvb_guardinterval_t guard_interval,dvbt_transmission_mode_t transmission_mode,int include_cell_id,int cell_id)1199 dvbt_reference_signals_impl::dvbt_reference_signals_impl(
1200 int itemsize,
1201 int ninput,
1202 int noutput,
1203 dvb_constellation_t constellation,
1204 dvbt_hierarchy_t hierarchy,
1205 dvb_code_rate_t code_rate_HP,
1206 dvb_code_rate_t code_rate_LP,
1207 dvb_guardinterval_t guard_interval,
1208 dvbt_transmission_mode_t transmission_mode,
1209 int include_cell_id,
1210 int cell_id)
1211 : block("dvbt_reference_signals",
1212 io_signature::make(1, 1, itemsize * ninput),
1213 io_signature::make(1, 1, itemsize * noutput)),
1214 config(constellation,
1215 hierarchy,
1216 code_rate_HP,
1217 code_rate_LP,
1218 guard_interval,
1219 transmission_mode,
1220 include_cell_id,
1221 cell_id),
1222 d_pg(config)
1223 {
1224 d_ninput = ninput;
1225 d_noutput = noutput;
1226 }
1227
1228 /*
1229 * Our virtual destructor.
1230 */
~dvbt_reference_signals_impl()1231 dvbt_reference_signals_impl::~dvbt_reference_signals_impl() {}
1232
forecast(int noutput_items,gr_vector_int & ninput_items_required)1233 void dvbt_reference_signals_impl::forecast(int noutput_items,
1234 gr_vector_int& ninput_items_required)
1235 {
1236 ninput_items_required[0] = noutput_items;
1237 }
1238
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)1239 int dvbt_reference_signals_impl::general_work(int noutput_items,
1240 gr_vector_int& ninput_items,
1241 gr_vector_const_void_star& input_items,
1242 gr_vector_void_star& output_items)
1243 {
1244 const gr_complex* in = (const gr_complex*)input_items[0];
1245 gr_complex* out = (gr_complex*)output_items[0];
1246
1247 for (int i = 0; i < noutput_items; i++) {
1248 d_pg.update_output(&in[i * d_ninput], &out[i * d_noutput]);
1249 }
1250
1251 // Tell runtime system how many input items we consumed on
1252 // each input stream.
1253 consume_each(noutput_items);
1254
1255 // Tell runtime system how many output items we produced.
1256 return noutput_items;
1257 }
1258
1259 } /* namespace dtv */
1260 } /* namespace gr */
1261