Merge pull request #49 from ismagom/master

Merge soft demodulation implementation improvement by marojevic
master
Ismael Gómez-Miguelez 10 years ago
commit 55c29ee9c7

@ -43,6 +43,7 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION)
@ -55,6 +56,9 @@ ENDIF()
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
ENDIF() ENDIF()
IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
ENDIF() ENDIF()

@ -40,12 +40,15 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t idx[2][6][32]; uint32_t idx[2][6][32];
uint32_t min_idx[2][64][6]; /* NEW: for each constellation point zone (2, 4, 16, 64 for BPSK, QPSK, 16QAM, 64QAM) the 2x(1, 2, 4, and 6 closest constellation points) for each bit, respectively. */
uint32_t d_idx[64][7]; /* NEW: for each constellation point zone (2, 4, 16, 64 for BPSK, QPSK, 16QAM, 64QAM) the 2, 3, 5 and 7 indices to constellation points that need to be computed for any recevied symbol modulated as BPSK, QPSK, 16QAM, and 64QAM, respectively. */
}soft_table_t; }soft_table_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
cf_t* symbol_table; // bit-to-symbol mapping cf_t* symbol_table; // bit-to-symbol mapping
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
uint32_t nsymbols; // number of modulation symbols uint32_t nsymbols; // number of modulation symbols
uint32_t nbits_x_symbol; // number of bits per symbol uint32_t nbits_x_symbol; // number of bits per symbol
}modem_table_t; }modem_table_t;

@ -35,7 +35,7 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) #define EXPAVERAGE(data, average, nframes) (((data) + (average) * (nframes)) / ((nframes) + 1))
/** Return the sum of all the elements */ /** Return the sum of all the elements */
@ -64,6 +64,9 @@ LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* substract two vectors z=x-y */ /* substract two vectors z=x-y */
LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len); LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len);
/* Square distance */
LIBLTE_API void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints);
/* scalar product */ /* scalar product */
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);

@ -58,8 +58,10 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int
q->table->symbol_table, q->table->soft_table.idx, q->sigma); q->table->symbol_table, q->table->soft_table.idx, q->sigma);
break; break;
case APPROX: case APPROX:
llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol, /* llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->sigma); q->table->symbol_table, q->table->soft_table.idx, q->sigma);
*/ llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->table->soft_table.d_idx, q->table->soft_table.min_idx, q->sigma);
break; break;
} }
return nsymbols*q->table->nbits_x_symbol; return nsymbols*q->table->nbits_x_symbol;

