mirror of https://github.com/PentHertz/srsLTE.git
Added LUT-based turbo coder
This commit is contained in:
parent
67a5e0f0f1
commit
ff1efb7b17
|
@ -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
|
||||
|
||||
|
|
|
@ -28,14 +28,22 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;i<long_cb/8;i++) {
|
||||
output[i] = tcod_lut_output[len_idx][state0][input[i]];
|
||||
state0 = tcod_lut_next_state[len_idx][state0][input[i]] % 8;
|
||||
}
|
||||
|
||||
/* Interleave input */
|
||||
for (uint32_t i=0;i<long_cb/8;i++) {
|
||||
h->temp[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;i<long_cb/8;i++) {
|
||||
output[long_cb/8+i] = tcod_lut_output[len_idx][state1][h->temp[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<long_cb;i++) {
|
||||
tcod_per_fw[len][i] = interl.forward[i];
|
||||
}
|
||||
for (uint32_t i=long_cb;i<6144;i++) {
|
||||
tcod_per_fw[len][i] = 0;
|
||||
}
|
||||
// Compute state transitions
|
||||
for (uint32_t state=0;state<8;state++) {
|
||||
for (uint32_t data=0;data<256;data++) {
|
||||
|
||||
uint8_t reg_0, reg_1, reg_2;
|
||||
reg_0 = (state&4)>>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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
########################################################################
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#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<long_cb/8;i++) {
|
||||
input_bytes[i] = rand()%256;
|
||||
}
|
||||
|
||||
srslte_bit_pack_vector(input_bytes, input_bits, long_cb);
|
||||
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
printf("Input bits:\n");
|
||||
for (int i=0;i<long_cb/8;i++) {
|
||||
srslte_vec_fprint_b(stdout, &input_bits[i*8], 8);
|
||||
}
|
||||
}
|
||||
|
||||
srslte_tcod_encode(&tcod, input_bits, output_bits, long_cb);
|
||||
srslte_tcod_encode_lut(&tcod, input_bytes, output_bytes, long_cb);
|
||||
|
||||
srslte_bit_pack_vector(output_bytes, output_bits2, 2*long_cb+12);
|
||||
|
||||
/* de-Interleace bits for comparison */
|
||||
for (int i=0;i<long_cb;i++) {
|
||||
for (int j=0;j<2;j++) {
|
||||
output_bits3[j*long_cb+i] = output_bits[3*i+j+1];
|
||||
}
|
||||
}
|
||||
// copy tail
|
||||
memcpy(&output_bits3[2*long_cb], &output_bits[3*long_cb], 12);
|
||||
|
||||
if (SRSLTE_VERBOSE_ISINFO()) {
|
||||
printf("1st encoder\n");
|
||||
srslte_vec_fprint_b(stdout, output_bits2, long_cb);
|
||||
srslte_vec_fprint_b(stdout, output_bits3, long_cb);
|
||||
|
||||
printf("2nd encoder\n");
|
||||
srslte_vec_fprint_b(stdout, &output_bits2[long_cb], long_cb);
|
||||
srslte_vec_fprint_b(stdout, &output_bits3[long_cb], long_cb);
|
||||
|
||||
printf("tail\n");
|
||||
srslte_vec_fprint_b(stdout, &output_bits2[2*long_cb], 12);
|
||||
srslte_vec_fprint_b(stdout, &output_bits3[2*long_cb], 12);
|
||||
printf("\n");
|
||||
}
|
||||
for (int i=0;i<2*long_cb+12;i++) {
|
||||
if (output_bits2[i] != output_bits3[i]) {
|
||||
printf("error in bit %d, len=%d\n", i, len);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srslte_tcod_free(&tcod);
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue