Fixed B210 USRP Clock issue. Added Turbo Rate matching

master
ismagom 11 years ago
parent 6fe5a05952
commit eb52aeb1ab

@ -100,12 +100,14 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
return 0; return 0;
} }
int cuhd_open(char *args, void **h) { int cuhd_open(char *args, void **h) {
cuhd_handler* handler = new cuhd_handler(); cuhd_handler* handler = new cuhd_handler();
std::string _args=std::string(args); std::string _args=std::string(args);
handler->usrp = uhd::usrp::multi_usrp::make(_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"); handler->usrp->set_clock_source("internal");
std::string otw, cpu; std::string otw, cpu;

@ -57,7 +57,7 @@
#define NOF_PORTS 2 #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 max_track_lost = 20, nof_frames = -1;
int track_len=300; int track_len=300;
char *input_file_name = NULL; char *input_file_name = NULL;

@ -33,8 +33,8 @@
#define TX_NULL 80 #define TX_NULL 80
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);
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);
/* High-level API */ /* High-level API */

@ -26,19 +26,32 @@
*/ */
#ifndef RM_CONV_ #ifndef RM_TURBO_
#define RM_CONV_ #define RM_TURBO_
#ifndef RX_NULL
#define RX_NULL 10000 #define RX_NULL 10000
#endif
#ifndef TX_NULL
#define TX_NULL 80 #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_init(rm_turbo_t *q, int max_codeblock_len);
int rm_turbo_rx(float *input, float *output, int in_len, int out_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 */ /* High-level API */
typedef struct { typedef struct {
rm_turbo_t q;
struct rm_turbo_init { struct rm_turbo_init {
int direction; int direction;
} init; } init;
@ -47,6 +60,7 @@ typedef struct {
struct rm_turbo_ctrl_in { struct rm_turbo_ctrl_in {
int E; int E;
int S; int S;
int rv_idx;
} ctrl_in; } ctrl_in;
void *output; void *output;
int out_len; int out_len;

@ -34,14 +34,14 @@
#define NROWS_MAX NCOLS #define NROWS_MAX NCOLS
#define RATE 3 #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, { 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 }; 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, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
31, 15 }; 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]; char tmp[RATE * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p; 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 (s = 0; s < 3; s++) {
for (j = 0; j < NCOLS; j++) { for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) { 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; tmp[k] = TX_NULL;
} else { } 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++; k++;
} }
@ -93,7 +93,7 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
/* Undoes Convolutional Code Rate Matching. /* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2 * 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 nrows, ndummy, K_p;
int i, j, k; 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_i = (j % K_p) / nrows;
d_j = (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) { if (tmp[j] == RX_NULL) {
tmp[j] = input[k]; tmp[j] = input[k];
} else if (input[k] != RX_NULL) { } 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_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS; d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) { 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]; + d_i];
if (o != RX_NULL) { if (o != RX_NULL) {
output[i * RATE + j] = o; output[i * RATE + j] = o;

@ -27,87 +27,135 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include "lte/fec/rm_turbo.h" #include "lte/fec/rm_turbo.h"
#define NCOLS 32 #define NCOLS 32
#define NROWS_MAX NCOLS #define NROWS_MAX NCOLS
#define RATE 3 #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, { 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 }; 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, int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7, q->buffer_len = buffer_len;
31, 15 }; 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;
}
int rm_turbo_tx(char *input, char *output, int in_len, int out_len) { 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[RATE * NCOLS * NROWS_MAX]; char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p; int nrows, ndummy, K_p;
int i, j, k, s; int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1; nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) { K_p = nrows * NCOLS;
fprintf(stderr, "Input too large. Max input length is %d\n", if (3 * K_p > q->buffer_len) {
RATE * NCOLS * NROWS_MAX); fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1; return -1;
} }
K_p = nrows * NCOLS;
ndummy = K_p - in_len / RATE; ndummy = K_p - in_len / RATE;
if (ndummy < 0) { if (ndummy < 0) {
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; k = 0;
for (s = 0; s < 3; s++) { for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) { for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) { for (i = 0; i < nrows; i++) {
if (i * NCOLS + RM_PERM_CC[j] < ndummy) { if (s == 0) {
tmp[k] = TX_NULL; kidx = k%K_p;
} else {
kidx = K_p + 2 * (k%K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else { } else {
tmp[k] = input[(i * NCOLS + RM_PERM_CC[j] - ndummy) * 3 + s]; tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
} }
k++; 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; k = 0;
j = 0; j = 0;
while (k < out_len) { while (k < out_len) {
if (tmp[j] != TX_NULL) { if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[j]; output[k] = tmp[(k0 + j) % N_cb];
k++; k++;
} }
j++; j++;
if (j == RATE * K_p) {
j = 0;
}
} }
return 0; return 0;
} }
/* Undoes Convolutional Code Rate Matching. /* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2 * 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 i, j, k;
int d_i, d_j; 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; nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) { K_p = nrows * NCOLS;
fprintf(stderr, "Output too large. Max output length is %d\n", if (3 * K_p > q->buffer_len) {
RATE * NCOLS * NROWS_MAX); fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1; return -1;
} }
K_p = nrows * NCOLS;
ndummy = K_p - out_len / RATE; ndummy = K_p - out_len / RATE;
if (ndummy < 0) { 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 */ /* 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; k = 0;
j = 0; j = 0;
while (k < in_len) { while (k < in_len) {
d_i = (j % K_p) / nrows; jp = (k0 + j) % N_cb;
d_j = (j % K_p) % nrows;
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) { if (jp == 32 || jp == 95 || jp == 0) {
if (tmp[j] == RX_NULL) { i=0;
tmp[j] = input[k]; }
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) { } else if (input[k] != RX_NULL) {
tmp[j] += input[k]; /* soft combine LLRs */ tmp[jp] += input[k]; /* soft combine LLRs */
} }
k++; k++;
} }
j++; j++;
if (j == RATE * K_p) {
j = 0;
}
} }
/* interleaving and bit selection */ /* 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_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS; d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) { 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) { if (o != RX_NULL) {
output[i * RATE + j] = o; output[i * RATE + j] = o;
} else { } else {
@ -155,26 +236,27 @@ int rm_turbo_rx(float *input, float *output, int in_len, int out_len) {
return 0; return 0;
} }
/** High-level API */ /** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) { int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
return 0;
} }
/** This function can be called in a subframe (1ms) basis */ /** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) { int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) { if (hl->init.direction) {
//rm_turbo_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S); 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.S;
} else {
rm_turbo_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E);
hl->out_len = hl->ctrl_in.E; 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; return 0;
} }
int rm_turbo_stop(rm_turbo_hl* hl) { int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0; 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) ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
TARGET_LINK_LIBRARIES(rm_conv_test lte) 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_1 rm_conv_test -t 480 -r 1920)
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480) 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; 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); exit(-1);
} }
@ -108,7 +108,7 @@ int main(int argc, char **argv) {
rm_symbols[i] = rm_bits[i]?1:-1; 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); exit(-1);
} }

@ -37,14 +37,15 @@
#include "lte.h" #include "lte.h"
int nof_tx_bits=-1, nof_rx_bits=-1; int nof_tx_bits=-1, nof_rx_bits=-1;
int rv_idx = 0;
void usage(char *prog) { 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) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "tr")) != -1) { while ((opt = getopt(argc, argv, "tri")) != -1) {
switch (opt) { switch (opt) {
case 't': case 't':
nof_tx_bits = atoi(argv[optind]); nof_tx_bits = atoi(argv[optind]);
@ -52,6 +53,9 @@ void parse_args(int argc, char **argv) {
case 'r': case 'r':
nof_rx_bits = atoi(argv[optind]); nof_rx_bits = atoi(argv[optind]);
break; break;
case 'i':
rv_idx = atoi(argv[optind]);
break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -72,6 +76,7 @@ int main(int argc, char **argv) {
char *bits, *rm_bits; char *bits, *rm_bits;
float *rm_symbols, *unrm_symbols; float *rm_symbols, *unrm_symbols;
int nof_errors; int nof_errors;
rm_turbo_t rm_turbo;
parse_args(argc, argv); parse_args(argc, argv);
@ -100,36 +105,38 @@ int main(int argc, char **argv) {
bits[i] = rand()%2; bits[i] = rand()%2;
} }
if (rm_conv_tx(bits, rm_bits, nof_tx_bits, nof_rx_bits)) { rm_turbo_init(&rm_turbo, 1000);
exit(-1);
} rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
for (i=0;i<nof_rx_bits;i++) { 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)) { rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx);
exit(-1);
}
nof_errors = 0; nof_errors = 0;
for (i=0;i<nof_tx_bits;i++) { for (i=0;i<nof_tx_bits;i++) {
if ((unrm_symbols[i] > 0) != bits[i]) { if ((unrm_symbols[i] > 0) != bits[i]) {
nof_errors++; nof_errors++;
printf("%.2f != %d\n", unrm_symbols[i], bits[i]);
} }
} }
if (nof_rx_bits > nof_tx_bits) {
if (nof_errors) { rm_turbo_free(&rm_turbo);
printf("nof_errors=%d\n", nof_errors);
exit(-1);
}
}
free(bits); free(bits);
free(rm_bits); free(rm_bits);
free(rm_symbols); free(rm_symbols);
free(unrm_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"); printf("Ok\n");
exit(0); 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 */ /* 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 */ /* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */
for (j=0;j<120;j++) { 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); 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 */ /* 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); DEBUG("Viterbi input: ", 0);
if (VERBOSE_ISDEBUG()) { 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)); 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 /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission

Loading…
Cancel
Save