@ -34,6 +34,8 @@
#include "liblte/phy/modem/modem_table.h" #include "liblte/phy/modem/modem_table.h"
#include "lte_tables.h" #include "lte_tables.h"
void LLR_approx_params(const cf_t* table, soft_table_t *soft_table, int B);
/** /**
* Set the BPSK modulation table */ * Set the BPSK modulation table */
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod) void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
@ -53,6 +55,18 @@ void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */ /* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
soft_table->idx[0][0][0] = 0; soft_table->idx[0][0][0] = 0;
soft_table->idx[1][0][0] = 1; soft_table->idx[1][0][0] = 1;
/* set two matrices for LLR approx. calculation */
soft_table->min_idx[0][0][0] = 0;
soft_table->min_idx[0][1][0] = 0;
soft_table->min_idx[1][0][0] = 1;
soft_table->min_idx[1][1][0] = 1;
soft_table->d_idx[0][0] = 0;
soft_table->d_idx[0][1] = 1;
soft_table->d_idx[1][0] = 0;
soft_table->d_idx[1][1] = 1;
} }
/** /**
@ -91,6 +105,8 @@ void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
soft_table->idx[1][0][1] = 3; soft_table->idx[1][0][1] = 3;
soft_table->idx[1][1][0] = 1; soft_table->idx[1][1][0] = 1;
soft_table->idx[1][1][1] = 3; soft_table->idx[1][1][1] = 3;
LLR_approx_params(table, soft_table, 2); /* last param indicating B (bits per symbol) */
} }
/** /**
@ -156,6 +172,8 @@ void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_dem
soft_table->idx[0][3][i] = 2*i; soft_table->idx[0][3][i] = 2*i;
soft_table->idx[1][3][i] = 2*i+1; soft_table->idx[1][3][i] = 2*i+1;
} }
LLR_approx_params(table, soft_table, 4); /* last param indication B (bits per symbol) */
} }
/** /**
@ -277,4 +295,96 @@ void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_dem
soft_table->idx[0][5][i] = 2*i; soft_table->idx[0][5][i] = 2*i;
soft_table->idx[1][5][i] = 2*i+1; soft_table->idx[1][5][i] = 2*i+1;
} }
LLR_approx_params(table, soft_table, 6); /* last param indication modulation */
}
/* Precompute two tables for calculating the distances based on the received symbol location relative to the constellation points */
void LLR_approx_params(const cf_t* table, soft_table_t *soft_table, int B) {
int i, j, b, k;
float x, y, d0, d1, min_d0, min_d1;
int M, D;
uint32_t min_idx0[64][6], min_idx1[64][6];
uint32_t count;
int flag;
D = B+1; /* number of different distances to be computed */
//M = pow(2,B); /* number of constellation points */
switch (B) {
case 1: {M = 2; break;} /* BPSK */
case 2: {M = 4; break;} /* QPSK */
case 4: {M = 16; break;} /* 16QAM */
case 6: {M = 64; break;} /* 64QAM */
default: {M = 4; break;} /* QPSK */
}
for (i=0;i<M;i++) { /* constellation points */
for (b=0;b<B;b++) { /* bits per symbol */
min_d0 = 100;
min_d1 = 100;
for (j=0;j<M/2;j++) { /* half the symbols have a '0', the other half a '1' at any bit position of modulation symbol */
x = __real__ table[i] - __real__ table[soft_table->idx[0][b][j]];
y = __imag__ table[i] - __imag__ table[soft_table->idx[0][b][j]];
d0 = x*x + y*y;
if (d0 < min_d0) {
min_d0 = d0;
min_idx0[i][b] = soft_table->idx[0][b][j];
}
x = __real__ table[i] - __real__ table[soft_table->idx[1][b][j]];
y = __imag__ table[i] - __imag__ table[soft_table->idx[1][b][j]];
d1 = x*x + y*y;
if (d1 < min_d1) {
min_d1 = d1;
min_idx1[i][b] = soft_table->idx[1][b][j];
}
}
}
}
for (i=0;i<M;i++) {
for (j=0;j<D;j++) {
soft_table->d_idx[i][j] = -1; /* intialization */
}
}
for (i=0;i<M;i++) {
count = 0;
for (b=0;b<B;b++) { /* bit(b) = 0 */
flag = 0;
for (k=0;k<count;k++) {
if (min_idx0[i][b] == soft_table->d_idx[i][k]) {
soft_table->min_idx[0][i][b] = k;
flag = 1; /* no new entry to idxdx */
break;
}
}
if (flag == 0) { /* new entry to min and d_idx */
soft_table->d_idx[i][count] = min_idx0[i][b];
soft_table->min_idx[0][i][b] = count;
count++;
}
}
for (b=0;b<B;b++) { /* bit(b) = 1 */
flag = 0;
for (k=0;k<count;k++) {
if (min_idx1[i][b] == soft_table->d_idx[i][k]) {
soft_table->min_idx[1][i][b] = k;
flag = 1; /* no new entry to d_idx */
break;
}
}
if (flag == 0) { /* new entry to min and d_idx */
soft_table->d_idx[i][count] = min_idx1[i][b];
soft_table->min_idx[1][i][b] = count;
count++;
}
}
}
} }

@ -38,6 +38,14 @@
#define QAM64_LEVEL_3 5/sqrt(42) #define QAM64_LEVEL_3 5/sqrt(42)
#define QAM64_LEVEL_4 7/sqrt(42) #define QAM64_LEVEL_4 7/sqrt(42)
//////////////// NUEVO //////////////////////
/* HARD DEMODULATION Thresholds, necessary for obtaining the zone of received symbol for optimized LLR approx implementation */
#define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
//=========================================//
#define QAM64_LEVEL_x 2/sqrt(42) #define QAM64_LEVEL_x 2/sqrt(42)
/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the /* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the
* symbol from the bit sequence */ * symbol from the bit sequence */

