diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 7b2242287..5861f1232 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -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_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_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_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION) @@ -55,6 +56,9 @@ ENDIF() IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") ENDIF() +IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION") +ENDIF() IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") ENDIF() diff --git a/lte/phy/include/liblte/phy/modem/modem_table.h b/lte/phy/include/liblte/phy/modem/modem_table.h index cbc4fbee9..794cd0bc4 100644 --- a/lte/phy/include/liblte/phy/modem/modem_table.h +++ b/lte/phy/include/liblte/phy/modem/modem_table.h @@ -40,12 +40,15 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { 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; typedef struct LIBLTE_API { - cf_t* symbol_table; // bit-to-symbol mapping - soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) - uint32_t nsymbols; // number of modulation symbols + cf_t* symbol_table; // bit-to-symbol mapping + soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) + uint32_t nsymbols; // number of modulation symbols uint32_t nbits_x_symbol; // number of bits per symbol }modem_table_t; diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 06a57b0cc..3989dd69d 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -35,7 +35,7 @@ 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 */ @@ -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 */ 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 */ 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); diff --git a/lte/phy/lib/modem/src/demod_soft.c b/lte/phy/lib/modem/src/demod_soft.c index d030a3733..aa9884e71 100644 --- a/lte/phy/lib/modem/src/demod_soft.c +++ b/lte/phy/lib/modem/src/demod_soft.c @@ -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); break; 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); +*/ 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; } return nsymbols*q->table->nbits_x_symbol; diff --git a/lte/phy/lib/modem/src/lte_tables.c b/lte/phy/lib/modem/src/lte_tables.c index e571174c7..b16a6172e 100644 --- a/lte/phy/lib/modem/src/lte_tables.c +++ b/lte/phy/lib/modem/src/lte_tables.c @@ -34,6 +34,8 @@ #include "liblte/phy/modem/modem_table.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 */ 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) */ soft_table->idx[0][0][0] = 0; 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][1][0] = 1; 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[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[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;iidx[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;id_idx[i][j] = -1; /* intialization */ + } + } + + for (i=0;id_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;bd_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++; + } + } + } } + diff --git a/lte/phy/lib/modem/src/lte_tables.h b/lte/phy/lib/modem/src/lte_tables.h index 166594fcc..3698945fc 100644 --- a/lte/phy/lib/modem/src/lte_tables.h +++ b/lte/phy/lib/modem/src/lte_tables.h @@ -38,6 +38,14 @@ #define QAM64_LEVEL_3 5/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) /* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the * symbol from the bit sequence */ diff --git a/lte/phy/lib/modem/src/soft_algs.c b/lte/phy/lib/modem/src/soft_algs.c index 589c24824..8c79c5a9c 100644 --- a/lte/phy/lib/modem/src/soft_algs.c +++ b/lte/phy/lib/modem/src/soft_algs.c @@ -31,56 +31,560 @@ #include #include #include +#include #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 -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) +typedef _Complex float cf_t; + +// There are 3 implemenations: 1 - based on zones; 2 - using volk, 3 - straightforward C +#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 */ - /* Compute the distances squared d[i] between the received symbol and all constellation points */ - for (i = 0; i < M; i++) { - x = __real__ in[s] - __real__ symbols[i]; - y = __imag__ in[s] - __imag__ symbols[i]; - d[i] = x * x + y * y; + 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) */ + 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 */ /* initiate num[b] and den[b] */ - num = d[S[0][b][0]]; - den = d[S[1][b][0]]; + num[s * B + b] = 1e10; + den[s * B + b] = 1e10; - /* Minimum distance squared search between recevied symbol and a constellation point with a - '1' and a '0' for each bit position */ - for (i = 1; i < M / 2; i++) { /* half the constellation points have '1'|'0' at any given bit position */ - if (d[S[0][b][i]] < num) { - num = d[S[0][b][i]]; + for (i = 0; i < M / 2; i++) { + if (d[s][S[0][b][i]] < num[s * B + b]) { + num[s * B + b] = d[s][S[0][b][i]]; } - if (d[S[1][b][i]] < den) { - den = d[S[1][b][i]]; + if (d[s][S[1][b][i]] < den[s * B + b]) { + 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 @@ -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 sigma2 Noise vatiance */ -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) +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) { int i, s, b; 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. * Change sign if mapping negative to '0' and positive to '1' */ 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 */ 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; float num, den; diff --git a/lte/phy/lib/modem/src/soft_algs.h b/lte/phy/lib/modem/src/soft_algs.h index c683700a6..91a5e93aa 100644 --- a/lte/phy/lib/modem/src/soft_algs.h +++ b/lte/phy/lib/modem/src/soft_algs.h @@ -26,7 +26,7 @@ */ -void llr_approx(const _Complex float *in, +/*void llr_approx(const _Complex float *in, float *out, int N, int M, @@ -34,6 +34,17 @@ void llr_approx(const _Complex float *in, _Complex float *symbols, uint32_t (*S)[6][32], 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, float *out, @@ -43,3 +54,4 @@ void llr_exact(const _Complex float *in, _Complex float *symbols, uint32_t (*S)[6][32], float sigma2); + diff --git a/lte/phy/lib/modem/test/modem_test.c b/lte/phy/lib/modem/test/modem_test.c index 0fc09a642..97c97ff17 100644 --- a/lte/phy/lib/modem/test/modem_test.c +++ b/lte/phy/lib/modem/test/modem_test.c @@ -36,6 +36,9 @@ #include "liblte/phy/phy.h" +time_t start, finish; +struct timeval x, y; + int num_bits = 1000; lte_mod_t modulation; bool soft_output = false, soft_exact = false; @@ -98,6 +101,10 @@ int main(int argc, char **argv) { cf_t *symbols; float *llr; +// unsigned long strt, fin; +// strt = x->tv_usec; +// fin = y->tv_usec; + parse_args(argc, argv); /* initialize objects */ @@ -156,7 +163,12 @@ int main(int argc, char **argv) { /* demodulate */ if (soft_output) { + + gettimeofday(&x, NULL); 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=0 ? 1 : 0; } diff --git a/lte/phy/lib/modem/test/soft_demod_test.c b/lte/phy/lib/modem/test/soft_demod_test.c index a5621e305..96b76c5b0 100644 --- a/lte/phy/lib/modem/test/soft_demod_test.c +++ b/lte/phy/lib/modem/test/soft_demod_test.c @@ -100,7 +100,7 @@ float mse_threshold() { case LTE_QAM16: return 0.11; case LTE_QAM64: - return 0.18; + return 0.19; default: return -1.0; } @@ -129,6 +129,7 @@ int main(int argc, char **argv) { demod_soft_table_set(&demod_soft, &mod); demod_soft_sigma_set(&demod_soft, 2.0 / mod.nbits_x_symbol); + /* allocate buffers */ input = malloc(sizeof(char) * num_bits); if (!input) { @@ -159,7 +160,7 @@ int main(int argc, char **argv) { } /* generate random data */ - srand(time(NULL)); + srand(0); int ret = -1; double mse; @@ -187,7 +188,9 @@ int main(int argc, char **argv) { get_time_interval(t); /* 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 */ mse = 0.0; diff --git a/lte/phy/lib/ue/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c index 203011776..0b98459ee 100644 --- a/lte/phy/lib/ue/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -30,8 +30,6 @@ #include #include -#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) - #define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) #define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) diff --git a/lte/phy/lib/utils/src/vector.c b/lte/phy/lib/utils/src/vector.c index c85b7b99e..6df4883d9 100644 --- a/lte/phy/lib/utils/src/vector.c +++ b/lte/phy/lib/utils/src/vector.c @@ -71,6 +71,19 @@ cf_t vec_acc_cc(cf_t *x, uint32_t len) { 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