mirror of https://github.com/PentHertz/srsLTE.git
Fixed B210 USRP Clock issue. Added Turbo Rate matching
This commit is contained in:
parent
6fe5a05952
commit
eb52aeb1ab
|
@ -100,12 +100,14 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int cuhd_open(char *args, void **h) {
|
||||
cuhd_handler* handler = new cuhd_handler();
|
||||
std::string _args=std::string(args);
|
||||
handler->usrp = uhd::usrp::multi_usrp::make(_args);
|
||||
|
||||
// Try to set LTE clock
|
||||
handler->usrp->set_master_clock_rate(30720000);
|
||||
|
||||
handler->usrp->set_clock_source("internal");
|
||||
|
||||
std::string otw, cpu;
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
#define NOF_PORTS 2
|
||||
|
||||
float find_threshold = 30.0, track_threshold = 10.0;
|
||||
float find_threshold = 20.0, track_threshold = 10.0;
|
||||
int max_track_lost = 20, nof_frames = -1;
|
||||
int track_len=300;
|
||||
char *input_file_name = NULL;
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#define TX_NULL 80
|
||||
|
||||
|
||||
int rm_conv_tx(char *input, char *output, int in_len, int out_len);
|
||||
int rm_conv_rx(float *input, float *output, int in_len, int out_len);
|
||||
int rm_conv_tx(char *input, int in_len, char *output, int out_len);
|
||||
int rm_conv_rx(float *input, int in_len, float *output, int out_len);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
|
|
@ -26,19 +26,32 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef RM_CONV_
|
||||
#define RM_CONV_
|
||||
#ifndef RM_TURBO_
|
||||
#define RM_TURBO_
|
||||
|
||||
#ifndef RX_NULL
|
||||
#define RX_NULL 10000
|
||||
#endif
|
||||
|
||||
#ifndef TX_NULL
|
||||
#define TX_NULL 80
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int buffer_len;
|
||||
char *buffer;
|
||||
int *d2_perm;
|
||||
} rm_turbo_t;
|
||||
|
||||
int rm_turbo_tx(char *input, char *output, int in_len, int out_len);
|
||||
int rm_turbo_rx(float *input, float *output, int in_len, int out_len);
|
||||
int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
|
||||
void rm_turbo_free(rm_turbo_t *q);
|
||||
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx);
|
||||
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
rm_turbo_t q;
|
||||
struct rm_turbo_init {
|
||||
int direction;
|
||||
} init;
|
||||
|
@ -47,6 +60,7 @@ typedef struct {
|
|||
struct rm_turbo_ctrl_in {
|
||||
int E;
|
||||
int S;
|
||||
int rv_idx;
|
||||
} ctrl_in;
|
||||
void *output;
|
||||
int out_len;
|
||||
|
|
|
@ -34,14 +34,14 @@
|
|||
#define NROWS_MAX NCOLS
|
||||
#define RATE 3
|
||||
|
||||
unsigned char RM_PERM_CC[NCOLS] =
|
||||
unsigned char RM_PERM_TC[NCOLS] =
|
||||
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
|
||||
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
|
||||
unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
|
||||
unsigned char RM_PERM_TC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
|
||||
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
|
||||
31, 15 };
|
||||
|
||||
int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
|
||||
int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
|
||||
|
||||
char tmp[RATE * NCOLS * NROWS_MAX];
|
||||
int nrows, ndummy, K_p;
|
||||
|
@ -64,10 +64,10 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
|
|||
for (s = 0; s < 3; s++) {
|
||||
for (j = 0; j < NCOLS; j++) {
|
||||
for (i = 0; i < nrows; i++) {
|
||||
if (i*NCOLS + RM_PERM_CC[j] < ndummy) {
|
||||
if (i*NCOLS + RM_PERM_TC[j] < ndummy) {
|
||||
tmp[k] = TX_NULL;
|
||||
} else {
|
||||
tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s];
|
||||
tmp[k] = input[(i*NCOLS + RM_PERM_TC[j]-ndummy)*3+s];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
|
|||
/* Undoes Convolutional Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
|
||||
*/
|
||||
int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
|
||||
int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
|
||||
|
||||
int nrows, ndummy, K_p;
|
||||
int i, j, k;
|
||||
|
@ -125,7 +125,7 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
|
|||
d_i = (j % K_p) / nrows;
|
||||
d_j = (j % K_p) % nrows;
|
||||
|
||||
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
|
||||
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
|
||||
if (tmp[j] == RX_NULL) {
|
||||
tmp[j] = input[k];
|
||||
} else if (input[k] != RX_NULL) {
|
||||
|
@ -144,7 +144,7 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
|
|||
d_i = (i + ndummy) / NCOLS;
|
||||
d_j = (i + ndummy) % NCOLS;
|
||||
for (j = 0; j < RATE; j++) {
|
||||
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
|
||||
float o = tmp[K_p * j + RM_PERM_TC_INV[d_j] * nrows
|
||||
+ d_i];
|
||||
if (o != RX_NULL) {
|
||||
output[i * RATE + j] = o;
|
||||
|
|
|
@ -27,87 +27,135 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte/fec/rm_turbo.h"
|
||||
|
||||
#define NCOLS 32
|
||||
#define NROWS_MAX NCOLS
|
||||
#define RATE 3
|
||||
|
||||
unsigned char RM_PERM_CC[NCOLS] =
|
||||
unsigned char RM_PERM_TC[NCOLS] =
|
||||
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9,
|
||||
25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
|
||||
|
||||
unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
|
||||
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
|
||||
31, 15 };
|
||||
|
||||
int rm_turbo_tx(char *input, char *output, int in_len, int out_len) {
|
||||
|
||||
char tmp[RATE * NCOLS * NROWS_MAX];
|
||||
int nrows, ndummy, K_p;
|
||||
|
||||
int i, j, k, s;
|
||||
|
||||
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Input too large. Max input length is %d\n",
|
||||
RATE * NCOLS * NROWS_MAX);
|
||||
int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
|
||||
q->buffer_len = buffer_len;
|
||||
q->buffer = malloc(buffer_len * sizeof(float));
|
||||
if (!q->buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1);
|
||||
if (!q->d2_perm) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rm_turbo_free(rm_turbo_t *q) {
|
||||
if (q->buffer) {
|
||||
free(q->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Turbo Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
|
||||
*
|
||||
* TODO: Soft buffer size limitation according to UE category
|
||||
*/
|
||||
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) {
|
||||
|
||||
char *tmp = (char*) q->buffer;
|
||||
int nrows, ndummy, K_p;
|
||||
|
||||
int i, j, k, s, kidx, N_cb, k0;
|
||||
|
||||
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
|
||||
K_p = nrows * NCOLS;
|
||||
if (3 * K_p > q->buffer_len) {
|
||||
fprintf(stderr,
|
||||
"Input too large. Max input length including dummy bits is %d\n",
|
||||
q->buffer_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ndummy = K_p - in_len / RATE;
|
||||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
|
||||
/* Sub-block interleaver 5.1.4.1.1 */
|
||||
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
|
||||
k = 0;
|
||||
for (s = 0; s < 3; s++) {
|
||||
for (s = 0; s < 2; s++) {
|
||||
for (j = 0; j < NCOLS; j++) {
|
||||
for (i = 0; i < nrows; i++) {
|
||||
if (i * NCOLS + RM_PERM_CC[j] < ndummy) {
|
||||
tmp[k] = TX_NULL;
|
||||
if (s == 0) {
|
||||
kidx = k%K_p;
|
||||
} else {
|
||||
tmp[k] = input[(i * NCOLS + RM_PERM_CC[j] - ndummy) * 3 + s];
|
||||
kidx = K_p + 2 * (k%K_p);
|
||||
}
|
||||
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
|
||||
tmp[kidx] = TX_NULL;
|
||||
} else {
|
||||
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Bit collection, selection and transmission 5.1.4.1.2 */
|
||||
|
||||
// d_k^(2) goes through special permutation
|
||||
for (k = 0; k < K_p; k++) {
|
||||
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
|
||||
if ((kidx - ndummy) < 0) {
|
||||
tmp[K_p + 2 * k + 1] = TX_NULL;
|
||||
} else {
|
||||
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Bit selection and transmission 5.1.4.1.2 */
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
|
||||
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
|
||||
* rv_idx + 2);
|
||||
k = 0;
|
||||
j = 0;
|
||||
|
||||
while (k < out_len) {
|
||||
if (tmp[j] != TX_NULL) {
|
||||
output[k] = tmp[j];
|
||||
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
|
||||
output[k] = tmp[(k0 + j) % N_cb];
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
if (j == RATE * K_p) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Undoes Convolutional Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
|
||||
/* Undoes Turbo Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
|
||||
*/
|
||||
int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
|
||||
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) {
|
||||
|
||||
int nrows, ndummy, K_p;
|
||||
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
|
||||
int i, j, k;
|
||||
int d_i, d_j;
|
||||
bool isdummy;
|
||||
|
||||
float tmp[RATE * NCOLS * NROWS_MAX];
|
||||
float *tmp = (float*) q->buffer;
|
||||
|
||||
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Output too large. Max output length is %d\n",
|
||||
RATE * NCOLS * NROWS_MAX);
|
||||
K_p = nrows * NCOLS;
|
||||
if (3 * K_p > q->buffer_len) {
|
||||
fprintf(stderr,
|
||||
"Input too large. Max input length including dummy bits is %d\n",
|
||||
q->buffer_len);
|
||||
return -1;
|
||||
}
|
||||
K_p = nrows * NCOLS;
|
||||
|
||||
ndummy = K_p - out_len / RATE;
|
||||
if (ndummy < 0) {
|
||||
|
@ -119,24 +167,51 @@ int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
|
|||
}
|
||||
|
||||
/* Undo bit collection. Account for dummy bits */
|
||||
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
|
||||
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
|
||||
* rv_idx + 2);
|
||||
k = 0;
|
||||
j = 0;
|
||||
while (k < in_len) {
|
||||
d_i = (j % K_p) / nrows;
|
||||
d_j = (j % K_p) % nrows;
|
||||
jp = (k0 + j) % N_cb;
|
||||
|
||||
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
|
||||
if (tmp[j] == RX_NULL) {
|
||||
tmp[j] = input[k];
|
||||
if (jp == 32 || jp == 95 || jp == 0) {
|
||||
i=0;
|
||||
}
|
||||
|
||||
if (jp < K_p || !(jp%2)) {
|
||||
if (jp >= K_p) {
|
||||
d_i = ((jp-K_p) / 2) / nrows;
|
||||
d_j = ((jp-K_p) / 2) % nrows;
|
||||
} else {
|
||||
d_i = jp / nrows;
|
||||
d_j = jp % nrows;
|
||||
}
|
||||
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
|
||||
isdummy = false;
|
||||
} else {
|
||||
isdummy = true;
|
||||
}
|
||||
} else {
|
||||
int jpp = (jp-K_p-1)/2;
|
||||
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
|
||||
q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer
|
||||
if ((kidx - ndummy) < 0) {
|
||||
isdummy = true;
|
||||
} else {
|
||||
isdummy = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isdummy) {
|
||||
if (tmp[jp] == RX_NULL) {
|
||||
tmp[jp] = input[k];
|
||||
} else if (input[k] != RX_NULL) {
|
||||
tmp[j] += input[k]; /* soft combine LLRs */
|
||||
tmp[jp] += input[k]; /* soft combine LLRs */
|
||||
}
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
if (j == RATE * K_p) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* interleaving and bit selection */
|
||||
|
@ -144,7 +219,13 @@ int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
|
|||
d_i = (i + ndummy) / NCOLS;
|
||||
d_j = (i + ndummy) % NCOLS;
|
||||
for (j = 0; j < RATE; j++) {
|
||||
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i];
|
||||
if (j != 2) {
|
||||
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
|
||||
} else {
|
||||
// use the saved permuatation function to avoid computing the inverse
|
||||
kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1;
|
||||
}
|
||||
float o = tmp[kidx];
|
||||
if (o != RX_NULL) {
|
||||
output[i * RATE + j] = o;
|
||||
} else {
|
||||
|
@ -155,26 +236,27 @@ int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** High-level API */
|
||||
|
||||
int rm_turbo_initialize(rm_turbo_hl* h) {
|
||||
|
||||
return 0;
|
||||
return rm_turbo_init(&h->q, 7000);
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) basis */
|
||||
int rm_turbo_work(rm_turbo_hl* hl) {
|
||||
if (hl->init.direction) {
|
||||
//rm_turbo_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S);
|
||||
hl->out_len = hl->ctrl_in.S;
|
||||
} else {
|
||||
rm_turbo_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E);
|
||||
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx);
|
||||
hl->out_len = hl->ctrl_in.E;
|
||||
} else {
|
||||
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx);
|
||||
hl->out_len = hl->ctrl_in.S;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rm_turbo_stop(rm_turbo_hl* hl) {
|
||||
rm_turbo_free(&hl->q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,304 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lte/fec/permute.h"
|
||||
|
||||
#include "lte/fec/turbodecoder.h"
|
||||
|
||||
|
||||
void compute_beta(llr_t *beta, llr_t *data, llr_t *parity, int long_cb, int dec) {
|
||||
llr_t m_b0, m_b1, m_b2, m_b3, m_b4, m_b5, m_b6, m_b7;
|
||||
llr_t new0, new1, new2, new3, new4, new5, new6, new7;
|
||||
llr_t old0, old1, old2, old3, old4, old5, old6, old7;
|
||||
|
||||
llr_t x, y, xy;
|
||||
int k;
|
||||
int end = long_cb + RATE;
|
||||
|
||||
old0 = beta[8 * (end) + 0];
|
||||
old1 = beta[8 * (end) + 1];
|
||||
old2 = beta[8 * (end) + 2];
|
||||
old3 = beta[8 * (end) + 3];
|
||||
old4 = beta[8 * (end) + 4];
|
||||
old5 = beta[8 * (end) + 5];
|
||||
old6 = beta[8 * (end) + 6];
|
||||
old7 = beta[8 * (end) + 7];
|
||||
|
||||
for (k = end - 1; k >= 0; k--) {
|
||||
if (k > long_cb - 1) {
|
||||
if (dec == 1) {
|
||||
x = data[RATE * (long_cb ) + NINPUTS * (k - long_cb)];
|
||||
y = data[RATE * (long_cb ) + NINPUTS * (k - long_cb) + 1];
|
||||
} else {
|
||||
x = data[RATE * (long_cb ) + NINPUTS * RATE + NINPUTS * (k - long_cb)];
|
||||
y = data[RATE * (long_cb ) + NINPUTS * RATE + NINPUTS * (k - long_cb) + 1];
|
||||
}
|
||||
} else {
|
||||
x = data[RATE * k];
|
||||
y = parity[RATE * k];
|
||||
}
|
||||
xy = x + y;
|
||||
|
||||
m_b0 = old4 + xy;
|
||||
m_b1 = old4;
|
||||
m_b2 = old5 + y;
|
||||
m_b3 = old5 + x;
|
||||
m_b4 = old6 + x;
|
||||
m_b5 = old6 + y;
|
||||
m_b6 = old7;
|
||||
m_b7 = old7 + xy;
|
||||
|
||||
new0 = old0;
|
||||
new1 = old0 + xy;
|
||||
new2 = old1 + x;
|
||||
new3 = old1 + y;
|
||||
new4 = old2 + y;
|
||||
new5 = old2 + x;
|
||||
new6 = old3 + xy;
|
||||
new7 = old3;
|
||||
|
||||
if (m_b0 > new0) new0 = m_b0;
|
||||
beta[8 * k + 0] = new0;
|
||||
old0 = new0;
|
||||
|
||||
if (m_b1 > new1) new1 = m_b1;
|
||||
beta[8 * k + 1] = new1;
|
||||
old1 = new1;
|
||||
|
||||
if (m_b2 > new2) new2 = m_b2;
|
||||
beta[8 * k + 2] = new2;
|
||||
old2 = new2;
|
||||
|
||||
if (m_b3 > new3) new3 = m_b3;
|
||||
beta[8 * k + 3] = new3;
|
||||
old3 = new3;
|
||||
|
||||
if (m_b4 > new4) new4 = m_b4;
|
||||
beta[8 * k + 4] = new4;
|
||||
old4 = new4;
|
||||
|
||||
if (m_b5 > new5) new5 = m_b5;
|
||||
beta[8 * k + 5] = new5;
|
||||
old5 = new5;
|
||||
|
||||
if (m_b6 > new6) new6 = m_b6;
|
||||
beta[8 * k + 6] = new6;
|
||||
old6 = new6;
|
||||
|
||||
if (m_b7 > new7) new7 = m_b7;
|
||||
beta[8 * k + 7] = new7;
|
||||
old7 = new7;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void compute_alfa(llr_t *alfa, llr_t *beta, llr_t *data, llr_t *parity, llr_t *output, int long_cb, int dec) {
|
||||
llr_t m_b0, m_b1, m_b2, m_b3, m_b4, m_b5, m_b6, m_b7;
|
||||
llr_t new0, new1, new2, new3, new4, new5, new6, new7;
|
||||
llr_t old0, old1, old2, old3, old4, old5, old6, old7;
|
||||
llr_t max1_0, max1_1, max1_2, max1_3, max1_4, max1_5, max1_6, max1_7;
|
||||
llr_t max0_0, max0_1, max0_2, max0_3, max0_4, max0_5, max0_6, max0_7;
|
||||
llr_t m1, m0;
|
||||
llr_t x, y, xy;
|
||||
llr_t out;
|
||||
int k;
|
||||
int end = long_cb;
|
||||
|
||||
old0 = alfa[0];
|
||||
old1 = alfa[1];
|
||||
old2 = alfa[2];
|
||||
old3 = alfa[3];
|
||||
old4 = alfa[4];
|
||||
old5 = alfa[5];
|
||||
old6 = alfa[6];
|
||||
old7 = alfa[7];
|
||||
|
||||
for (k = 1; k < end + 1; k++) {
|
||||
x = data[RATE * (k - 1)];
|
||||
y = parity[RATE * (k - 1)];
|
||||
|
||||
xy = x + y;
|
||||
|
||||
m_b0 = old0;
|
||||
m_b1 = old3 + y;
|
||||
m_b2 = old4 + y;
|
||||
m_b3 = old7;
|
||||
m_b4 = old1;
|
||||
m_b5 = old2 + y;
|
||||
m_b6 = old5 + y;
|
||||
m_b7 = old6;
|
||||
|
||||
new0 = old1 + xy;
|
||||
new1 = old2 + x;
|
||||
new2 = old5 + x;
|
||||
new3 = old6 + xy;
|
||||
new4 = old0 + xy;
|
||||
new5 = old3 + x;
|
||||
new6 = old4 + x;
|
||||
new7 = old7 + xy;
|
||||
|
||||
max0_0 = m_b0 + beta[8 * k + 0];
|
||||
max0_1 = m_b1 + beta[8 * k + 1];
|
||||
max0_2 = m_b2 + beta[8 * k + 2];
|
||||
max0_3 = m_b3 + beta[8 * k + 3];
|
||||
max0_4 = m_b4 + beta[8 * k + 4];
|
||||
max0_5 = m_b5 + beta[8 * k + 5];
|
||||
max0_6 = m_b6 + beta[8 * k + 6];
|
||||
max0_7 = m_b7 + beta[8 * k + 7];
|
||||
|
||||
max1_0 = new0 + beta[8 * k + 0];
|
||||
max1_1 = new1 + beta[8 * k + 1];
|
||||
max1_2 = new2 + beta[8 * k + 2];
|
||||
max1_3 = new3 + beta[8 * k + 3];
|
||||
max1_4 = new4 + beta[8 * k + 4];
|
||||
max1_5 = new5 + beta[8 * k + 5];
|
||||
max1_6 = new6 + beta[8 * k + 6];
|
||||
max1_7 = new7 + beta[8 * k + 7];
|
||||
|
||||
m1 = max1_0;
|
||||
if (max1_1 > m1) m1 = max1_1;
|
||||
if (max1_2 > m1) m1 = max1_2;
|
||||
if (max1_3 > m1) m1 = max1_3;
|
||||
if (max1_4 > m1) m1 = max1_4;
|
||||
if (max1_5 > m1) m1 = max1_5;
|
||||
if (max1_6 > m1) m1 = max1_6;
|
||||
if (max1_7 > m1) m1 = max1_7;
|
||||
|
||||
m0 = max0_0;
|
||||
if (max0_1 > m0) m0 = max0_1;
|
||||
if (max0_2 > m0) m0 = max0_2;
|
||||
if (max0_3 > m0) m0 = max0_3;
|
||||
if (max0_4 > m0) m0 = max0_4;
|
||||
if (max0_5 > m0) m0 = max0_5;
|
||||
if (max0_6 > m0) m0 = max0_6;
|
||||
if (max0_7 > m0) m0 = max0_7;
|
||||
|
||||
|
||||
if (m_b0 > new0) new0 = m_b0;
|
||||
old0 = new0;
|
||||
|
||||
if (m_b1 > new1) new1 = m_b1;
|
||||
old1 = new1;
|
||||
|
||||
if (m_b2 > new2) new2 = m_b2;
|
||||
old2 = new2;
|
||||
|
||||
if (m_b3 > new3) new3 = m_b3;
|
||||
old3 = new3;
|
||||
|
||||
if (m_b4 > new4) new4 = m_b4;
|
||||
old4 = new4;
|
||||
|
||||
if (m_b5 > new5) new5 = m_b5;
|
||||
old5 = new5;
|
||||
|
||||
if (m_b6 > new6) new6 = m_b6;
|
||||
old6 = new6;
|
||||
|
||||
if (m_b7 > new7) new7 = m_b7;
|
||||
old7 = new7;
|
||||
|
||||
out = m1 - m0;
|
||||
|
||||
/*
|
||||
if (dec == 2) {
|
||||
if (abs(out) < HALT_min) {
|
||||
HALT_min = abs(out);
|
||||
}
|
||||
}
|
||||
*/
|
||||
output[k - 1] = out;
|
||||
}
|
||||
|
||||
alfa[0] = old0;
|
||||
alfa[1] = old1;
|
||||
alfa[2] = old2;
|
||||
alfa[3] = old3;
|
||||
alfa[4] = old4;
|
||||
alfa[5] = old5;
|
||||
alfa[6] = old6;
|
||||
alfa[7] = old7;
|
||||
}
|
||||
|
||||
void DEC_RSC(tdec_t *q, llr_t *input, llr_t *output, int *per, int dec) {
|
||||
int k;
|
||||
int i;
|
||||
int last_state = q->long_cb + RATE;
|
||||
|
||||
/** Initialize alfa states */
|
||||
q->alfa[0] = 0;
|
||||
for (k = 1; k < NUMSTATES; k++) {
|
||||
q->alfa[k] = -INF;
|
||||
}
|
||||
|
||||
q->beta[last_state * NUMSTATES] = 0;
|
||||
for (k = 1; k < NUMSTATES; k++)
|
||||
q->beta[last_state * NUMSTATES + k] = -INF;
|
||||
|
||||
/* copy data temporal buffer (to allow fastest loops)*/
|
||||
memcpy(q->data, input, RATE * last_state * sizeof (llr_t));
|
||||
|
||||
q->parity = &input[dec];
|
||||
|
||||
if (dec == 1) {
|
||||
for (i = 0; i < last_state; i++) {
|
||||
q->data[RATE * i] += q->W[i ];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < last_state; i++) {
|
||||
q->data[RATE * i] = q->LLR1[per[i ]] - q->W[per[i ]];
|
||||
}
|
||||
}
|
||||
|
||||
compute_beta(q->beta, q->data, &input[dec], q->long_cb, dec);
|
||||
compute_alfa(q->alfa, q->beta, q->data, &input[dec], output, q->long_cb, dec);
|
||||
}
|
||||
|
||||
void decide(llr_t *LLR2, char *output, int *desper, int long_cb) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < long_cb; i++)
|
||||
output[i] = (LLR2[desper[i]] > 0) ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
void update_W(llr_t *W, llr_t *LLR1, llr_t *LLR2, int *desper, int long_cb) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < long_cb; i++) {
|
||||
W[i] += LLR2[desper[i]] - LLR1[i];
|
||||
}
|
||||
}
|
||||
|
||||
int turbo_decoder(tdec_t *q, llr_t *input, char *output, int *halt) {
|
||||
|
||||
int i;
|
||||
long halt_mean=0;
|
||||
int stop=0;
|
||||
q->iteration = 0;
|
||||
|
||||
|
||||
if (ComputePermutation(&q->permuta, q->long_cb,PER_UMTS)<0)
|
||||
return -1;
|
||||
|
||||
memset(q->W, 0, sizeof (llr_t) * q->long_cb);
|
||||
|
||||
do {
|
||||
if (q->iteration)
|
||||
update_W(q->W, q->LLR1, q->LLR2, q->permuta.DESPER, q->long_cb);
|
||||
|
||||
|
||||
DEC_RSC(q, input, q->LLR1, q->permuta.PER, 1);
|
||||
|
||||
DEC_RSC(q, input, q->LLR2, q->permuta.PER, 2);
|
||||
|
||||
q->iteration++;
|
||||
|
||||
} while (q->iteration < q->max_iterations && stop==0);
|
||||
decide(q->LLR2, output, q->permuta.DESPER, q->long_cb);
|
||||
|
||||
return q->iteration;
|
||||
}
|
||||
|
|
@ -27,6 +27,9 @@
|
|||
ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
|
||||
TARGET_LINK_LIBRARIES(rm_conv_test lte)
|
||||
|
||||
ADD_EXECUTABLE(rm_turbo_test rm_turbo_test.c)
|
||||
TARGET_LINK_LIBRARIES(rm_turbo_test lte)
|
||||
|
||||
ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920)
|
||||
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480)
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ int main(int argc, char **argv) {
|
|||
bits[i] = rand()%2;
|
||||
}
|
||||
|
||||
if (rm_conv_tx(bits, rm_bits, nof_tx_bits, nof_rx_bits)) {
|
||||
if (rm_conv_tx(bits, nof_tx_bits, rm_bits, nof_rx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ int main(int argc, char **argv) {
|
|||
rm_symbols[i] = rm_bits[i]?1:-1;
|
||||
}
|
||||
|
||||
if (rm_conv_rx(rm_symbols, unrm_symbols, nof_rx_bits, nof_tx_bits)) {
|
||||
if (rm_conv_rx(rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,14 +37,15 @@
|
|||
#include "lte.h"
|
||||
|
||||
int nof_tx_bits=-1, nof_rx_bits=-1;
|
||||
int rv_idx = 0;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits\n", prog);
|
||||
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits [-i rv_idx]\n", prog);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "tr")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "tri")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
nof_tx_bits = atoi(argv[optind]);
|
||||
|
@ -52,6 +53,9 @@ void parse_args(int argc, char **argv) {
|
|||
case 'r':
|
||||
nof_rx_bits = atoi(argv[optind]);
|
||||
break;
|
||||
case 'i':
|
||||
rv_idx = atoi(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
|
@ -72,6 +76,7 @@ int main(int argc, char **argv) {
|
|||
char *bits, *rm_bits;
|
||||
float *rm_symbols, *unrm_symbols;
|
||||
int nof_errors;
|
||||
rm_turbo_t rm_turbo;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
|
@ -100,36 +105,38 @@ int main(int argc, char **argv) {
|
|||
bits[i] = rand()%2;
|
||||
}
|
||||
|
||||
if (rm_conv_tx(bits, rm_bits, nof_tx_bits, nof_rx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
rm_turbo_init(&rm_turbo, 1000);
|
||||
|
||||
rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
|
||||
|
||||
for (i=0;i<nof_rx_bits;i++) {
|
||||
rm_symbols[i] = rm_bits[i]?1:-1;
|
||||
rm_symbols[i] = (float) rm_bits[i]?1:-1;
|
||||
}
|
||||
|
||||
if (rm_conv_rx(rm_symbols, unrm_symbols, nof_rx_bits, nof_tx_bits)) {
|
||||
exit(-1);
|
||||
}
|
||||
rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx);
|
||||
|
||||
nof_errors = 0;
|
||||
for (i=0;i<nof_tx_bits;i++) {
|
||||
if ((unrm_symbols[i] > 0) != bits[i]) {
|
||||
nof_errors++;
|
||||
printf("%.2f != %d\n", unrm_symbols[i], bits[i]);
|
||||
}
|
||||
}
|
||||
if (nof_rx_bits > nof_tx_bits) {
|
||||
if (nof_errors) {
|
||||
printf("nof_errors=%d\n", nof_errors);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
rm_turbo_free(&rm_turbo);
|
||||
|
||||
free(bits);
|
||||
free(rm_bits);
|
||||
free(rm_symbols);
|
||||
free(unrm_symbols);
|
||||
|
||||
if (nof_tx_bits >= nof_rx_bits) {
|
||||
if (nof_errors) {
|
||||
printf("nof_errors=%d\n", nof_errors);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Ok\n");
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -382,7 +382,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
|
|||
}
|
||||
|
||||
/* unrate matching */
|
||||
rm_conv_rx(q->temp, q->pbch_rm_f, 4 * nof_bits, 120);
|
||||
rm_conv_rx(q->temp, 4 * nof_bits, q->pbch_rm_f, 120);
|
||||
|
||||
/* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */
|
||||
for (j=0;j<120;j++) {
|
||||
|
@ -531,7 +531,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
|
|||
|
||||
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
|
||||
|
||||
rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits);
|
||||
rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E,
|
|||
}
|
||||
*/
|
||||
/* unrate matching */
|
||||
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
|
||||
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
|
||||
|
||||
DEBUG("Viterbi input: ", 0);
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
|
@ -543,7 +543,7 @@ void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned s
|
|||
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
|
||||
}
|
||||
|
||||
rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E);
|
||||
rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
|
||||
}
|
||||
|
||||
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
|
||||
|
|
Loading…
Reference in New Issue