@ -31,56 +31,560 @@
#include <math.h> #include <math.h>
#include <complex.h> #include <complex.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "soft_algs.h" #include "soft_algs.h"
#include "liblte/phy/utils/vector.h"
#define LLR_APPROX_USE_VOLK #define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
#ifdef LLR_APPROX_USE_VOLK typedef _Complex float cf_t;
void
llr_approx(const _Complex float *in, float *out, int N, int M, int B, // There are 3 implemenations: 1 - based on zones; 2 - using volk, 3 - straightforward C
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2) #define LLR_APPROX_IMPLEMENTATION 1
#if LLR_APPROX_IMPLEMENTATION == 1
float dd[10000][7]; // 7 distances that are needed to compute LLR approx for 64QAM
uint32_t zone[10000]; // Zone of received symbol with respect to grid of QAM constellation diagram
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QPSK(const cf_t * in, uint32_t * z, int N)
{ {
int i, s, b;
float num, den;
int change_sign = -1;
float x, y, d[64];
for (s = 0; s < N; s++) { /* recevied symbols */ int s;
/* Compute the distances squared d[i] between the received symbol and all constellation points */ float re, im;
for (i = 0; i < M; i++) {
x = __real__ in[s] - __real__ symbols[i]; for (s = 0; s < N; s++) {
y = __imag__ in[s] - __imag__ symbols[i];
d[i] = x * x + y * y; re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) { /* 1st Quadrand (upper-right) */
z[s] = 0;
} else { /* 4th Quadrand (lower-right) */
z[s] = 1;
}
} else {
if (im > 0) { /* 2nd Quadrand (upper-left) */
z[s] = 2;
} else { /* 3rd Quadrand (lower-left) */
z[s] = 3;
}
}
}
}
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QAM16(const cf_t * in, uint32_t * z, int N)
{
int s;
float re, im;
for (s = 0; s < N; s++) {
re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) { /* 1st Quadrand (upper-right) */
if (re > QAM16_THRESHOLD) {
if (im > QAM16_THRESHOLD) {
z[s] = 3;
} else {
z[s] = 2;
}
} else {
if (im > QAM16_THRESHOLD) {
z[s] = 1;
} else {
z[s] = 0;
}
}
} else { /* 4th Quadrand (lower-right) */
if (re > QAM16_THRESHOLD) {
if (im < -QAM16_THRESHOLD) {
z[s] = 7;
} else {
z[s] = 6;
}
} else {
if (im < -QAM16_THRESHOLD) {
z[s] = 5;
} else {
z[s] = 4;
}
}
}
} else {
if (im > 0) { /* 2nd Quadrand (upper-left) */
if (re < -QAM16_THRESHOLD) {
if (im > QAM16_THRESHOLD) {
z[s] = 11;
} else {
z[s] = 10;
}
} else {
if (im > QAM16_THRESHOLD) {
z[s] = 9;
} else {
z[s] = 8;
}
}
} else { /* 3rd Quadrand (lower-left) */
if (re < -QAM16_THRESHOLD) {
if (im < -QAM16_THRESHOLD) {
z[s] = 15;
} else {
z[s] = 14;
}
} else {
if (im < -QAM16_THRESHOLD) {
z[s] = 13;
} else {
z[s] = 12;
}
}
}
} }
}
}
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QAM64(const cf_t * in, uint32_t * z, int N)
{
int s;
float re, im;
for (s = 0; s < N; s++) {
re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) {
if (re > QAM64_THRESHOLD_2) {
if (re > QAM64_THRESHOLD_3) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 15;
} else {
z[s] = 14;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 10;
} else {
z[s] = 11;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 13;
} else {
z[s] = 12;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 8;
} else {
z[s] = 9;
}
}
} else if (re > QAM64_THRESHOLD_1) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 5;
} else {
z[s] = 4;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 0;
} else {
z[s] = 1;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 7;
} else {
z[s] = 6;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 2;
} else {
z[s] = 3;
}
}
} else { /* forth quadrant (lower-right) */
if (re > QAM64_THRESHOLD_2) {
if (re > QAM64_THRESHOLD_3) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 31;
} else {
z[s] = 30;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 26;
} else {
z[s] = 27;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 29;
} else {
z[s] = 28;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 24;
} else {
z[s] = 25;
}
}
} else if (re > QAM64_THRESHOLD_1) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 21;
} else {
z[s] = 20;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 16;
} else {
z[s] = 17;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 23;
} else {
z[s] = 22;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 18;
} else {
z[s] = 19;
}
}
}
} else { /* re < 0 */
if (im > 0) { /* second quadrant (upper-left) */
if (re < -QAM64_THRESHOLD_2) {
if (re < -QAM64_THRESHOLD_3) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 47;
} else {
z[s] = 46;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 42;
} else {
z[s] = 43;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 45;
} else {
z[s] = 44;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 40;
} else {
z[s] = 41;
}
}
} else if (re < -QAM64_THRESHOLD_1) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 37;
} else {
z[s] = 36;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 32;
} else {
z[s] = 33;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 39;
} else {
z[s] = 38;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 34;
} else {
z[s] = 35;
}
}
} else { /* third quadrant (lower-left) */
if (re < -QAM64_THRESHOLD_2) {
if (re < -QAM64_THRESHOLD_3) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 63;
} else {
z[s] = 62;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 58;
} else {
z[s] = 59;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 61;
} else {
z[s] = 60;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 56;
} else {
z[s] = 57;
}
}
} else if (re < -QAM64_THRESHOLD_1) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 53;
} else {
z[s] = 52;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 48;
} else {
z[s] = 49;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 55;
} else {
z[s] = 54;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 50;
} else {
z[s] = 51;
}
}
}
}
}
}
static void compute_zone(const cf_t * in, uint32_t * z, int N, int B)
{
switch (B) {
case 1:{
memset(zone, 0, N * sizeof(int));
break;
} /* BPSK */
case 2:{
zone_QPSK(in, z, N);
break;
} /* QPSK */
case 4:{
zone_QAM16(in, z, N);
break;
} /* 16QAM */
case 6:{
zone_QAM64(in, z, N);
break;
} /* 64QAM */
}
}
static void compute_square_dist(const cf_t * in, cf_t * symbols,
uint32_t(*idx)[7], int N, int B)
{
int s, b;
float *d_ptr;
cf_t symbols_extract[7];
for (s = 0; s < N; s++) { /* N: number of received symbols */
d_ptr = dd[s];
for (b = 0; b < B + 1; b++) {
symbols_extract[b] = symbols[idx[zone[s]][b]]; /* only subset of distances to constellation points needed for LLR approx */
//x = __real__ in[s] - __real__ symbols[idx[zone[s]][b]];
//y = __imag__ in[s] - __imag__ symbols[idx[zone[s]][b]];
//dd[s][b] = x*x + y*y;
//printf("\n%f + j %f", __real__ symbols_extract[b], __imag__ symbols_extract[b]);
}
vec_square_dist(in[s], symbols_extract, d_ptr, B + 1); /* B+1 distances to be computed */
}
}
static void compute_llr(int N, int B, uint32_t(*min)[64][6], float sigma2,
float *out)
{
int s, b;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] =
(dd[s][min[0][zone[s]][b]] - dd[s][min[1][zone[s]][b]]) / sigma2;
}
}
}
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
uint32_t(*min)[64][6], float sigma2)
{
if ((M == 2) || (M == 4) || (M == 16) || (M == 64)) {
compute_zone(in, zone, N, B);
compute_square_dist(in, symbols, idx, N, B);
compute_llr(N, B, min, sigma2, out);
}
}
#elif LLR_APPROX_IMPLEMENTATION == 2
float d[10000][64];
float num[10000], den[10000];
static void compute_square_dist(const cf_t * in, cf_t * symbols, int N, int M)
{
int s;
float *d_ptr;
for (s = 0; s < N; s++) {
d_ptr = d[s];
vec_square_dist(in[s], symbols, d_ptr, M);
}
}
static void compute_min_dist(uint32_t(*S)[6][32], int N, int B, int M)
{
int s, b, i;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */ for (b = 0; b < B; b++) { /* bits per symbol */
/* initiate num[b] and den[b] */ /* initiate num[b] and den[b] */
num = d[S[0][b][0]]; num[s * B + b] = 1e10;
den = d[S[1][b][0]]; den[s * B + b] = 1e10;
/* Minimum distance squared search between recevied symbol and a constellation point with a for (i = 0; i < M / 2; i++) {
'1' and a '0' for each bit position */ if (d[s][S[0][b][i]] < num[s * B + b]) {
for (i = 1; i < M / 2; i++) { /* half the constellation points have '1'|'0' at any given bit position */ num[s * B + b] = d[s][S[0][b][i]];
if (d[S[0][b][i]] < num) {
num = d[S[0][b][i]];
} }
if (d[S[1][b][i]] < den) { if (d[s][S[1][b][i]] < den[s * B + b]) {
den = d[S[1][b][i]]; den[s * B + b] = d[s][S[1][b][i]];
} }
} }
/* Theoretical LLR and approximate LLR values are positive if
* symbol(s) with '0' is/are closer and negative if symbol(s)
* with '1' are closer.
* Change sign if mapping negative to '0' and positive to '1' */
out[s * B + b] = change_sign * (den - num) / sigma2;
} }
} }
}
static void compute_llr(int N, int B, float sigma2, float *out)
{
int s, b;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] = (num[s * B + b] - den[s * B + b]) / sigma2;
}
}
} }
#else void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2)
{
if (M <= 64) {
compute_square_dist(in, symbols, N, M);
compute_min_dist(S, N, B, M);
compute_llr(N, B, sigma2, out);
}
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] = (num[s * B + b] - den[s * B + b]) / sigma2;
}
}
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
uint32_t(*min)[64][6], float sigma2)
{
if (M <= 64) {
compute_square_dist(in, symbols, N, M);
compute_min_dist(S, N, B, M);
compute_llr(N, B, sigma2, out);
}
}
#else
/** /**
* @ingroup Soft Modulation Demapping based on the approximate * @ingroup Soft Modulation Demapping based on the approximate
@ -98,9 +602,9 @@ llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* \param S Soft demapping auxiliary matrix * \param S Soft demapping auxiliary matrix
* \param sigma2 Noise vatiance * \param sigma2 Noise vatiance
*/ */
void void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
llr_approx(const _Complex float *in, float *out, int N, int M, int B, _Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2) uint32_t(*min)[64][6], float sigma2)
{ {
int i, s, b; int i, s, b;
float num, den; float num, den;
@ -135,8 +639,12 @@ llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* with '1' are closer. * with '1' are closer.
* Change sign if mapping negative to '0' and positive to '1' */ * Change sign if mapping negative to '0' and positive to '1' */
out[s * B + b] = change_sign * (den - num) / sigma2; out[s * B + b] = change_sign * (den - num) / sigma2;
if (s < 10)
printf("out[%d]=%f=%f/%f\n", s * B + b, out[s * B + b], num, den);
} }
} /* if (s<10)
printf("out[%d]=%f=%f/%f\n",s*B+b,out[s*B+b], num,den);
*/ }
} }
@ -159,7 +667,7 @@ llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* \param sigma2 Noise vatiance * \param sigma2 Noise vatiance
*/ */
void llr_exact(const _Complex float *in, float *out, int N, int M, int B, void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2) _Complex float *symbols, uint32_t(*S)[6][32], float sigma2)
{ {
int i, s, b; int i, s, b;
float num, den; float num, den;

@ -26,7 +26,7 @@
*/ */
void llr_approx(const _Complex float *in, /*void llr_approx(const _Complex float *in,
float *out, float *out,
int N, int N,
int M, int M,
@ -34,6 +34,17 @@ void llr_approx(const _Complex float *in,
_Complex float *symbols, _Complex float *symbols,
uint32_t (*S)[6][32], uint32_t (*S)[6][32],
float sigma2); float sigma2);
*/
void llr_approx(const _Complex float *in,
float *out,
int N,
int M,
int B,
_Complex float *symbols,
uint32_t (*S)[6][32],
uint32_t (*idx)[7], /*64x7 table of integers [0..63], indices to 7 distances to be computed */
uint32_t (*min)[64][6], /*2x64x6 table of integers [0..6], indices to 2x6 nearest symbols */
float sigma2);
void llr_exact(const _Complex float *in, void llr_exact(const _Complex float *in,
float *out, float *out,
@ -43,3 +54,4 @@ void llr_exact(const _Complex float *in,
_Complex float *symbols, _Complex float *symbols,
uint32_t (*S)[6][32], uint32_t (*S)[6][32],
float sigma2); float sigma2);

@ -36,6 +36,9 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
time_t start, finish;
struct timeval x, y;
int num_bits = 1000; int num_bits = 1000;
lte_mod_t modulation; lte_mod_t modulation;
bool soft_output = false, soft_exact = false; bool soft_output = false, soft_exact = false;
@ -98,6 +101,10 @@ int main(int argc, char **argv) {
cf_t *symbols; cf_t *symbols;
float *llr; float *llr;
// unsigned long strt, fin;
// strt = x->tv_usec;
// fin = y->tv_usec;
parse_args(argc, argv); parse_args(argc, argv);
/* initialize objects */ /* initialize objects */
@ -156,7 +163,12 @@ int main(int argc, char **argv) {
/* demodulate */ /* demodulate */
if (soft_output) { if (soft_output) {
gettimeofday(&x, NULL);
demod_soft_demodulate(&demod_soft, symbols, llr, num_bits / mod.nbits_x_symbol); demod_soft_demodulate(&demod_soft, symbols, llr, num_bits / mod.nbits_x_symbol);
gettimeofday(&y, NULL);
printf("\nElapsed time [ns]: %d\n", (int) y.tv_usec - (int) x.tv_usec);
for (i=0;i<num_bits;i++) { for (i=0;i<num_bits;i++) {
output[i] = llr[i]>=0 ? 1 : 0; output[i] = llr[i]>=0 ? 1 : 0;
} }

@ -100,7 +100,7 @@ float mse_threshold() {
case LTE_QAM16: case LTE_QAM16:
return 0.11; return 0.11;
case LTE_QAM64: case LTE_QAM64:
return 0.18; return 0.19;
default: default:
return -1.0; return -1.0;
} }
@ -129,6 +129,7 @@ int main(int argc, char **argv) {
demod_soft_table_set(&demod_soft, &mod); demod_soft_table_set(&demod_soft, &mod);
demod_soft_sigma_set(&demod_soft, 2.0 / mod.nbits_x_symbol); demod_soft_sigma_set(&demod_soft, 2.0 / mod.nbits_x_symbol);
/* allocate buffers */ /* allocate buffers */
input = malloc(sizeof(char) * num_bits); input = malloc(sizeof(char) * num_bits);
if (!input) { if (!input) {
@ -159,7 +160,7 @@ int main(int argc, char **argv) {
} }
/* generate random data */ /* generate random data */
srand(time(NULL)); srand(0);
int ret = -1; int ret = -1;
double mse; double mse;
@ -187,7 +188,9 @@ int main(int argc, char **argv) {
get_time_interval(t); get_time_interval(t);
/* compute exponentially averaged execution time */ /* compute exponentially averaged execution time */
mean_texec = EXPAVERAGE((float) t[0].tv_usec, mean_texec, n); if (n > 0) {
mean_texec = EXPAVERAGE((float) t[0].tv_usec, mean_texec, n-1);
}
/* check MSE */ /* check MSE */
mse = 0.0; mse = 0.0;

@ -30,8 +30,6 @@
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1))
#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) #define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb)
#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) #define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp)

@ -71,6 +71,19 @@ cf_t vec_acc_cc(cf_t *x, uint32_t len) {
return z; return z;
} }
void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints) {
#ifndef HAVE_VOLK_SQUARE_DIST_FUNCTION
uint32_t i;
cf_t diff;
for (i=0;i<npoints;i++) {
diff = symbol - points[i];
distance[i] = crealf(diff) * crealf(diff) + cimagf(diff) * cimagf(diff);
}
#else
volk_32fc_x2_square_dist_32f(distance,&symbol,points,npoints);
#endif
}
void vec_sub_fff(float *x, float *y, float *z, uint32_t len) { void vec_sub_fff(float *x, float *y, float *z, uint32_t len) {
#ifndef HAVE_VOLK_SUB_FLOAT_FUNCTION #ifndef HAVE_VOLK_SUB_FLOAT_FUNCTION
int i; int i;

Loading…
Cancel
Save