From ff1efb7b179c0894f6dac688943a07e54cff2e1b Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 12 Sep 2015 13:27:59 +0200 Subject: [PATCH] Added LUT-based turbo coder --- srslte/include/srslte/fec/turbocoder.h | 8 ++ srslte/lib/fec/src/turbocoder.c | 165 ++++++++++++++++++++++++- srslte/lib/fec/test/CMakeLists.txt | 5 + srslte/lib/fec/test/turbocoder_test.c | 141 +++++++++++++++++++++ 4 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 srslte/lib/fec/test/turbocoder_test.c diff --git a/srslte/include/srslte/fec/turbocoder.h b/srslte/include/srslte/fec/turbocoder.h index 697d1e80a..eb281132b 100644 --- a/srslte/include/srslte/fec/turbocoder.h +++ b/srslte/include/srslte/fec/turbocoder.h @@ -49,6 +49,7 @@ typedef struct SRSLTE_API { uint32_t max_long_cb; + uint8_t *temp; srslte_tc_interl_t interl; } srslte_tcod_t; @@ -62,5 +63,12 @@ SRSLTE_API int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *output, uint32_t long_cb); +SRSLTE_API int srslte_tcod_encode_lut(srslte_tcod_t *h, + uint8_t *input, + uint8_t *output, + uint32_t long_cb); + +SRSLTE_API void srslte_tcod_gentable(); + #endif diff --git a/srslte/lib/fec/src/turbocoder.c b/srslte/lib/fec/src/turbocoder.c index f7f6ac013..03d28bba1 100644 --- a/srslte/lib/fec/src/turbocoder.c +++ b/srslte/lib/fec/src/turbocoder.c @@ -28,14 +28,22 @@ #include #include +#include +#include +#include "srslte/fec/cbsegm.h" #include "srslte/fec/turbocoder.h" +#include "srslte/utils/bit.h" +#include "srslte/utils/vector.h" #define NOF_REGS 3 #define RATE 3 #define TOTALTAIL 12 +uint8_t tcod_lut_next_state[188][8][256]; +uint8_t tcod_lut_output[188][8][256]; +uint16_t tcod_per_fw[188][6114]; int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) { @@ -43,15 +51,21 @@ int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) { return -1; } h->max_long_cb = max_long_cb; + h->temp = srslte_vec_malloc(max_long_cb/8); return 0; } void srslte_tcod_free(srslte_tcod_t *h) { srslte_tc_interl_free(&h->interl); h->max_long_cb = 0; + if (h->temp) { + free(h->temp); + } } -int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32_t long_cb) { +/* Expects bits (1 byte = 1 bit) and produces bits. The systematic and parity bits are interlaced in the output */ +int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32_t long_cb) +{ uint8_t reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2; uint32_t i, k = 0, j; @@ -97,7 +111,7 @@ int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32 reg1_2 = reg1_1; reg1_1 = reg1_0; reg1_0 = in; - + if (input[i] == SRSLTE_TX_NULL) { output[k] = SRSLTE_TX_NULL; } else { @@ -119,7 +133,6 @@ int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32 output[k] = out; k++; - } @@ -163,3 +176,149 @@ int srslte_tcod_encode(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32 return 0; } +/* Expects bytes and produces bytes. The systematic and parity bits are interlaced in the output */ +int srslte_tcod_encode_lut(srslte_tcod_t *h, uint8_t *input, uint8_t *output, uint32_t long_cb) +{ + if (long_cb % 8) { + fprintf(stderr, "Turbo coder LUT implementation long_cb must be multiple of 8\n"); + return -1; + } + + int ret = srslte_cbsegm_cbindex(long_cb); + if (ret < 0) { + return -1; + } + uint8_t len_idx = (uint8_t) ret; + + /* Parity bits for the 1st constituent encoders */ + uint8_t state0 = 0; + for (uint32_t i=0;itemp[i] = 0; + for (uint32_t j=0;j<8;j++) { + uint32_t i_p = tcod_per_fw[len_idx][i*8+j]; + if (input[i_p/8] & (1<<(7-i_p%8))) { + h->temp[i] |= 1<<(7-j); + } + } + } + + /* Parity bits for the 2nd constituent encoders */ + uint8_t state1 = 0; + for (uint32_t i=0;itemp[i]]; + state1 = tcod_lut_next_state[len_idx][state1][h->temp[i]] % 8; + } + + /* Tail bits */ + uint8_t reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2; + uint8_t bit, in, out; + uint8_t k=0; + uint8_t tail[12]; + + reg2_0 = (state1&4)>>2; + reg2_1 = (state1&2)>>1; + reg2_2 = state1&1; + + reg1_0 = (state0&4)>>2; + reg1_1 = (state0&2)>>1; + reg1_2 = state0&1; + + /* TAILING CODER #1 */ + for (uint32_t j = 0; j < NOF_REGS; j++) { + bit = reg1_2 ^ reg1_1; + + tail[k] = bit; + k++; + + in = bit ^ (reg1_2 ^ reg1_1); + out = reg1_2 ^ (reg1_0 ^ in); + + reg1_2 = reg1_1; + reg1_1 = reg1_0; + reg1_0 = in; + + tail[k] = out; + k++; + } + + /* TAILING CODER #2 */ + for (uint32_t j = 0; j < NOF_REGS; j++) { + bit = reg2_2 ^ reg2_1; + + tail[k] = bit; + k++; + + in = bit ^ (reg2_2 ^ reg2_1); + out = reg2_2 ^ (reg2_0 ^ in); + + reg2_2 = reg2_1; + reg2_1 = reg2_0; + reg2_0 = in; + + tail[k] = out; + k++; + } + + srslte_bit_unpack_vector(tail, &output[2*(long_cb/8)], TOTALTAIL); + + return 2*long_cb+TOTALTAIL; +} + +void srslte_tcod_gentable() { + srslte_tc_interl_t interl; + + if (srslte_tc_interl_init(&interl, 6144)) { + fprintf(stderr, "Error initiating interleave\n"); + return; + } + + for (uint32_t len=0;len<188;len++) { + uint32_t long_cb = srslte_cbsegm_cbsize(len); + if (srslte_tc_interl_LTE_gen(&interl, long_cb)) { + fprintf(stderr, "Error initiating TC interleaver for long_cb=%d\n", long_cb); + return; + } + // Save fw/bw permutation tables + for (uint32_t i=0;i>2; + reg_1 = (state&2)>>1; + reg_2 = state&1; + + tcod_lut_output[len][state][data] = 0; + uint8_t bit, in, out; + for (uint32_t i = 0; i < 8; i++) { + bit = (data&(1<<(7-i)))?1:0; + + in = bit ^ (reg_2 ^ reg_1); + out = reg_2 ^ (reg_0 ^ in); + + reg_2 = reg_1; + reg_1 = reg_0; + reg_0 = in; + + tcod_lut_output[len][state][data] |= out<<(7-i); + + } + tcod_lut_next_state[len][state][data] = reg_0<<2 | reg_1<<1 | reg_2; + } + } + } + + srslte_tc_interl_free(&interl); +} diff --git a/srslte/lib/fec/test/CMakeLists.txt b/srslte/lib/fec/test/CMakeLists.txt index 86b549df6..3bbcddf48 100644 --- a/srslte/lib/fec/test/CMakeLists.txt +++ b/srslte/lib/fec/test/CMakeLists.txt @@ -53,6 +53,11 @@ ADD_TEST(turbodecoder_test_known turbodecoder_test -n 1 -s 1 -k -e 0.5) BuildMex(MEXNAME turbodecoder SOURCES turbodecoder_test_mex.c LIBRARIES srslte srslte_mex) +ADD_EXECUTABLE(turbocoder_test turbocoder_test.c) +TARGET_LINK_LIBRARIES(turbocoder_test srslte) +ADD_TEST(turbocoder_test_40 turbocoder_test -l 40) +ADD_TEST(turbocoder_test_6114 turbocoder_test -l 6114) + ######################################################################## # Viterbi TEST ######################################################################## diff --git a/srslte/lib/fec/test/turbocoder_test.c b/srslte/lib/fec/test/turbocoder_test.c new file mode 100644 index 000000000..12e1858a9 --- /dev/null +++ b/srslte/lib/fec/test/turbocoder_test.c @@ -0,0 +1,141 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 The srsLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "srslte/srslte.h" + +uint32_t long_cb = 0; + +void usage(char *prog) { + printf("Usage: %s\n", prog); + printf("\t-l long_cb [Default check all]\n", long_cb); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "lv")) != -1) { + switch (opt) { + case 'l': + long_cb = atoi(argv[optind]); + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +uint8_t input_bytes[6144/8]; +uint8_t input_bits[6144]; +uint8_t output_bits[3*6144+12]; +uint8_t output_bytes[3*6144+12]; +uint8_t output_bits2[3*6144+12]; +uint8_t output_bits3[3*6144+12]; + +int main(int argc, char **argv) { + + parse_args(argc, argv); + + srslte_tcod_gentable(); + + srslte_tcod_t tcod; + srslte_tcod_init(&tcod, 6144); + + uint32_t st=0, end=187; + if (long_cb) { + st=srslte_cbsegm_cbindex(long_cb); + end=st; + } + + for (uint32_t len=st;len<=end;len++) { + long_cb = srslte_cbsegm_cbsize(len); + printf("Checking long_cb=%d\n", long_cb); + for (int i=0;i