IT++ Logo
turbo.cpp
Go to the documentation of this file.
1
29#include <itpp/comm/turbo.h>
30
31
32namespace itpp
33{
34// -------------------------------------------------------------------------------------
35// Turbo Codec
36// -------------------------------------------------------------------------------------
37std::string Turbo_Codec::string_from_metric(const Turbo_Codec::Metric& in_metric)
38{
39 if(in_metric == Metric::LOGMAX) {
40 return std::string("LOGMAX");
41 }
42 else if(in_metric == Metric::LOGMAP) {
43 return std::string("LOGMAP");
44 }
45 else if(in_metric == Metric::MAP) {
46 return std::string("MAP");
47 }
48 else if(in_metric == Metric::TABLE) {
49 return std::string("TABLE");
50 }
51 else {
52 return std::string("UNKNOWN");
53 }
54}
55void Turbo_Codec::set_parameters(ivec gen1, ivec gen2, int constraint_length, const ivec &interleaver_sequence,
56 int in_iterations, const std::string &in_metric, double in_logmax_scale_factor,
58{
59 //Set the input parameters:
60 iterations = in_iterations;
61 interleaver_size = interleaver_sequence.size();
62 Nuncoded = interleaver_size;
63 logmax_scale_factor = in_logmax_scale_factor;
64 adaptive_stop = in_adaptive_stop;
65
66 //Check the decoding metric
67 if(in_metric == "LOGMAX") {
68 metric = Metric::LOGMAX;
69 }
70 else if(in_metric == "LOGMAP") {
71 metric = Metric::LOGMAP;
72 }
73 else if(in_metric == "MAP") {
74 metric = Metric::MAP;
75 }
76 else if(in_metric == "TABLE") {
77 metric = Metric::TABLE;
78 }
79 else {
80 it_error("Turbo_Codec::set_parameters: The decoder metric must be either MAP, LOGMAP, LOGMAX or TABLE");
81 }
82
83 if(logmax_scale_factor != 1.0) {
84 it_assert(metric == Metric::LOGMAX, "Turbo_Codec::set_parameters: logmax_scale_factor can only be used together with LOGMAX decoding");
85 }
86
87 //The RSC Encoders:
90 n1 = gen1.length() - 1; //Number of parity bits from rscc1
91 n2 = gen2.length() - 1; //Number of parity bits from rscc2
92 n_tot = 1 + n1 + n2; //Total number of parity bits and systematic bits
93
94 //Set the number of tail bits:
95 m_tail = constraint_length - 1;
96
97 //Calculate the number of coded bits per code-block:
98 Ncoded = Nuncoded * n_tot + m_tail * (1 + n1) + m_tail * (1 + n2);
99
100 //Set the interleaver sequence
101 bit_interleaver.set_interleaver_depth(interleaver_size);
102 float_interleaver.set_interleaver_depth(interleaver_size);
103 bit_interleaver.set_interleaver_sequence(interleaver_sequence);
104 float_interleaver.set_interleaver_sequence(interleaver_sequence);
105
106 //Default value of the channel reliability scaling factor is 1
107 Lc = 1.0;
108
109 // LLR algebra table
110 rscc1.set_llrcalc(in_llrcalc);
111 rscc2.set_llrcalc(in_llrcalc);
112
113}
114
115void Turbo_Codec::set_interleaver(const ivec &interleaver_sequence)
116{
117 interleaver_size = interleaver_sequence.size();
118 Nuncoded = interleaver_size;
119
120 //Calculate the number of coded bits per code-block:
121 Ncoded = Nuncoded * n_tot + m_tail * (1 + n1) + m_tail * (1 + n2);
122
123 //Set the interleaver sequence
124 bit_interleaver.set_interleaver_depth(interleaver_size);
125 float_interleaver.set_interleaver_depth(interleaver_size);
126 bit_interleaver.set_interleaver_sequence(interleaver_sequence);
127 float_interleaver.set_interleaver_sequence(interleaver_sequence);
128}
129
131{
132 logmax_scale_factor = in_logmax_scale_factor;
133
134 //Check the decoding metric
135 if(in_metric == "LOGMAX") {
136 metric = Metric::LOGMAX;
137 }
138 else if(in_metric == "LOGMAP") {
139 metric = Metric::LOGMAP;
140 }
141 else if(in_metric == "MAP") {
142 metric = Metric::MAP;
143 }
144 else if(in_metric == "TABLE") {
145 metric = Metric::TABLE;
146 }
147 else {
148 it_error("Turbo_Codec::set_metric: The decoder metric must be either MAP, LOGMAP, LOGMAX or TABLE");
149 }
150
151 rscc1.set_llrcalc(in_llrcalc);
152 rscc2.set_llrcalc(in_llrcalc);
153}
154
156{
157 iterations = in_iterations;
158}
159
161{
162 adaptive_stop = in_adaptive_stop;
163}
164
166{
167 Ec = in_Ec;
168 N0 = in_N0;
169 Lc = 4.0 * std::sqrt(Ec) / N0;
170}
171
173{
174 Lc = in_Lc;
175}
176
177
178void Turbo_Codec::encode(const bvec &input, bvec &output)
179{
180 //Local variables:
181 int i, k, j, no_blocks;
182 int count;
183 bvec input_bits, in1, in2, tail1, tail2, out;
185
186 //Initializations:
187 no_blocks = input.length() / Nuncoded;
188 output.set_size(no_blocks * Ncoded, false);
189
190 //Set the bit counter to zero:
191 count = 0;
192
193 //Encode all code blocks:
194 for(i = 0; i < no_blocks; i++) {
195
196 //Encode one block
197 input_bits = input.mid(i * Nuncoded, Nuncoded);
199
200 //The data part:
201 for(k = 0; k < Nuncoded; k++) {
202 output(count) = in1(k);
203 count++; //Systematic bits
204 for(j = 0; j < n1; j++) { output(count) = parity1(k, j); count++; } //Parity-1 bits
205 for(j = 0; j < n2; j++) { output(count) = parity2(k, j); count++; } //Parity-2 bits
206 }
207
208 //The first tail:
209 for(k = 0; k < m_tail; k++) {
210 output(count) = in1(Nuncoded + k);
211 count++; //First systematic tail bit
212 for(j = 0; j < n1; j++) { output(count) = parity1(Nuncoded + k, j); count++; } //Parity-1 tail bits
213 }
214
215 //The second tail:
216 for(k = 0; k < m_tail; k++) {
217 output(count) = in2(Nuncoded + k);
218 count++; //Second systematic tail bit
219 for(j = 0; j < n2; j++) { output(count) = parity2(Nuncoded + k, j); count++; } //Parity-2 tail bits
220 }
221
222 }
223
224}
225
231
233 const bvec &true_bits)
234{
235
236 if((n1 == 1) && (n2 == 1) && (metric != Metric::MAP)) {
237 //This is a speed optimized decoder for R=1/3 (log domain metrics only)
239 }
240 else {
241
242 //Local variables:
243 vec rec, rec_syst1, rec_syst2;
247 int count;
248 bool CHECK_TRUE_BITS;
249
250 //Initilaizations:
251 no_blocks = received_signal.length() / Ncoded;
252 decoded_bits.set_size(no_blocks * Nuncoded, false);
253 decoded_bits_i.set_size(iterations, no_blocks * Nuncoded, false);
254 rec_syst1.set_size(Nuncoded + m_tail, false);
255 rec_syst2.set_size(Nuncoded + m_tail, false);
256 rec_syst2.clear();
257 rec_parity1.set_size(Nuncoded + m_tail, n1, false);
258 rec_parity2.set_size(Nuncoded + m_tail, n2, false);
260
261 //Check the vector true_bits:
262 if(true_bits.size() > 1) {
263 it_assert(true_bits.size() == (Nuncoded * no_blocks), "Turbo_Codec::decode: Wrong size of input vectors");
264 CHECK_TRUE_BITS = true;
265 }
266 else {
267 CHECK_TRUE_BITS = false;
268 }
269
270 //Set the bit counter to zero:
271 count = 0;
272
273 //Itterate over all received code blocks:
274 for(i = 0; i < no_blocks; i++) {
275
276 //The data part:
277 for(k = 0; k < Nuncoded; k++) {
278 rec_syst1(k) = received_signal(count);
279 count++; //Systematic bit
280 for(j = 0; j < n1; j++) { rec_parity1(k, j) = received_signal(count); count++; } //Parity-1 bits
281 for(j = 0; j < n2; j++) { rec_parity2(k, j) = received_signal(count); count++; } //Parity-2 bits
282 }
283
284 //The first tail:
285 for(k = 0; k < m_tail; k++) {
286 rec_syst1(Nuncoded + k) = received_signal(count);
287 count++; //Tail 1 systematic bit
288 for(j = 0; j < n1; j++) { rec_parity1(Nuncoded + k, j) = received_signal(count); count++; } //Tail 1 parity-1 bits
289 }
290
291 //The second tail:
292 for(k = 0; k < m_tail; k++) {
293 rec_syst2(Nuncoded + k) = received_signal(count);
294 count++; //Tail2 systematic bit
295 for(j = 0; j < n2; j++) { rec_parity2(Nuncoded + k, j) = received_signal(count); count++; } //Tali2 parity-2 bits
296 }
297
298 //Scale the input data if necessary:
299 if(Lc != 1.0) {
300 rec_syst1 *= Lc;
301 rec_syst2 *= Lc;
302 rec_parity1 *= Lc;
303 rec_parity2 *= Lc;
304 }
305
306 //Decode the block:
307 if(CHECK_TRUE_BITS) {
309 nrof_used_iterations_i, true_bits.mid(i * Nuncoded, Nuncoded));
311 }
312 else {
315 }
316
317 //Put the decoded bits in the output vector:
318 decoded_bits.replace_mid(i * Nuncoded, decoded_bits_i.get_row(iterations - 1));
319
320 }
321
322 }
323
324}
325
326void Turbo_Codec::encode_block(const bvec &input, bvec &in1, bvec &in2, bmat &parity1, bmat &parity2)
327{
328 //Local variables:
330
331 //Error check:
332 it_assert(input.length() == Nuncoded, "Turbo_Codec::encode_block: Parameter error in Nuncoded.");
333
334 //Initializations:
335 tail1.set_size(m_tail, false);
336 tail1.clear();
337 tail2.set_size(m_tail, false);
338 tail2.clear();
339 parity1.set_size(Nuncoded + m_tail, n1, false);
340 parity1.clear();
341 parity2.set_size(Nuncoded + m_tail, n2, false);
342 parity2.clear();
343 interleaved_input.set_size(Nuncoded, false);
344 interleaved_input.clear();
345
346 //The first encoder:
347 rscc1.encode_tail(input, tail1, parity1);
348
349 //The interleaver:
350 bit_interleaver.interleave(input, interleaved_input);
351
352 //The second encoder:
354
355 //The input vectors used to the two constituent encoders:
356 in1 = concat(input, tail1);
358
359}
360
361void Turbo_Codec::decode_block(const vec &rec_syst1, const vec &rec_syst2, const mat &rec_parity1,
363 const bvec &true_bits)
364{
365 //Local variables:
366 int i;
367 int count, l, k;
371
372 //Size initializations:
373 decoded_bits_i.set_size(iterations, Nuncoded, false);
374 Le12.set_size(Nuncoded + m_tail, false);
375 Le21.set_size(Nuncoded + m_tail, false);
376 Le21.zeros();
377
378 //Calculate the interleaved and the deinterleaved sequences:
379 float_interleaver.interleave(rec_syst1.left(interleaver_size), int_rec_syst1);
380 float_interleaver.deinterleave(rec_syst2.left(interleaver_size), deint_rec_syst2);
381
382 //Combine the results from rec_syst1 and rec_syst2 (in case some bits are transmitted several times)
383 rec_syst = rec_syst1.left(interleaver_size) + deint_rec_syst2;
384 int_rec_syst = rec_syst2.left(interleaver_size) + int_rec_syst1;
385
386 //Get the two tails
387 tail1 = rec_syst1.right(m_tail);
388 tail2 = rec_syst2.right(m_tail);
389
390 //Form the input vectors (including tails) to the two decoders:
393
394 // Check the vector true_bits
395 if(true_bits.size() > 1) {
396 it_assert(true_bits.size() == Nuncoded, "Turbo_Codec::decode_block: Illegal size of input vector true_bits");
397 CHECK_TRUE_BITS = true;
398 }
399 else {
400 CHECK_TRUE_BITS = false;
401 }
402
403 if(CHECK_TRUE_BITS) {
404 it_assert(adaptive_stop == false,
405 "Turbo_Codec::decode_block: You can not stop iterations both adaptively and on true bits");
406 }
407
408 // Do the iterative decoding:
409 nrof_used_iterations_i = iterations;
410 for(i = 0; i < iterations; i++) {
411
412 // Decode Code 1
413 if(metric == Metric::MAP) {
414 rscc1.map_decode(rec_syst, rec_parity1, Le21, Le12, true);
415 }
416 else if((metric == Metric::LOGMAX) || (metric == Metric::LOGMAP) || (metric == Metric::TABLE)) {
417 rscc1.log_decode(rec_syst, rec_parity1, Le21, Le12, true, string_from_metric(metric));
418 if(logmax_scale_factor != 1.0) {
419 Le12 *= logmax_scale_factor;
420 }
421 }
422 else {
423 it_error("Turbo_Codec::decode_block: Illegal metric value");
424 }
425
426 // Interleave the extrinsic information:
427 float_interleaver.interleave(Le12.left(interleaver_size), tmp);
428 Le12_int = concat(tmp, zeros(Le12.size() - interleaver_size));
429
430 // Decode Code 2
431 if(metric == Metric::MAP) {
433 }
434 else if((metric == Metric::LOGMAX) || (metric == Metric::LOGMAP) || (metric == Metric::TABLE)) {
435 rscc2.log_decode(int_rec_syst, rec_parity2, Le12_int, Le21_int, true, string_from_metric(metric));
436 if(logmax_scale_factor != 1.0) {
437 Le21_int *= logmax_scale_factor;
438 }
439 }
440 else {
441 it_error("Turbo_Codec::decode_block: Illegal metric value");
442 }
443
444 // De-interleave the extrinsic information:
445 float_interleaver.deinterleave(Le21_int.left(interleaver_size), tmp);
446 Le21 = concat(tmp, zeros(Le21_int.size() - interleaver_size));
447
448 // Take bit decisions
449 L = rec_syst + Le21 + Le12;
450 count = 0;
451 for(l = 0; l < Nuncoded; l++) {
452 (L(l) > 0.0) ? (decoded_bits_i(i, count) = bin(0)) : (decoded_bits_i(i, count) = bin(1));
453 count++;
454 }
455
456 //Check if it is possible to stop iterating early:
457 CONTINUE = true;
458 if(i < (iterations - 1)) {
459
460 if(CHECK_TRUE_BITS) {
461 CONTINUE = false;
462 for(k = 0; k < Nuncoded; k++) { if(true_bits(k) != decoded_bits_i(i, k)) { CONTINUE = true; break; } }
463 }
464
465 if((adaptive_stop) && (i > 0)) {
466 CONTINUE = false;
467 for(k = 0; k < Nuncoded; k++) { if(decoded_bits_i(i - 1, k) != decoded_bits_i(i, k)) { CONTINUE = true; break; } }
468 }
469
470 }
471
472 //Check if iterations shall continue:
473 if(CONTINUE == false) {
474 //Copy the results from current iteration to all following iterations:
475 for(k = (i + 1); k < iterations; k++) {
476 decoded_bits_i.set_row(k, decoded_bits_i.get_row(i));
478 }
479 break;
480 }
481
482 }
483
484}
485
487 const bvec &true_bits)
488{
489 //Local variables:
494 int no_blocks, i, j, k, l, nrof_used_iterations_i;
495 int count, count_out;
497
498 //Initializations:
499 no_blocks = received_signal.length() / Ncoded;
500 decoded_bits.set_size(no_blocks * Nuncoded, false);
501 rec_syst1.set_size(Nuncoded + m_tail, false);
502 rec_syst2.set_size(Nuncoded + m_tail, false);
503 rec_syst2.clear();
504 rec_parity1.set_size(Nuncoded + m_tail, false);
505 rec_parity2.set_size(Nuncoded + m_tail, false);
506 temp_decoded_bits.set_size(Nuncoded, false);
507 decoded_bits_previous_iteration.set_size(Nuncoded, false);
509
510 //Size initializations:
511 Le12.set_size(Nuncoded, false);
512 Le21.set_size(Nuncoded, false);
513
514 //Set the bit counter to zero:
515 count = 0;
516 count_out = 0;
517
518 // Check the vector true_bits
519 if(true_bits.size() > 1) {
520 it_assert(true_bits.size() == Nuncoded * no_blocks, "Turbo_Codec::decode_n3: Illegal size of input vector true_bits");
521 CHECK_TRUE_BITS = true;
522 }
523 else {
524 CHECK_TRUE_BITS = false;
525 }
526
527 if(CHECK_TRUE_BITS) {
528 it_assert(adaptive_stop == false,
529 "Turbo_Codec::decode_block: You can not stop iterations both adaptively and on true bits");
530 }
531
532 //Iterate over all received code blocks:
533 for(i = 0; i < no_blocks; i++) {
534
535 //Reset extrinsic data:
536 Le21.zeros();
537
538 //The data part:
539 for(k = 0; k < Nuncoded; k++) {
540 rec_syst1(k) = received_signal(count);
541 count++; //Systematic bit
542 rec_parity1(k) = received_signal(count);
543 count++; //Parity-1 bits
544 rec_parity2(k) = received_signal(count);
545 count++; //Parity-2 bits
546 }
547
548 //The first tail:
549 for(k = 0; k < m_tail; k++) {
550 rec_syst1(Nuncoded + k) = received_signal(count);
551 count++; //Tail 1 systematic bit
552 rec_parity1(Nuncoded + k) = received_signal(count);
553 count++; //Tail 1 parity-1 bits
554 }
555
556 //The second tail:
557 for(k = 0; k < m_tail; k++) {
558 rec_syst2(Nuncoded + k) = received_signal(count);
559 count++; //Tail2 systematic bit
560 rec_parity2(Nuncoded + k) = received_signal(count);
561 count++; //Tali2 parity-2 bits
562 }
563
564 float_interleaver.interleave(rec_syst1.left(Nuncoded), int_rec_syst1);
565 rec_syst2.replace_mid(0, int_rec_syst1);
566
567 //Scale the input data if necessary:
568 if(Lc != 1.0) {
569 rec_syst1 *= Lc;
570 rec_syst2 *= Lc;
571 rec_parity1 *= Lc;
572 rec_parity2 *= Lc;
573 }
574
575 //Decode the block:
576 CONTINUE = true;
577 nrof_used_iterations_i = iterations;
578 for(j = 0; j < iterations; j++) {
579
580 rscc1.log_decode_n2(rec_syst1, rec_parity1, Le21, Le12, true, string_from_metric(metric));
581 if(logmax_scale_factor != 1.0) { Le12 *= logmax_scale_factor; }
582 float_interleaver.interleave(Le12, Le12_int);
583
584 rscc2.log_decode_n2(rec_syst2, rec_parity2, Le12_int, Le21_int, true, string_from_metric(metric));
585 if(logmax_scale_factor != 1.0) { Le21_int *= logmax_scale_factor; }
586 float_interleaver.deinterleave(Le21_int, Le21);
587
588 if(adaptive_stop) {
589 L = rec_syst1.left(Nuncoded) + Le21.left(Nuncoded) + Le12.left(Nuncoded);
590 for(l = 0; l < Nuncoded; l++) {(L(l) > 0.0) ? (temp_decoded_bits(l) = bin(0)) : (temp_decoded_bits(l) = bin(1)); }
591 if(j == 0) { decoded_bits_previous_iteration = temp_decoded_bits; }
592 else {
593 if(temp_decoded_bits == decoded_bits_previous_iteration) {
594 CONTINUE = false;
595 }
596 else if(j < (iterations - 1)) {
597 decoded_bits_previous_iteration = temp_decoded_bits;
598 }
599 }
600 }
601
602 if(CHECK_TRUE_BITS) {
603 L = rec_syst1.left(Nuncoded) + Le21.left(Nuncoded) + Le12.left(Nuncoded);
604 for(l = 0; l < Nuncoded; l++) {(L(l) > 0.0) ? (temp_decoded_bits(l) = bin(0)) : (temp_decoded_bits(l) = bin(1)); }
605 if(temp_decoded_bits == true_bits.mid(i * Nuncoded, Nuncoded)) {
606 CONTINUE = false;
607 }
608 }
609
610 if(CONTINUE == false) { nrof_used_iterations_i = j + 1; break; }
611
612 }
613
614 //Take final bit decisions
615 L = rec_syst1.left(Nuncoded) + Le21.left(Nuncoded) + Le12.left(Nuncoded);
616 for(l = 0; l < Nuncoded; l++) {
617 (L(l) > 0.0) ? (decoded_bits(count_out) = bin(0)) : (decoded_bits(count_out) = bin(1));
618 count_out++;
619 }
620
622
623 }
624
625}
626
627// -------------------------------------------------------------------------------------
628// Punctured Turbo Codec
629// -------------------------------------------------------------------------------------
630
636
638{
639 int p, j;
640
641 punct_total = 0;
642 punct_total2 = 0;
643
644 it_error_if(pmatrix.rows() != n_tot || pmatrix.cols() == 0, "Wrong size of puncture matrix");
645 puncture_matrix = pmatrix;
646 Period = puncture_matrix.cols();
647
648 // all rows
649 for(j = 0; j < n_tot; j++) {
650 for(p = 0; p < Period; p++)
651 punct_total += static_cast<int>(puncture_matrix(j, p));
652 }
653 // systematic bits
654 for(p = 0; p < Period; p++)
655 punct_total2 += static_cast<int>(puncture_matrix(0, p));
656 punct_total1 = punct_total2;
657 // 1st code parity bits
658 for(j = 1; j < n1 + 1; j++) {
659 for(p = 0; p < Period; p++)
660 punct_total1 += static_cast<int>(puncture_matrix(j, p));
661 }
662 // 2nd code parity bits
663 for(j = 1 + n1; j < n_tot; j++) {
664 for(p = 0; p < Period; p++)
665 punct_total2 += static_cast<int>(puncture_matrix(j, p));
666 }
667
668 // nominal rate
669 rate = Period / static_cast<double>(punct_total);
671}
672
673
675{
676 if(nominal) return rate;
677 else {
678 if(Period == 0)
679 return static_cast<double>(Nuncoded) / Ncoded;
680 else
681 return static_cast<double>(Nuncoded) / pNcoded;
682 }
683}
684
685
686bvec Punctured_Turbo_Codec::encode(const bvec &input)
687{
688 bvec coded_bits;
689
690 encode(input, coded_bits);
691 return coded_bits;
692}
693
701
702void Punctured_Turbo_Codec::encode(const bvec &input, bvec &output)
703{
704 it_assert(Period != 0, "Punctured_Turbo_Codec: puncture matrix is not set");
705
706 Turbo_Codec::encode(input, output);
707
708 int i, k, p, j, p1;
709 int no_blocks = output.size() / Ncoded;
710 int count = 0, count_p = 0;
711
712 for(k = 0; k < no_blocks; k++) {
713 p = 0;
714 // data
715 for(i = 0; i < Nuncoded; i++) {
716 for(j = 0; j < n_tot; j++) {
717 if(puncture_matrix(j, p) == bin(1)) {
718 output(count_p) = output(count);
719 count_p++;
720 }
721 count++;
722 }
723 p = (p + 1) % Period;
724 }
725 p1 = p;
726
727 //The first tail:
728 for(i = 0; i < m_tail; i++) {
729 for(j = 0; j < n1 + 1; j++) {
730 if(puncture_matrix(j, p) == bin(1)) {
731 output(count_p) = output(count);
732 count_p++;
733 }
734 count++;
735 }
736 p = (p + 1) % Period;
737 }
738 //The second tail:
739 for(i = 0; i < m_tail; i++) {
740 // systematic bit
741 if(puncture_matrix(0, p1) == bin(1)) {
742 output(count_p) = output(count);
743 count_p++;
744 }
745 count++;
746 // parity
747 for(j = n1 + 1; j < n_tot; j++) {
748 if(puncture_matrix(j, p1) == bin(1)) {
749 output(count_p) = output(count);
750 count_p++;
751 }
752 count++;
753 }
754 p1 = (p1 + 1) % Period;
755 }
756 } //for
757
758 output.set_size(count_p, true);
759}
760
761
763{
764 int i, k, p, j, p1;
765 int index = 0, index_p = 0;
766 int no_blocks = received_signal.size() / pNcoded;
767 vec temp(no_blocks * Ncoded);
768
769 it_assert(Period != 0, "Punctured_Turbo_Codec: puncture matrix is not set");
770 it_assert(no_blocks * pNcoded == received_signal.size(), "Punctured_Turbo_Codec: received vector is not an integer multiple of encoded block");
771 for(i = 0; i < no_blocks; i++) {
772 p = 0;
773 // data
774 for(k = 0; k < Nuncoded; k++) {
775 for(j = 0; j < n_tot; j++) {
776 if(puncture_matrix(j, p) == bin(1)) {
777 temp(index) = received_signal(index_p);
778 index_p++;
779 }
780 else { // insert dummy symbols with same contribution for 0 and 1
781 temp(index) = 0;
782 }
783 index++;
784 }
785 p = (p + 1) % Period;
786 } // for
787 p1 = p;
788
789 // 1st code tail
790 for(k = 0; k < m_tail; k++) {
791 for(j = 0; j < n1 + 1; j++) {
792 if(puncture_matrix(j, p) == bin(1)) {
793 temp(index) = received_signal(index_p);
794 index_p++;
795 }
796 else { // insert dummy symbols with same contribution for 0 and 1
797 temp(index) = 0;
798 }
799 index++;
800 }
801 p = (p + 1) % Period;
802 } // for
803 // 2nd code tail
804 for(k = 0; k < m_tail; k++) {
805 // systematic bits
806 if(puncture_matrix(0, p1) == bin(1)) {
807 temp(index) = received_signal(index_p);
808 index_p++;
809 }
810 else { // insert dummy symbols with same contribution for 0 and 1
811 temp(index) = 0;
812 }
813 index++;
814 // parity bits
815 for(j = n1 + 1; j < n_tot; j++) {
816 if(puncture_matrix(j, p1) == bin(1)) {
817 temp(index) = received_signal(index_p);
818 index_p++;
819 }
820 else { // insert dummy symbols with same contribution for 0 and 1
821 temp(index) = 0;
822 }
823 index++;
824 }
825 p1 = (p1 + 1) % Period;
826 } //2nd tail
827 } // for
828
830}
831
837
839{
840 int i, j, ii, p = 0, p1;
841
842 if(Period == 0)
843 pNcoded = Ncoded;
844 else {
845 i = (Nuncoded / Period);
846 ii = i * punct_total;
847 i *= Period;
848 for(; i < Nuncoded; i++) {
849 for(j = 0; j < n_tot; j++)
850 if(puncture_matrix(j, p) == bin(1)) ii++;
851 p = (p + 1) % Period;
852 }
853 p1 = p;
854
855 // first tail
856 for(i = 0; i < m_tail; i++) {
857 for(j = 0; j < n1 + 1; j++)
858 if(puncture_matrix(j, p) == bin(1)) ii++;
859 p = (p + 1) % Period;
860 }
861 // second tail
862 for(i = 0; i < m_tail; i++) {
863 for(j = 0; j < n_tot; j++) {
864 if(puncture_matrix(j, p1) == bin(1)) ii++;
865 if(j == 0) j += n1;
866 }
867 p1 = (p1 + 1) % Period;
868 }
869
870 pNcoded = ii;
871 }
872}
873
875{
876 // fill_bits - number of bits that must be added at the end of encoded block (in order to obtain punctured_size length vector)
877
878 int Nuncoded;
879
880 if(tc.Period == 0) {
881 Nuncoded = (punctured_size - tc.m_tail * (tc.n_tot + 1)) / tc.n_tot;
882 fill_bits = punctured_size - (Nuncoded * tc.n_tot + tc.m_tail * (tc.n_tot + 1));
883 }
884 else {
885 int i, j, ii, p, p1, no_pblocks;
886 // uncoded - // no_pblocks might be too small
887 j = static_cast<int>(std::ceil(static_cast<double>(tc.m_tail * (tc.punct_total1 + tc.punct_total2)) / tc.Period));
888 no_pblocks = (punctured_size - j) / tc.punct_total;
889 ii = punctured_size - no_pblocks * tc.punct_total - j;
890
891 for(i = 0; i < 2 * tc.Period; i++) {
892 for(j = 0; j < tc.n_tot; j++)
893 if(tc.puncture_matrix(j, i % tc.Period) == bin(1)) ii--;
894 if(ii < 0) break;
895 }
896 Nuncoded = no_pblocks * tc.Period + i;
897
898 // punctured (from uncoded)
899 no_pblocks = (Nuncoded / tc.Period);
900 ii = no_pblocks * tc.punct_total;
901 p = 0;
902 for(i = no_pblocks * tc.Period; i < Nuncoded; i++) {
903 for(j = 0; j < tc.n_tot; j++)
904 if(tc.puncture_matrix(j, p) == bin(1)) ii++;
905 p = (p + 1) % tc.Period;
906 }
907 p1 = p;
908 // first tail
909 for(i = 0; i < tc.m_tail; i++) {
910 for(j = 0; j < tc.n1 + 1; j++)
911 if(tc.puncture_matrix(j, p1) == bin(1)) ii++;
912 p1 = (p1 + 1) % tc.Period;
913 }
914 // second tail
915 for(i = 0; i < tc.m_tail; i++) {
916 for(j = 0; j < tc.n_tot; j++) {
917 if(tc.puncture_matrix(j, p1) == bin(1)) ii++;
918 if(j == 0) j += tc.n1;
919 }
920 p1 = (p1 + 1) % tc.Period;
921 }
923 }
924
925 return Nuncoded;
926}
927
928
929// -------------------------------------------------------------------------------------
930// Special interleaver sequence generators
931// -------------------------------------------------------------------------------------
932
933ivec wcdma_turbo_interleaver_sequence(int interleaver_size)
934{
935 const int MAX_INTERLEAVER_SIZE = 5114;
936 const int MIN_INTERLEAVER_SIZE = 40;
937 int K; //Interleaver size
938 int R; //Number of rows of rectangular matrix
939 int C; //Number of columns of rectangular matrix
940 int p; //Prime number
941 int v; //Primitive root
942 ivec s; //Base sequence for intra-row permutation
943 ivec q; //Minimum prime integers
944 ivec r; //Permuted prime integers
945 ivec T; //Inter-row permutation pattern
946 imat U; //Intra-row permutation patter
947 ivec I; //The interleaver sequence
948 ivec primes, roots, Pat1, Pat2, Pat3, Pat4, Isort;
949 int i, j, qj, temp, row, col, index, count;
950
951 if(interleaver_size > MAX_INTERLEAVER_SIZE) {
952
953 I = sort_index(randu(interleaver_size));
954 return I;
955
956 }
957 else {
958
959 p = 0;
960 v = 0;
961
962 //Check the range of the interleaver size:
963 it_assert(interleaver_size <= MAX_INTERLEAVER_SIZE, "wcdma_turbo_interleaver_sequence: The interleaver size is to large");
964 it_assert(interleaver_size >= MIN_INTERLEAVER_SIZE, "wcdma_turbo_interleaver_sequence: The interleaver size is to small");
965
966 K = interleaver_size;
967
968 //Definitions of primes and associated primitive roots:
969 primes = "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257";
970 roots = "0 0 0 3 2 2 3 2 5 2 3 2 6 3 5 2 2 2 2 7 5 3 2 3 5 2 5 2 6 3 3 2 3 2 2 6 5 2 5 2 2 2 19 5 2 3 2 3 2 6 3 7 7 6 3";
971
972 //Determine R
973 if((K >= 40) && (K <= 159)) {
974 R = 5;
975 }
976 else if(((K >= 160) && (K <= 200)) || ((K >= 481) && (K <= 530))) {
977 R = 10;
978 }
979 else {
980 R = 20;
981 }
982
983 //Determine C
984 if((K >= 481) && (K <= 530)) {
985 p = 53;
986 v = 2;
987 C = p;
988 }
989 else {
990 //Find minimum prime p such that (p+1) - K/R >= 0 ...
991 for(i = 0; i < primes.length(); i++) {
992 if((double(primes(i) + 1) - double(K) / double(R)) >= 0.0) {
993 p = primes(i);
994 v = roots(i);
995 break;
996 }
997 }
998 //... and etermine C such that
999 if((double(p) - double(K) / double(R)) >= 0.0) {
1000 if((double(p) - 1.0 - double(K) / double(R)) >= 0.0) {
1001 C = p - 1;
1002 }
1003 else {
1004 C = p;
1005 }
1006 }
1007 else {
1008 C = p + 1;
1009 }
1010 }
1011
1012 //Construct the base sequencs s for intra-row permutaions
1013 s.set_size(p - 1, false);
1014 s.clear();
1015 s(0) = 1;
1016 for(i = 1; i <= (p - 2); i++) {
1017 s(i) = mod(v * s(i - 1), p);
1018 }
1019
1020 //Let q(0) = 1 be the first prime integer in {q(j)}, and select the consecutive
1021 //minimum prime integers {q(j)}, j = 1, 2, ..., (R-1) such that gcd( q(j), p-1) == 1, q(j) > 6, and q(j) > q(j-1)
1022 q.set_size(R, false);
1023 q.clear();
1024 q(0) = 1;
1025 for(j = 1; j <= (R - 1); j++) {
1026 for(i = 0; i < primes.length(); i++) {
1027 qj = primes(i);
1028 if((qj > 6) && (qj > q(j - 1))) {
1029 if(gcd(qj, p - 1) == 1) {
1030 q(j) = qj;
1031 break;
1032 }
1033 }
1034 }
1035 }
1036
1037 //Definitions of Pat1, Pat2, Pat3, and Pat4:
1038 Pat1 = "19 9 14 4 0 2 5 7 12 18 10 8 13 17 3 1 16 6 15 11";
1039 Pat2 = "19 9 14 4 0 2 5 7 12 18 16 13 17 15 3 1 6 11 8 10";
1040 Pat3 = "9 8 7 6 5 4 3 2 1 0";
1041 Pat4 = "4 3 2 1 0";
1042
1043 //T(j) is the inter-row permutation patters defined as one of the following four
1044 //kinds of patterns: Pat1, Pat2, Pat3, and Pat4 depending on the number of input bits K
1045 if(K >= 3211) {
1046 T = Pat1;
1047 }
1048 else if(K >= 3161) {
1049 T = Pat2;
1050 }
1051 else if(K >= 2481) {
1052 T = Pat1;
1053 }
1054 else if(K >= 2281) {
1055 T = Pat2;
1056 }
1057 else if(K >= 531) {
1058 T = Pat1;
1059 }
1060 else if(K >= 481) {
1061 T = Pat3;
1062 }
1063 else if(K >= 201) {
1064 T = Pat1;
1065 }
1066 else if(K >= 160) {
1067 T = Pat3;
1068 }
1069 else {
1070 T = Pat4;
1071 }
1072
1073 //Permute {q(j)} to make {r(j)} such that r(T(j)) = q(j), j = 0, 1, ..., (R-1),
1074 //where T(j) indicates the original row position of the j-th permuted row
1075 r.set_size(R, false);
1076 r.clear();
1077 for(j = 0; j <= (R - 1); j++) {
1078 r(T(j)) = q(j);
1079 }
1080
1081 //U(j,i) is the input bit position of i-th output after the permutation of j-th row
1082 //Perform the j-th (j=0, 1, 2, ..., (R-1)) intra-row permutation as
1083 U.set_size(R, C, false);
1084 U.clear();
1085 if(C == p) {
1086 for(j = 0; j <= (R - 1); j++) {
1087 for(i = 0; i <= (p - 2); i++) {
1088 U(j, i) = s(mod(i * r(j), p - 1));
1089 }
1090 U(j, p - 1) = 0;
1091 }
1092 }
1093 else if(C == (p + 1)) {
1094 for(j = 0; j <= (R - 1); j++) {
1095 for(i = 0; i <= (p - 2); i++) {
1096 U(j, i) = s(mod(i * r(j), p - 1));
1097 }
1098 U(j, p - 1) = 0;
1099 U(j, p) = p;
1100 }
1101 if(K == (C * R)) {
1102 temp = U(R - 1, p);
1103 U(R - 1, p) = U(R - 1, 0);
1104 U(R - 1, 0) = temp;
1105 }
1106 }
1107 else if(C == (p - 1)) {
1108 for(j = 0; j <= (R - 1); j++) {
1109 for(i = 0; i <= (p - 2); i++) {
1110 U(j, i) = s(mod(i * r(j), p - 1)) - 1;
1111 }
1112 }
1113 }
1114
1115 //Calculate the interleaver sequence:
1116 I.set_size(K, false);
1117 I.clear();
1118 count = 0;
1119 for(i = 0; i < C; i++) {
1120 for(j = 0; j < R; j++) {
1121 row = T(j);
1122 col = U(row, i);
1123 index = row * C + col;
1124 if(index < K) {
1125 I(count) = index;
1126 count++;
1127 }
1128 }
1129 }
1130
1131 return I;
1132 }
1133}
1134
1135ivec lte_turbo_interleaver_sequence(int interleaver_size)
1136// for standard see pp. 14 http://www.3gpp.org/FTP/Specs/latest/Rel-10/36_series/36212-a50.zip
1137{
1138
1139 //Definitions of block lengths and associated f1 and f2 factors:
1140 ivec block_lengths("40 48 56 64 72 80 88 96 104 112 120 128 136 144 152 160 168 176 184 192 200 208 216 224 232 240 248 256 264 272 280 288 296 304 312 320 328 336 344 352 360 368 376 384 392 400 408 416 424 432 440 448 456 464 472 480 488 496 504 512 528 544 560 576 592 608 624 640 656 672 688 704 720 736 752 768 784 800 816 832 848 864 880 896 912 928 944 960 976 992 1008 1024 1056 1088 1120 1152 1184 1216 1248 1280 1312 1344 1376 1408 1440 1472 1504 1536 1568 1600 1632 1664 1696 1728 1760 1792 1824 1856 1888 1920 1952 1984 2016 2048 2112 2176 2240 2304 2368 2432 2496 2560 2624 2688 2752 2816 2880 2944 3008 3072 3136 3200 3264 3328 3392 3456 3520 3584 3648 3712 3776 3840 3904 3968 4032 4096 4160 4224 4288 4352 4416 4480 4544 4608 4672 4736 4800 4864 4928 4992 5056 5120 5184 5248 5312 5376 5440 5504 5568 5632 5696 5760 5824 5888 5952 6016 6080 6144");
1141 ivec f1_factors(" 3 7 19 7 7 11 5 11 7 41 103 15 9 17 9 21 101 21 57 23 13 27 11 27 85 29 33 15 17 33 103 19 19 37 19 21 21 115 193 21 133 81 45 23 243 151 155 25 51 47 91 29 29 247 29 89 91 157 55 31 17 35 227 65 19 37 41 39 185 43 21 155 79 139 23 217 25 17 127 25 239 17 137 215 29 15 147 29 59 65 55 31 17 171 67 35 19 39 19 199 21 211 21 43 149 45 49 71 13 17 25 183 55 127 27 29 29 57 45 31 59 185 113 31 17 171 209 253 367 265 181 39 27 127 143 43 29 45 157 47 13 111 443 51 51 451 257 57 313 271 179 331 363 375 127 31 33 43 33 477 35 233 357 337 37 71 71 37 39 127 39 39 31 113 41 251 43 21 43 45 45 161 89 323 47 23 47 263");
1142 ivec f2_factors("10 12 42 16 18 20 22 24 26 84 90 32 34 108 38 120 84 44 46 48 50 52 36 56 58 60 62 32 198 68 210 36 74 76 78 120 82 84 86 44 90 46 94 48 98 40 102 52 106 72 110 168 114 58 118 180 122 62 84 64 66 68 420 96 74 76 234 80 82 252 86 44 120 92 94 48 98 80 102 52 106 48 110 112 114 58 118 60 122 124 84 64 66 204 140 72 74 76 78 240 82 252 86 88 60 92 846 48 28 80 102 104 954 96 110 112 114 116 354 120 610 124 420 64 66 136 420 216 444 456 468 80 164 504 172 88 300 92 188 96 28 240 204 104 212 192 220 336 228 232 236 120 244 248 168 64 130 264 134 408 138 280 142 480 146 444 120 152 462 234 158 80 96 902 166 336 170 86 174 176 178 120 182 184 186 94 190 480");
1143 const int MAX_INTERLEAVER_SIZE = 6144;
1144 const int MIN_INTERLEAVER_SIZE = 40;
1145
1146 // Check the range of the interleaver size:
1147 it_assert(interleaver_size <= MAX_INTERLEAVER_SIZE, "lte_turbo_interleaver_sequence: The interleaver size is too large");
1148 it_assert(interleaver_size >= MIN_INTERLEAVER_SIZE, "lte_turbo_interleaver_sequence: The interleaver size is too small");
1149
1150 // Check whether the given interleaver size is correct:
1151 int left, right, index, temp;
1152 bool search = true;
1153
1154 // do a binary search for interleaver_size in block_lengths
1155 left = 0;
1156 right = block_lengths.size() - 1;
1157 temp = 0;
1158 while((search) && (left <= right)) {
1159 index = (left + right) / 2;
1160 temp = block_lengths(index);
1161 if(temp == interleaver_size) {
1162 search = false;
1163 }
1164 else {
1165 if(temp > interleaver_size) {
1166 right = index - 1;
1167 }
1168 else {
1169 left = index + 1;
1170 }
1171 }
1172 }
1173 it_assert(!search, "lte_turbo_interleaver_sequence: The interleaver size is incorrect!");
1174
1175 // Definitions of key parameters:
1176 int K = interleaver_size; // Interleaver size
1177 int f1_factor = f1_factors(index);
1178 int f2_factor = f2_factors(index);
1179 ivec I(K); //The interleaver sequence
1180
1181 // Calculate the interleaver sequence:
1182 for(int i = 0; i < K; i++) {
1183 I(i) = static_cast<int>((static_cast<int64_t>(i) * f1_factor + static_cast<int64_t>(i) * i * f2_factor) % K);
1184 }
1185
1186 return I;
1187}
1188
1189
1190} // namespace itpp
General array class.
Definition array.h:105
Array< T > mid(int pos, int n) const
Get n elements of the array starting from pos.
Definition array.h:377
int size() const
Returns the number of data elements in the array object.
Definition array.h:155
Array< T > left(int n) const
Get n left elements of the array.
Definition array.h:357
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
int length() const
Returns the number of data elements in the array object.
Definition array.h:157
Array< T > right(int n) const
Get n right elements of the array.
Definition array.h:367
Log-likelihood algebra calculation unit.
Definition llr.h:125
Punctured turbo encoder/decoder Class.
Definition turbo.h:332
int Period
Number of columns in the puncturing matrix.
Definition turbo.h:505
void set_parameters(ivec gen1, ivec gen2, int constraint_length, const ivec &interleaver_sequence, bmat &pmatrix, int in_iterations=8, std::string in_metric="LOGMAX", double in_logmax_scale_factor=1.0, bool in_adaptive_stop=false, itpp::LLR_calc_unit lcalc=itpp::LLR_calc_unit())
Set parameters for the punctured turbo encoder/decoder.
Definition turbo.cpp:631
void calculate_punctured_size(void)
Calculates length of the puncturing codeword.
Definition turbo.cpp:838
void set_puncture_matrix(const bmat &pmatrix)
Sets puncturing matrix for turbo code (size n_tot * Period)
Definition turbo.cpp:637
virtual void decode(const vec &received_signal, bvec &decoded_bits, const bvec &true_bits="0")
Decoder function.
Definition turbo.cpp:832
double get_rate(bool nominal=true)
Returns rate of the turbo code.
Definition turbo.cpp:674
void encode(const bvec &input, bvec &output)
Encoder function.
Definition turbo.cpp:702
virtual void map_decode(const vec &rec_systematic, const mat &rec_parity, const vec &extrinsic_input, vec &extrinsic_output, bool set_terminated=false)
Maximum A Posteriori (MAP) Probability symbol-by-symbol decoder.
void set_generator_polynomials(const ivec &gen, int constraint_length)
Set generator polynomials.
void encode_tail(const bvec &input, bvec &tail, bmat &parity_bits)
Encode a binary vector of inputs and also adds a tail of K-1 zeros to force the encoder into the zero...
virtual void log_decode_n2(const vec &rec_systematic, const vec &rec_parity, const vec &extrinsic_input, vec &extrinsic_output, bool set_terminated=false, std::string metric="LOGMAX")
Special Log-MAP/Log-MAX decoder implementation for n = 2.
void set_llrcalc(LLR_calc_unit in_llrcalc)
Set the lookup table for algebra with quantized LLR values (see LLR_calc_unit class)
virtual void log_decode(const vec &rec_systematic, const mat &rec_parity, const vec &extrinsic_input, vec &extrinsic_output, bool set_terminated=false, std::string metric="LOGMAX")
Log domain implementation of the Maximum A Posteriori (MAP) Probability symbol-by-symbol decoder.
void set_interleaver_depth(int in_interleaver_depth)
Set the length of the interleaver sequence to be used.
Definition interleave.h:183
Vec< T > interleave(const Vec< T > &input)
Function for sequence interleaving. May add some zeros.
Definition interleave.h:468
Vec< T > deinterleave(const Vec< T > &input, short keepzeros=0)
Function for sequence deinterleaving. Removes additional zeros if keepzeros = 0.
Definition interleave.h:515
void set_interleaver_sequence(ivec in_interleaver_sequence)
Set the interleaver sequence to be used.
Definition interleave.h:535
void encode(const bvec &input, bvec &output)
Encoder function.
Definition turbo.cpp:178
void set_iterations(int in_iterations=8)
Sets the number of decoding iterations. Default value is 8.
Definition turbo.cpp:155
void set_metric(std::string in_metric="LOGMAX", double in_logmax_scale_factor=1.0, LLR_calc_unit lcalc=LLR_calc_unit())
Set the decoder metric.
Definition turbo.cpp:130
virtual void decode_block(const vec &rec_syst1, const vec &rec_syst2, const mat &rec_parity1, const mat &rec_parity2, bmat &decoded_bits_i, int &nrof_used_iterations_i, const bvec &true_bits="0")
Decode a single block.
Definition turbo.cpp:361
void set_awgn_channel_parameters(double in_Ec, double in_N0)
Set parameters for decoding on an AWGN channel.
Definition turbo.cpp:165
void set_parameters(ivec gen1, ivec gen2, int constraint_length, const ivec &interleaver_sequence, int in_iterations=8, const std::string &in_metric="LOGMAX", double in_logmax_scale_factor=1.0, bool in_adaptive_stop=false, LLR_calc_unit lcalc=LLR_calc_unit())
Set parameters for the turbo encoder/decoder.
Definition turbo.cpp:55
void set_adaptive_stop(bool in_adaptive_stop=true)
Use and adaptive number of iterations.
Definition turbo.cpp:160
void set_interleaver(const ivec &interleaver_sequence)
Set a new internal interleaver sequence for the turbo encoder/decoder.
Definition turbo.cpp:115
void encode_block(const bvec &input, bvec &in1, bvec &in2, bmat &parity1, bmat &parity2)
Encode a single block.
Definition turbo.cpp:326
void set_scaling_factor(double in_Lc)
Set scaling factor for decoding on e.g. Rayleigh fading channels.
Definition turbo.cpp:172
virtual void decode(const vec &received_signal, bvec &decoded_bits, const bvec &true_bits="0")
Decoder function.
Definition turbo.cpp:226
void decode_n3(const vec &received_signal, bvec &decoded_bits, ivec &nrof_used_iterations, const bvec &true_bits="0")
Special decoder function for R = 1/3 i.e. two parity bits for each systematic bit.
Definition turbo.cpp:486
Binary arithmetic (boolean) class.
Definition binary.h:57
#define it_error_if(t, s)
Abort if t is true.
Definition itassert.h:117
#define it_error(s)
Abort unconditionally.
Definition itassert.h:126
#define it_assert(t, s)
Abort if t is not true.
Definition itassert.h:94
int mod(int k, int n)
Calculates the modulus, i.e. the signed reminder after division.
Definition elem_math.h:166
int gcd(int a, int b)
Compute the greatest common divisor (GCD) g of the elements a and b.
void roots(const vec &p, cvec &r)
Calculate the roots of the polynomial.
Definition poly.cpp:66
double randu(void)
Generates a random uniform (0,1) number.
Definition random.h:804
ITPP_EXPORT vec zeros(int size)
A Double vector of zeros.
Mat< bin > bmat
bin matrix
Definition mat.h:508
itpp namespace
Definition itmex.h:37
ivec lte_turbo_interleaver_sequence(int interleaver_size)
Generates the interleaver sequence for the internal turbo encoder interleaver used in LTE.
Definition turbo.cpp:1135
ivec wcdma_turbo_interleaver_sequence(int interleaver_size)
Generates the interleaver sequence for the internal turbo encoder interleaver used in WCDMA.
Definition turbo.cpp:933
const Array< T > concat(const Array< T > &a, const T &e)
Append element e to the end of the Array a.
Definition array.h:486
int calculate_uncoded_size(Punctured_Turbo_Codec &tc, int punctured_size, int &fill_bits)
Definition turbo.cpp:874
Definition of a (punctured) turbo encoder/decoder class.

Generated on Tue Aug 17 2021 10:59:15 for IT++ by Doxygen 1.9.8