2019-04-26 12:27:38 -07:00
|
|
|
/*
|
2020-03-13 04:12:52 -07:00
|
|
|
* Copyright 2013-2020 Software Radio Systems Limited
|
2018-09-04 08:51:35 -07:00
|
|
|
*
|
2019-04-26 12:27:38 -07:00
|
|
|
* This file is part of srsLTE.
|
2018-09-04 08:51:35 -07:00
|
|
|
*
|
|
|
|
* 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/.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdint.h>
|
2018-09-04 08:51:35 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <strings.h>
|
|
|
|
|
|
|
|
#include "srslte/phy/fec/turbodecoder_gen.h"
|
|
|
|
#include "srslte/phy/utils/vector.h"
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
#define NUMSTATES 8
|
|
|
|
#define NINPUTS 2
|
|
|
|
#define TAIL 3
|
|
|
|
#define TOTALTAIL 12
|
2018-09-04 08:51:35 -07:00
|
|
|
|
|
|
|
#define INF 10000
|
|
|
|
|
|
|
|
#define debug_enabled 0
|
|
|
|
|
|
|
|
#if debug_enabled
|
2019-12-16 07:04:22 -08:00
|
|
|
#define debug_state \
|
|
|
|
printf("k=%5d, in=%5d, pa=%3d, out=%5d, alpha=", k, x, parity[k - 1], out); \
|
|
|
|
srslte_vec_fprint_s(stdout, alpha, 8); \
|
|
|
|
printf(", beta="); \
|
|
|
|
srslte_vec_fprint_s(stdout, &beta[8 * (k)], 8); \
|
|
|
|
printf("\n");
|
2018-09-04 08:51:35 -07:00
|
|
|
#else
|
|
|
|
#define debug_state
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
*
|
|
|
|
* MAP_GEN is the MAX-LOG-MAP generic implementation of the
|
|
|
|
* Decoder
|
|
|
|
*
|
|
|
|
************************************************/
|
2019-12-16 07:04:22 -08:00
|
|
|
static void map_gen_beta(tdec_gen_t* s, int16_t* input, int16_t* app, int16_t* parity, uint32_t long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
2019-12-16 07:04:22 -08:00
|
|
|
int16_t m_b[8], new[8], old[8];
|
|
|
|
int16_t x, y, xy;
|
|
|
|
int k;
|
|
|
|
uint32_t end = long_cb + SRSLTE_TCOD_RATE;
|
|
|
|
int16_t* beta = s->beta;
|
2018-09-04 08:51:35 -07:00
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
old[i] = beta[8 * (end) + i];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = end - 1; k >= 0; k--) {
|
|
|
|
x = input[k];
|
2019-12-16 07:04:22 -08:00
|
|
|
if (app && k < long_cb) {
|
2018-09-04 08:51:35 -07:00
|
|
|
x += app[k];
|
|
|
|
}
|
|
|
|
y = parity[k];
|
|
|
|
|
|
|
|
xy = x + y;
|
|
|
|
|
|
|
|
m_b[0] = old[4] + xy;
|
|
|
|
m_b[1] = old[4];
|
|
|
|
m_b[2] = old[5] + y;
|
|
|
|
m_b[3] = old[5] + x;
|
|
|
|
m_b[4] = old[6] + x;
|
|
|
|
m_b[5] = old[6] + y;
|
|
|
|
m_b[6] = old[7];
|
|
|
|
m_b[7] = old[7] + xy;
|
|
|
|
|
|
|
|
new[0] = old[0];
|
|
|
|
new[1] = old[0] + xy;
|
|
|
|
new[2] = old[1] + x;
|
|
|
|
new[3] = old[1] + y;
|
|
|
|
new[4] = old[2] + y;
|
|
|
|
new[5] = old[2] + x;
|
|
|
|
new[6] = old[3] + xy;
|
|
|
|
new[7] = old[3];
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (m_b[i] > new[i])
|
|
|
|
new[i] = m_b[i];
|
2019-12-16 07:04:22 -08:00
|
|
|
old[i] = new[i];
|
2018-09-04 08:51:35 -07:00
|
|
|
beta[8 * k + i] = old[i];
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if ((k % 4) == 0 && k < long_cb) {
|
2018-09-04 08:51:35 -07:00
|
|
|
for (i = 1; i < 8; i++) {
|
|
|
|
old[i] -= old[0];
|
|
|
|
}
|
|
|
|
old[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
static void
|
|
|
|
map_gen_alpha(tdec_gen_t* s, int16_t* input, int16_t* app, int16_t* parity, int16_t* output, uint32_t long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
2019-12-16 07:04:22 -08:00
|
|
|
int16_t m_b[8], new[8], old[8], max1[8], max0[8];
|
|
|
|
int16_t m1, m0;
|
|
|
|
int16_t x, y, xy;
|
|
|
|
int16_t out;
|
2018-09-04 08:51:35 -07:00
|
|
|
uint32_t k;
|
2019-12-16 07:04:22 -08:00
|
|
|
uint32_t end = long_cb;
|
|
|
|
int16_t* beta = s->beta;
|
2018-09-04 08:51:35 -07:00
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
old[0] = 0;
|
|
|
|
for (i = 1; i < 8; i++) {
|
|
|
|
old[i] = -INF;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if debug_enabled
|
|
|
|
int16_t alpha[8];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (k = 1; k < end + 1; k++) {
|
|
|
|
x = input[k - 1];
|
|
|
|
if (app) {
|
|
|
|
x += app[k - 1];
|
|
|
|
}
|
|
|
|
y = parity[k - 1];
|
|
|
|
|
|
|
|
xy = x + y;
|
|
|
|
|
|
|
|
#if debug_enabled
|
2019-12-16 07:04:22 -08:00
|
|
|
memcpy(alpha, old, sizeof(int16_t) * 8);
|
2018-09-04 08:51:35 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
m_b[0] = old[0];
|
|
|
|
m_b[1] = old[3] + y;
|
|
|
|
m_b[2] = old[4] + y;
|
|
|
|
m_b[3] = old[7];
|
|
|
|
m_b[4] = old[1];
|
|
|
|
m_b[5] = old[2] + y;
|
|
|
|
m_b[6] = old[5] + y;
|
|
|
|
m_b[7] = old[6];
|
|
|
|
|
|
|
|
new[0] = old[1] + xy;
|
|
|
|
new[1] = old[2] + x;
|
|
|
|
new[2] = old[5] + x;
|
|
|
|
new[3] = old[6] + xy;
|
|
|
|
new[4] = old[0] + xy;
|
|
|
|
new[5] = old[3] + x;
|
|
|
|
new[6] = old[4] + x;
|
|
|
|
new[7] = old[7] + xy;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
max0[i] = m_b[i] + beta[8 * k + i];
|
|
|
|
max1[i] = new[i] + beta[8 * k + i];
|
|
|
|
}
|
|
|
|
|
|
|
|
m1 = max1[0];
|
|
|
|
m0 = max0[0];
|
|
|
|
|
|
|
|
for (i = 1; i < 8; i++) {
|
|
|
|
if (max1[i] > m1)
|
|
|
|
m1 = max1[i];
|
|
|
|
if (max0[i] > m0)
|
|
|
|
m0 = max0[i];
|
|
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (m_b[i] > new[i])
|
|
|
|
new[i] = m_b[i];
|
2019-12-16 07:04:22 -08:00
|
|
|
old[i] = new[i];
|
|
|
|
}
|
2018-09-04 08:51:35 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if ((k % 4) == 0) {
|
2018-09-04 08:51:35 -07:00
|
|
|
for (i = 1; i < 8; i++) {
|
|
|
|
old[i] -= old[0];
|
|
|
|
}
|
|
|
|
old[0] = 0;
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
out = m1 - m0;
|
2018-09-04 08:51:35 -07:00
|
|
|
output[k - 1] = out;
|
|
|
|
|
|
|
|
debug_state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
int tdec_gen_init(void** hh, uint32_t max_long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
|
|
|
*hh = calloc(1, sizeof(tdec_gen_t));
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
tdec_gen_t* h = (tdec_gen_t*)*hh;
|
2018-09-04 08:51:35 -07:00
|
|
|
|
|
|
|
h->beta = srslte_vec_malloc(sizeof(int16_t) * (max_long_cb + SRSLTE_TCOD_TOTALTAIL + 1) * NUMSTATES);
|
|
|
|
if (!h->beta) {
|
|
|
|
perror("srslte_vec_malloc");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
h->max_long_cb = max_long_cb;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
void tdec_gen_free(void* hh)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
2019-12-16 07:04:22 -08:00
|
|
|
tdec_gen_t* h = (tdec_gen_t*)hh;
|
2018-09-07 05:05:45 -07:00
|
|
|
if (h) {
|
|
|
|
if (h->beta) {
|
|
|
|
free(h->beta);
|
|
|
|
}
|
|
|
|
free(h);
|
2018-09-04 08:51:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
void tdec_gen_dec(void* hh, int16_t* input, int16_t* app, int16_t* parity, int16_t* output, uint32_t long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
2019-12-16 07:04:22 -08:00
|
|
|
tdec_gen_t* h = (tdec_gen_t*)hh;
|
2018-09-04 08:51:35 -07:00
|
|
|
|
|
|
|
h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
|
|
|
|
for (uint32_t k = 1; k < NUMSTATES; k++)
|
|
|
|
h->beta[(long_cb + TAIL) * NUMSTATES + k] = -INF;
|
|
|
|
|
|
|
|
map_gen_beta(h, input, app, parity, long_cb);
|
|
|
|
map_gen_alpha(h, input, app, parity, output, long_cb);
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
void tdec_gen_extract_input(int16_t* input,
|
|
|
|
int16_t* syst,
|
|
|
|
int16_t* app2,
|
|
|
|
int16_t* parity0,
|
|
|
|
int16_t* parity1,
|
|
|
|
uint32_t long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
|
|
|
// Prepare systematic and parity bits for MAP DEC #1
|
|
|
|
for (uint32_t i = 0; i < long_cb; i++) {
|
|
|
|
syst[i] = input[SRSLTE_TCOD_RATE * i];
|
|
|
|
parity0[i] = input[SRSLTE_TCOD_RATE * i + 1];
|
|
|
|
parity1[i] = input[SRSLTE_TCOD_RATE * i + 2];
|
|
|
|
}
|
|
|
|
for (uint32_t i = long_cb; i < long_cb + SRSLTE_TCOD_RATE; i++) {
|
|
|
|
syst[i] = input[SRSLTE_TCOD_RATE * long_cb + NINPUTS * (i - long_cb)];
|
|
|
|
parity0[i] = input[SRSLTE_TCOD_RATE * long_cb + NINPUTS * (i - long_cb) + 1];
|
|
|
|
|
|
|
|
app2[i] = input[SRSLTE_TCOD_RATE * long_cb + NINPUTS * SRSLTE_TCOD_RATE + NINPUTS * (i - long_cb)];
|
2019-12-16 07:04:22 -08:00
|
|
|
parity1[i] = input[SRSLTE_TCOD_RATE * long_cb + NINPUTS * SRSLTE_TCOD_RATE + NINPUTS * (i - long_cb) + 1];
|
2018-09-04 08:51:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
void tdec_gen_decision_byte(int16_t* app1, uint8_t* output, uint32_t long_cb)
|
2018-09-04 08:51:35 -07:00
|
|
|
{
|
|
|
|
uint8_t mask[8] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
|
|
|
|
|
|
|
|
// long_cb is always byte aligned
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t i = 0; i < long_cb / 8; i++) {
|
|
|
|
uint8_t out0 = app1[8 * i + 0] > 0 ? mask[0] : 0;
|
|
|
|
uint8_t out1 = app1[8 * i + 1] > 0 ? mask[1] : 0;
|
|
|
|
uint8_t out2 = app1[8 * i + 2] > 0 ? mask[2] : 0;
|
|
|
|
uint8_t out3 = app1[8 * i + 3] > 0 ? mask[3] : 0;
|
|
|
|
uint8_t out4 = app1[8 * i + 4] > 0 ? mask[4] : 0;
|
|
|
|
uint8_t out5 = app1[8 * i + 5] > 0 ? mask[5] : 0;
|
|
|
|
uint8_t out6 = app1[8 * i + 6] > 0 ? mask[6] : 0;
|
|
|
|
uint8_t out7 = app1[8 * i + 7] > 0 ? mask[7] : 0;
|
2018-09-04 08:51:35 -07:00
|
|
|
|
|
|
|
output[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7;
|
|
|
|
}
|
|
|
|
}
|