Added scaling factor to predecoder

master
Xavier Arteaga 7 years ago
parent ab3a3108f1
commit 91c9ddf244

@ -49,18 +49,21 @@
*/ */
SRSLTE_API int srslte_precoding_single(cf_t *x, SRSLTE_API int srslte_precoding_single(cf_t *x,
cf_t *y, cf_t *y,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
int nof_layers, int nof_layers,
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS], cf_t *y[SRSLTE_MAX_PORTS],
@ -68,6 +71,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,
int codebook_idx, int codebook_idx,
int nof_symbols, int nof_symbols,
float scaling,
srslte_mimo_type_t type); srslte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h" /* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
@ -76,6 +80,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
cf_t *h, cf_t *h,
cf_t *x, cf_t *x,
int nof_symbols, int nof_symbols,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
@ -83,33 +88,27 @@ SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *x, cf_t *x,
int nof_rxant, int nof_rxant,
int nof_symbols, int nof_symbols,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_predecoding_diversity(cf_t *y, SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_ports,
int nof_symbols); int nof_symbols,
float scaling);
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_symbols);
SRSLTE_API int srslte_predecoding_type(cf_t *y,
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports,
int nof_layers,
int nof_symbols, int nof_symbols,
srslte_mimo_type_t type, float scaling);
float noise_estimate);
SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder); SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder);
SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
@ -118,6 +117,7 @@ SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS],
int codebook_idx, int codebook_idx,
int nof_symbols, int nof_symbols,
srslte_mimo_type_t type, srslte_mimo_type_t type,
float scaling,
float noise_estimate); float noise_estimate);
SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],

@ -65,6 +65,9 @@ typedef struct SRSLTE_API {
uint16_t ue_rnti; uint16_t ue_rnti;
bool is_ue; bool is_ue;
/* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */
float rho_a;
/* buffers */ /* buffers */
// void buffers are shared for tx and rx // void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */
@ -101,6 +104,9 @@ SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q,
SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q,
uint16_t rnti); uint16_t rnti);
SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q,
float rho_a);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q,
uint16_t rnti); uint16_t rnti);

@ -104,6 +104,9 @@ typedef struct SRSLTE_API {
uint32_t pmi[SRSLTE_MAX_LAYERS]; uint32_t pmi[SRSLTE_MAX_LAYERS];
uint32_t ri; uint32_t ri;
/* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */
float rho_b;
srslte_dci_format_t dci_format; srslte_dci_format_t dci_format;
uint64_t pkt_errors; uint64_t pkt_errors;
uint64_t pkts_total; uint64_t pkts_total;
@ -244,6 +247,9 @@ SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q,
SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
uint8_t non_mbsfn_region_length); uint8_t non_mbsfn_region_length);
SRSLTE_API void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q,
float rho_a,
float rho_b);
SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q,

@ -173,7 +173,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) { for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, 0); srslte_predecoding_single(input, ce, output, num_re, 1.0f, 0);
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
@ -188,7 +188,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) { for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, srslte_chest_dl_get_noise_estimate(&est)); srslte_predecoding_single(input, ce, output, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est));
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);

@ -37,13 +37,13 @@
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.h> #include <immintrin.h>
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate);
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols, float scaling);
#endif #endif
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
#include <immintrin.h> #include <immintrin.h>
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate);
#endif #endif
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
@ -59,7 +59,7 @@ static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE;
#define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b))) #define PROD(a,b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b)))
int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
float *xPtr = (float*) x; float *xPtr = (float*) x;
const float *hPtr1 = (const float*) h[0]; const float *hPtr1 = (const float*) h[0];
@ -123,6 +123,9 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
x1Val1 = _mm_div_ps(x1Val1, h1square); x1Val1 = _mm_div_ps(x1Val1, h1square);
x2Val1 = _mm_div_ps(x2Val1, h2square); x2Val1 = _mm_div_ps(x2Val1, h2square);
x1Val1 = _mm_mul_ps(x1Val1, _mm_set1_ps(1/scaling));
x2Val1 = _mm_mul_ps(x2Val1, _mm_set1_ps(1/scaling));
_mm_store_ps(xPtr, x1Val1); xPtr+=4; _mm_store_ps(xPtr, x1Val1); xPtr+=4;
_mm_store_ps(xPtr, x2Val1); xPtr+=4; _mm_store_ps(xPtr, x2Val1); xPtr+=4;
@ -134,7 +137,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = scaling*r/(hh+noise_estimate);
} }
return nof_symbols; return nof_symbols;
} }
@ -147,7 +150,7 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
float *xPtr = (float*) x; float *xPtr = (float*) x;
const float *hPtr1 = (const float*) h[0]; const float *hPtr1 = (const float*) h[0];
@ -160,6 +163,8 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
__m256 noise = _mm256_set1_ps(noise_estimate); __m256 noise = _mm256_set1_ps(noise_estimate);
__m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val; __m256 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val;
__m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2; __m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2;
__m256 avx_scaling = _mm256_set1_ps(1/scaling);
for (int i=0;i<nof_symbols/8;i++) { for (int i=0;i<nof_symbols/8;i++) {
y1Val1 = _mm256_load_ps(yPtr1); yPtr1+=8; y1Val1 = _mm256_load_ps(yPtr1); yPtr1+=8;
@ -214,6 +219,9 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
x1Val = _mm256_div_ps(x1Val, h1square); x1Val = _mm256_div_ps(x1Val, h1square);
x2Val = _mm256_div_ps(x2Val, h2square); x2Val = _mm256_div_ps(x2Val, h2square);
x1Val = _mm256_mul_ps(x1Val, avx_scaling);
x2Val = _mm256_mul_ps(x2Val, avx_scaling);
_mm256_store_ps(xPtr, x1Val); xPtr+=8; _mm256_store_ps(xPtr, x1Val); xPtr+=8;
_mm256_store_ps(xPtr, x2Val); xPtr+=8; _mm256_store_ps(xPtr, x2Val); xPtr+=8;
} }
@ -224,14 +232,14 @@ int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = r/((hh+noise_estimate) * scaling);
} }
return nof_symbols; return nof_symbols;
} }
#endif #endif
int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
for (int i=0;i<nof_symbols;i++) { for (int i=0;i<nof_symbols;i++) {
cf_t r = 0; cf_t r = 0;
cf_t hh = 0; cf_t hh = 0;
@ -239,13 +247,13 @@ int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
r += y[p][i]*conj(h[p][i]); r += y[p][i]*conj(h[p][i]);
hh += conj(h[p][i])*h[p][i]; hh += conj(h[p][i])*h[p][i];
} }
x[i] = r/(hh+noise_estimate); x[i] = r / ((hh+noise_estimate) * scaling);
} }
return nof_symbols; return nof_symbols;
} }
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float noise_estimate) { int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float scaling, float noise_estimate) {
cf_t *y[SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS];
cf_t *h[SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS];
@ -255,40 +263,41 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32 && nof_rxant <= 2) { if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_rxant <= 2) { if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
#endif #endif
#endif #endif
} }
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate) { int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x,
int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32) { if (nof_symbols > 32) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32) { if (nof_symbols > 32) {
return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_sse(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
} }
#else #else
return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_gen(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
#endif #endif
#endif #endif
} }
@ -296,7 +305,7 @@ int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MA
/* C implementatino of the SFBC equalizer */ /* C implementatino of the SFBC equalizer */
int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols, int symbol_start) int nof_rxant, int nof_ports, int nof_symbols, int symbol_start, float scaling)
{ {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
@ -321,6 +330,7 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
x0 += (conjf(h00) * r0 + h11 * conjf(r1)); x0 += (conjf(h00) * r0 + h11 * conjf(r1));
x1 += (-h10 * conj(r0) + conj(h01) * r1); x1 += (-h10 * conj(r0) + conj(h01) * r1);
} }
hh *= scaling;
x[0][i] = x0 / hh * sqrt(2); x[0][i] = x0 / hh * sqrt(2);
x[1][i] = x1 / hh * sqrt(2); x[1][i] = x1 / hh * sqrt(2);
} }
@ -351,6 +361,10 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
x2 += (conjf(h1) * r2 + h3 * conjf(r3)); x2 += (conjf(h1) * r2 + h3 * conjf(r3));
x3 += (-h3 * conjf(r2) + conjf(h1) * r3); x3 += (-h3 * conjf(r2) + conjf(h1) * r3);
} }
hh02 *= scaling;
hh13 *= scaling;
x[0][i] = x0 / hh02 * sqrt(2); x[0][i] = x0 / hh02 * sqrt(2);
x[1][i] = x1 / hh02 * sqrt(2); x[1][i] = x1 / hh02 * sqrt(2);
x[2][i] = x2 / hh13 * sqrt(2); x[2][i] = x2 / hh13 * sqrt(2);
@ -365,15 +379,15 @@ int srslte_predecoding_diversity_gen_(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols) { int nof_rxant, int nof_ports, int nof_symbols, float scaling) {
return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0); return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0, scaling);
} }
/* SSE implementation of the 2-port SFBC equalizer */ /* SSE implementation of the 2-port SFBC equalizer */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_symbols) int nof_rxant, int nof_symbols, float scaling)
{ {
float *x0Ptr = (float*) x[0]; float *x0Ptr = (float*) x[0];
float *x1Ptr = (float*) x[1]; float *x1Ptr = (float*) x[1];
@ -385,7 +399,7 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
const float *yPtr1 = (const float*) y[1]; const float *yPtr1 = (const float*) y[1];
__m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f); __m128 conjugator = _mm_setr_ps(0, -0.f, 0, -0.f);
__m128 sqrt2 = _mm_setr_ps(sqrt(2), sqrt(2), sqrt(2), sqrt(2)); __m128 sqrt2 = _mm_set1_ps(sqrtf(2)/scaling);
__m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110; __m128 h0Val_00, h0Val_10, h1Val_00, h1Val_10, h000, h00conj0, h010, h01conj0, h100, h110;
__m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111; __m128 h0Val_01, h0Val_11, h1Val_01, h1Val_11, h001, h00conj1, h011, h01conj1, h101, h111;
@ -474,13 +488,13 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
_mm_store_ps(x1Ptr, x1); x1Ptr+=4; _mm_store_ps(x1Ptr, x1); x1Ptr+=4;
} }
// Compute remaining symbols using generic implementation // Compute remaining symbols using generic implementation
srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4)); srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, 2, nof_symbols, 4*(nof_symbols/4), scaling);
return nof_symbols; return nof_symbols;
} }
#endif #endif
int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_symbols) int nof_ports, int nof_symbols, float scaling)
{ {
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS];
@ -493,47 +507,31 @@ int srslte_predecoding_diversity(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[S
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) { if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling);
} else { } else {
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} }
#else #else
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
#endif #endif
} }
int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_symbols) int nof_rxant, int nof_ports, int nof_symbols, float scaling)
{ {
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
if (nof_symbols > 32 && nof_ports == 2) { if (nof_symbols > 32 && nof_ports == 2) {
return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols); return srslte_predecoding_diversity2_sse(y, h, x, nof_rxant, nof_symbols, scaling);
} else { } else {
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} }
#else #else
return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_gen(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
#endif #endif
} }
int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate)
{
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
uint32_t nof_rxant = 1;
for (int i=0;i<nof_ports;i++) {
h[i][0] = h_[i];
}
y[0] = y_;
return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, 0, nof_symbols, type, noise_estimate);
}
int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols, float noise_estimate) int nof_symbols, float scaling, float noise_estimate)
{ {
cf_t G[2][2], Gx[2][2]; cf_t G[2][2], Gx[2][2];
@ -559,8 +557,8 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t
} }
// x=G*y // x=G*y
x[0][i] = Gx[0][0]*y[0][i] + Gx[0][1]*y[1][i]; x[0][i] = (Gx[0][0]*y[0][i] + Gx[0][1]*y[1][i]) * scaling;
x[1][i] = Gx[1][0]*y[0][i] + Gx[1][1]*y[1][i]; x[1][i] = (Gx[1][0]*y[0][i] + Gx[1][1]*y[1][i]) * scaling;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -572,7 +570,8 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t
int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) { uint32_t nof_symbols,
float scaling) {
uint32_t i = 0; uint32_t i = 0;
__m256 mask0 = _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f); __m256 mask0 = _mm256_setr_ps(+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f);
@ -596,7 +595,7 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
__m256 x0, x1; __m256 x0, x1;
srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); srslte_mat_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f / scaling);
_mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1); _mm256_store_ps((float *) &x[1][i], x1);
@ -612,7 +611,8 @@ int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) { uint32_t nof_symbols,
float scaling) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 1; i += 2) { for (i = 0; i < nof_symbols - 1; i += 2) {
@ -633,7 +633,7 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
__m128 x0, x1; __m128 x0, x1;
srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f); srslte_mat_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f / scaling);
_mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1); _mm_store_ps((float *) &x[1][i], x1);
@ -644,9 +644,13 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
#endif #endif
// Generic implementation of ZF 2x2 CCD equalizer // Generic implementation of ZF 2x2 CCD equalizer
int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS],
int nof_symbols) { cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t h00, h01, h10, h11, det; cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols,
float scaling) {
cf_t h00, h01, h10, h11;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
// Even precoder // Even precoder
@ -654,11 +658,8 @@ int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
h10 = +h[0][1][i] + h[1][1][i]; h10 = +h[0][1][i] + h[1][1][i];
h01 = +h[0][0][i] - h[1][0][i]; h01 = +h[0][0][i] - h[1][0][i];
h11 = +h[0][1][i] - h[1][1][i]; h11 = +h[0][1][i] - h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det; srslte_mat_2x2_zf_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], 2.0f / scaling);
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
i++; i++;
@ -667,28 +668,24 @@ int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
h10 = h[0][1][i] - h[1][1][i]; h10 = h[0][1][i] - h[1][1][i];
h01 = h[0][0][i] + h[1][0][i]; h01 = h[0][0][i] + h[1][0][i];
h11 = h[0][1][i] + h[1][1][i]; h11 = h[0][1][i] + h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det;
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
srslte_mat_2x2_zf_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], 2.0f / scaling);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int nof_symbols) int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float scaling)
{ {
if (nof_ports == 2 && nof_rxant == 2) { if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols, scaling);
#else #else
return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols); return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else { } else {
@ -709,7 +706,7 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT
int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols, float noise_estimate) { uint32_t nof_symbols, float scaling, float noise_estimate) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 3; i += 4) { for (i = 0; i < nof_symbols - 3; i += 4) {
@ -730,7 +727,7 @@ int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
__m256 x0, x1; __m256 x0, x1;
srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); srslte_mat_2x2_mmse_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f / scaling);
_mm256_store_ps((float *) &x[0][i], x0); _mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1); _mm256_store_ps((float *) &x[1][i], x1);
@ -746,7 +743,7 @@ int srslte_predecoding_ccd_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS],
int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols, float noise_estimate) { uint32_t nof_symbols, float scaling, float noise_estimate) {
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < nof_symbols - 1; i += 2) { for (i = 0; i < nof_symbols - 1; i += 2) {
@ -767,7 +764,7 @@ int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
__m128 x0, x1; __m128 x0, x1;
srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f); srslte_mat_2x2_mmse_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, noise_estimate, 2.0f / scaling);
_mm_store_ps((float *) &x[0][i], x0); _mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1); _mm_store_ps((float *) &x[1][i], x1);
@ -779,8 +776,9 @@ int srslte_predecoding_ccd_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS],
// Generic implementation of ZF 2x2 CCD equalizer // Generic implementation of ZF 2x2 CCD equalizer
int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols, float noise_estimate) { int nof_symbols, float scaling, float noise_estimate) {
cf_t h00, h01, h10, h11; cf_t h00, h01, h10, h11;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
// Even precoder // Even precoder
@ -788,7 +786,7 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT
h10 = +h[0][1][i] + h[1][1][i]; h10 = +h[0][1][i] + h[1][1][i];
h01 = +h[0][0][i] - h[1][0][i]; h01 = +h[0][0][i] - h[1][0][i];
h11 = +h[0][1][i] - h[1][1][i]; h11 = +h[0][1][i] - h[1][1][i];
srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f / scaling);
i++; i++;
@ -797,24 +795,24 @@ int srslte_predecoding_ccd_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLT
h10 = h[0][1][i] - h[1][1][i]; h10 = h[0][1][i] - h[1][1][i];
h01 = h[0][0][i] + h[1][0][i]; h01 = h[0][0][i] + h[1][0][i];
h11 = h[0][1][i] + h[1][1][i]; h11 = h[0][1][i] + h[1][1][i];
srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f); srslte_mat_2x2_mmse_gen(y[0][i], y[1][i], h00, h01, h10, h11, &x[0][i], &x[1][i], noise_estimate, 2.0f / scaling);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float noise_estimate) int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, float scaling, float noise_estimate)
{ {
if (nof_ports == 2 && nof_rxant == 2) { if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_ccd_2x2_mmse_avx(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_avx(y, h, x, nof_symbols, scaling, noise_estimate);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_mmse_sse(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_sse(y, h, x, nof_symbols, scaling, noise_estimate);
#else #else
return srslte_predecoding_ccd_2x2_mmse_gen(y, h, x, nof_symbols, noise_estimate); return srslte_predecoding_ccd_2x2_mmse_gen(y, h, x, nof_symbols, scaling, noise_estimate);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else { } else {
@ -833,16 +831,16 @@ int srslte_predecoding_ccd_mmse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PO
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -901,16 +899,16 @@ int srslte_predecoding_multiplex_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer // SSE implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -968,16 +966,16 @@ int srslte_predecoding_multiplex_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1025,16 +1023,16 @@ int srslte_predecoding_multiplex_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[S
// AVX implementation of ZF 2x2 Spatial Multiplexity equalizer // AVX implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1095,16 +1093,16 @@ int srslte_predecoding_multiplex_2x2_mmse_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// SSE implementation of ZF 2x2 Spatial Multiplexity equalizer // SSE implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm; float norm;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx); fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
@ -1161,16 +1159,16 @@ int srslte_predecoding_multiplex_2x2_mmse_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer // Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols,
float noise_estimate) { float scaling, float noise_estimate) {
float norm = 1.0; float norm = 1.0;
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
norm = (float) M_SQRT2; norm = (float) M_SQRT2 / scaling;
break; break;
case 1: case 1:
case 2: case 2:
norm = 2.0f; norm = 2.0f / scaling;
break; break;
default: default:
ERROR("Wrong codebook_idx=%d", codebook_idx); ERROR("Wrong codebook_idx=%d", codebook_idx);
@ -1213,7 +1211,7 @@ int srslte_predecoding_multiplex_2x2_mmse_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h
// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer // Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer
int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
for (int i = 0; i < nof_symbols - 3; i += 4) { for (int i = 0; i < nof_symbols - 3; i += 4) {
__m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i])); __m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i]));
@ -1251,7 +1249,7 @@ int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
__m256 hh = _mm256_add_ps(hh0, hh1); __m256 hh = _mm256_add_ps(hh0, hh1);
__m256 hhrec = _mm256_rcp_ps(hh); __m256 hhrec = _mm256_rcp_ps(hh);
hhrec = _mm256_mul_ps(hhrec, _mm256_set1_ps((float) M_SQRT2)); hhrec = _mm256_mul_ps(hhrec, _mm256_set1_ps((float) M_SQRT2 / scaling));
__m256 y0 = _mm256_load_ps((float*)&y[0][i]); __m256 y0 = _mm256_load_ps((float*)&y[0][i]);
__m256 y1 = _mm256_load_ps((float*)&y[1][i]); __m256 y1 = _mm256_load_ps((float*)&y[1][i]);
@ -1272,7 +1270,7 @@ int srslte_predecoding_multiplex_2x1_mrc_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
for (int i = 0; i < nof_symbols - 1; i += 2) { for (int i = 0; i < nof_symbols - 1; i += 2) {
__m128 _h00 = _mm_load_ps((float*)&(h[0][0][i])); __m128 _h00 = _mm_load_ps((float*)&(h[0][0][i]));
@ -1310,7 +1308,7 @@ int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
__m128 hh = _mm_add_ps(hh0, hh1); __m128 hh = _mm_add_ps(hh0, hh1);
__m128 hhrec = _mm_rcp_ps(hh); __m128 hhrec = _mm_rcp_ps(hh);
hhrec = _mm_mul_ps(hhrec, _mm_set1_ps((float) M_SQRT2)); hhrec = _mm_mul_ps(hhrec, _mm_set1_ps((float) M_SQRT2 / scaling));
__m128 y0 = _mm_load_ps((float*)&y[0][i]); __m128 y0 = _mm_load_ps((float*)&y[0][i]);
__m128 y1 = _mm_load_ps((float*)&y[1][i]); __m128 y1 = _mm_load_ps((float*)&y[1][i]);
@ -1329,7 +1327,9 @@ int srslte_predecoding_multiplex_2x1_mrc_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer // Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer
int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols) { cf_t *x[SRSLTE_MAX_LAYERS], int codebook_idx, int nof_symbols, float scaling) {
float norm = (float) M_SQRT2 / scaling;
for (int i = 0; i < nof_symbols; i += 1) { for (int i = 0; i < nof_symbols; i += 1) {
cf_t h0, h1; cf_t h0, h1;
float hh; float hh;
@ -1356,7 +1356,7 @@ int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
hh = (float) M_SQRT2/(crealf(h0)*crealf(h0) + cimagf(h0)*cimagf(h0) + crealf(h1)*crealf(h1) + cimagf(h1)*cimagf(h1)); hh = norm / (crealf(h0) * crealf(h0) + cimagf(h0) * cimagf(h0) + crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1));
x[0][i] = (conjf(h0) * y[0][i] + conjf(h1) * y[1][i]) * hh; x[0][i] = (conjf(h0) * y[0][i] + conjf(h1) * y[1][i]) * hh;
} }
@ -1365,42 +1365,42 @@ int srslte_predecoding_multiplex_2x1_mrc_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[
int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols, int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols,
float noise_estimate) float scaling, float noise_estimate)
{ {
if (nof_ports == 2 && nof_rxant <= 2) { if (nof_ports == 2 && nof_rxant <= 2) {
if (nof_layers == 2) { if (nof_layers == 2) {
switch (mimo_decoder) { switch (mimo_decoder) {
case SRSLTE_MIMO_DECODER_ZF: case SRSLTE_MIMO_DECODER_ZF:
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x2_zf_avx(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_avx(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x2_zf_sse(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_sse(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
return srslte_predecoding_multiplex_2x2_zf_gen(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x2_zf_gen(y, h, x, codebook_idx, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
break; break;
case SRSLTE_MIMO_DECODER_MMSE: case SRSLTE_MIMO_DECODER_MMSE:
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x2_mmse_avx(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_avx(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x2_mmse_sse(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_sse(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#else #else
return srslte_predecoding_multiplex_2x2_mmse_gen(y, h, x, codebook_idx, nof_symbols, noise_estimate); return srslte_predecoding_multiplex_2x2_mmse_gen(y, h, x, codebook_idx, nof_symbols, scaling, noise_estimate);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
break; break;
} }
} else { } else {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_predecoding_multiplex_2x1_mrc_avx(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_avx(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_predecoding_multiplex_2x1_mrc_sse(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_sse(y, h, x, codebook_idx, nof_symbols, scaling);
#else #else
return srslte_predecoding_multiplex_2x1_mrc_gen(y, h, x, codebook_idx, nof_symbols); return srslte_predecoding_multiplex_2x1_mrc_gen(y, h, x, codebook_idx, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} }
@ -1417,9 +1417,10 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) {
} }
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers, cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers,
int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) { int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling,
float noise_estimate) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS,
@ -1437,10 +1438,10 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
if (nof_layers >= 2 && nof_layers <= 4) { if (nof_layers >= 2 && nof_layers <= 4) {
switch (mimo_decoder) { switch (mimo_decoder) {
case SRSLTE_MIMO_DECODER_ZF: case SRSLTE_MIMO_DECODER_ZF:
return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols); return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling);
break; break;
case SRSLTE_MIMO_DECODER_MMSE: case SRSLTE_MIMO_DECODER_MMSE:
return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, noise_estimate); return srslte_predecoding_ccd_mmse(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, scaling, noise_estimate);
break; break;
} }
} else { } else {
@ -1451,7 +1452,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
return -1; return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, noise_estimate); return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers);
@ -1460,7 +1461,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols); return srslte_predecoding_diversity_multi(y, h, x, nof_rxant, nof_ports, nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");
@ -1469,7 +1470,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
break; break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols,
noise_estimate); scaling, noise_estimate);
default: default:
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -1487,12 +1488,16 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
* *
**************************************************/ **************************************************/
int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols) { int srslte_precoding_single(cf_t *x, cf_t *y, int nof_symbols, float scaling) {
if (scaling == 1.0f) {
memcpy(y, x, nof_symbols * sizeof(cf_t)); memcpy(y, x, nof_symbols * sizeof(cf_t));
} else {
srslte_vec_sc_prod_cfc(x, scaling, y, (uint32_t) nof_symbols);
}
return nof_symbols; return nof_symbols;
} }
int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports, int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_ports,
int nof_symbols) { int nof_symbols, float scaling) {
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
for (i = 0; i < nof_symbols; i++) { for (i = 0; i < nof_symbols; i++) {
@ -1502,32 +1507,34 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
y[1][2 * i + 1] = conjf(x[0][i]); y[1][2 * i + 1] = conjf(x[0][i]);
} }
// normalize // normalize
srslte_vec_sc_prod_cfc(y[0], 1.0/sqrtf(2), y[0], 2*nof_symbols); srslte_vec_sc_prod_cfc(y[0], scaling/sqrtf(2), y[0], 2*nof_symbols);
srslte_vec_sc_prod_cfc(y[1], 1.0/sqrtf(2), y[1], 2*nof_symbols); srslte_vec_sc_prod_cfc(y[1], scaling/sqrtf(2), y[1], 2*nof_symbols);
return 2 * i; return 2 * i;
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
scaling /= sqrtf(2);
//int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4;
int m_ap = 4 * nof_symbols; int m_ap = 4 * nof_symbols;
for (i = 0; i < m_ap / 4; i++) { for (i = 0; i < m_ap / 4; i++) {
y[0][4 * i] = x[0][i] / sqrtf(2); y[0][4 * i] = x[0][i] * scaling;
y[1][4 * i] = 0; y[1][4 * i] = 0;
y[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); y[2][4 * i] = -conjf(x[1][i]) * scaling;
y[3][4 * i] = 0; y[3][4 * i] = 0;
y[0][4 * i + 1] = x[1][i] / sqrtf(2); y[0][4 * i + 1] = x[1][i] * scaling;
y[1][4 * i + 1] = 0; y[1][4 * i + 1] = 0;
y[2][4 * i + 1] = conjf(x[0][i]) / sqrtf(2); y[2][4 * i + 1] = conjf(x[0][i]) * scaling;
y[3][4 * i + 1] = 0; y[3][4 * i + 1] = 0;
y[0][4 * i + 2] = 0; y[0][4 * i + 2] = 0;
y[1][4 * i + 2] = x[2][i] / sqrtf(2); y[1][4 * i + 2] = x[2][i] * scaling;
y[2][4 * i + 2] = 0; y[2][4 * i + 2] = 0;
y[3][4 * i + 2] = -conjf(x[3][i]) / sqrtf(2); y[3][4 * i + 2] = -conjf(x[3][i]) * scaling;
y[0][4 * i + 3] = 0; y[0][4 * i + 3] = 0;
y[1][4 * i + 3] = x[3][i] / sqrtf(2); y[1][4 * i + 3] = x[3][i] * scaling;
y[2][4 * i + 3] = 0; y[2][4 * i + 3] = 0;
y[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); y[3][4 * i + 3] = conjf(x[2][i]) * scaling;
} }
return 4 * i; return 4 * i;
} else { } else {
@ -1538,9 +1545,9 @@ int srslte_precoding_diversity(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
__m256 norm_avx = _mm256_set1_ps(0.5f); __m256 norm_avx = _mm256_set1_ps(0.5f * scaling);
for (int i = 0; i < nof_symbols - 3; i += 4) { for (int i = 0; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float*) &x[0][i]); __m256 x0 = _mm256_load_ps((float*) &x[0][i]);
__m256 x1 = _mm256_load_ps((float*) &x[1][i]); __m256 x1 = _mm256_load_ps((float*) &x[1][i]);
@ -1563,9 +1570,9 @@ int srslte_precoding_cdd_2x2_avx(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
__m128 norm_sse = _mm_set1_ps(0.5f); __m128 norm_sse = _mm_set1_ps(0.5f * scaling);
for (int i = 0; i < nof_symbols - 1; i += 2) { for (int i = 0; i < nof_symbols - 1; i += 2) {
__m128 x0 = _mm_load_ps((float*) &x[0][i]); __m128 x0 = _mm_load_ps((float*) &x[0][i]);
__m128 x1 = _mm_load_ps((float*) &x[1][i]); __m128 x1 = _mm_load_ps((float*) &x[1][i]);
@ -1587,19 +1594,20 @@ int srslte_precoding_cdd_2x2_sse(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols) int srslte_precoding_cdd_2x2_gen(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_symbols, float scaling)
{ {
scaling /= 2.0f;
for (int i = 0; i < nof_symbols; i++) { for (int i = 0; i < nof_symbols; i++) {
y[0][i] = (x[0][i]+x[1][i])/2.0f; y[0][i] = (x[0][i]+x[1][i]) * scaling;
y[1][i] = (x[0][i]-x[1][i])/2.0f; y[1][i] = (x[0][i]-x[1][i]) * scaling;
i++; i++;
y[0][i] = (x[0][i]+x[1][i])/2.0f; y[0][i] = (x[0][i]+x[1][i]) * scaling;
y[1][i] = (-x[0][i]+x[1][i])/2.0f; y[1][i] = (-x[0][i]+x[1][i]) * scaling;
} }
return 2 * nof_symbols; return 2 * nof_symbols;
} }
int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols) int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols, float scaling)
{ {
if (nof_ports == 2) { if (nof_ports == 2) {
if (nof_layers != 2) { if (nof_layers != 2) {
@ -1607,12 +1615,12 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
return -1; return -1;
} }
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols); return srslte_precoding_cdd_2x2_avx(x, y, nof_symbols, scaling);
#else #else
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols); return srslte_precoding_cdd_2x2_sse(x, y, nof_symbols, scaling);
#else #else
return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols); return srslte_precoding_cdd_2x2_gen(x, y, nof_symbols, scaling);
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX */
} else if (nof_ports == 4) { } else if (nof_ports == 4) {
@ -1625,27 +1633,28 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
} }
int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports, int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int nof_ports,
int codebook_idx, uint32_t nof_symbols) int codebook_idx, uint32_t nof_symbols, float scaling)
{ {
int i = 0; int i = 0;
if (nof_ports == 2) { if (nof_ports == 2) {
if (nof_layers == 1) { if (nof_layers == 1) {
scaling /= sqrtf(2.0f);
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[1], nof_symbols);
break; break;
case 1: case 1:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[0], -1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], -scaling, y[1], nof_symbols);
break; break;
case 2: case 2:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_ccc(x[0], _Complex_I * scaling, y[1], nof_symbols);
break; break;
case 3: case 3:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols);
break; break;
default: default:
fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n",
@ -1655,17 +1664,19 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
} else if (nof_layers == 2) { } else if (nof_layers == 2) {
switch(codebook_idx) { switch(codebook_idx) {
case 0: case 0:
srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); scaling /= sqrtf(2.0f);
srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols);
srslte_vec_sc_prod_cfc(x[1], scaling, y[1], nof_symbols);
break; break;
case 1: case 1:
scaling /= 2.0f;
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
for (; i < nof_symbols - 3; i += 4) { for (; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float *) &x[0][i]); __m256 x0 = _mm256_load_ps((float *) &x[0][i]);
__m256 x1 = _mm256_load_ps((float *) &x[1][i]); __m256 x1 = _mm256_load_ps((float *) &x[1][i]);
__m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1));
__m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_ps(x0, x1)); __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_sub_ps(x0, x1));
_mm256_store_ps((float *) &y[0][i], y0); _mm256_store_ps((float *) &y[0][i], y0);
_mm256_store_ps((float *) &y[1][i], y1); _mm256_store_ps((float *) &y[1][i], y1);
@ -1677,8 +1688,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
__m128 x0 = _mm_load_ps((float *) &x[0][i]); __m128 x0 = _mm_load_ps((float *) &x[0][i]);
__m128 x1 = _mm_load_ps((float *) &x[1][i]); __m128 x1 = _mm_load_ps((float *) &x[1][i]);
__m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1));
__m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_ps(x0, x1)); __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_sub_ps(x0, x1));
_mm_store_ps((float *) &y[0][i], y0); _mm_store_ps((float *) &y[0][i], y0);
_mm_store_ps((float *) &y[1][i], y1); _mm_store_ps((float *) &y[1][i], y1);
@ -1686,18 +1697,19 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
for (; i < nof_symbols; i++) { for (; i < nof_symbols; i++) {
y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[0][i] = (x[0][i] + x[1][i]) * scaling;
y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; y[1][i] = (x[0][i] - x[1][i]) * scaling;
} }
break; break;
case 2: case 2:
scaling /= 2.0f;
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
for (; i < nof_symbols - 3; i += 4) { for (; i < nof_symbols - 3; i += 4) {
__m256 x0 = _mm256_load_ps((float*)&x[0][i]); __m256 x0 = _mm256_load_ps((float*)&x[0][i]);
__m256 x1 = _mm256_load_ps((float*)&x[1][i]); __m256 x1 = _mm256_load_ps((float*)&x[1][i]);
__m256 y0 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_add_ps(x0, x1)); __m256 y0 = _mm256_mul_ps(_mm256_set1_ps(scaling), _mm256_add_ps(x0, x1));
__m256 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); __m256 y1 = _mm256_mul_ps(_mm256_set1_ps(scaling), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1)));
_mm256_store_ps((float*)&y[0][i], y0); _mm256_store_ps((float*)&y[0][i], y0);
_mm256_store_ps((float*)&y[1][i], y1); _mm256_store_ps((float*)&y[1][i], y1);
@ -1709,8 +1721,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
__m128 x0 = _mm_load_ps((float*)&x[0][i]); __m128 x0 = _mm_load_ps((float*)&x[0][i]);
__m128 x1 = _mm_load_ps((float*)&x[1][i]); __m128 x1 = _mm_load_ps((float*)&x[1][i]);
__m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); __m128 y0 = _mm_mul_ps(_mm_set1_ps(scaling), _mm_add_ps(x0, x1));
__m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); __m128 y1 = _mm_mul_ps(_mm_set1_ps(scaling), _MM_MULJ_PS(_mm_sub_ps(x0, x1)));
_mm_store_ps((float*)&y[0][i], y0); _mm_store_ps((float*)&y[0][i], y0);
_mm_store_ps((float*)&y[1][i], y1); _mm_store_ps((float*)&y[1][i], y1);
@ -1718,8 +1730,8 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
for (; i < nof_symbols; i++) { for (; i < nof_symbols; i++) {
y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; y[0][i] = (x[0][i] + x[1][i])*scaling;
y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; y[1][i] = (_Complex_I*x[0][i] - _Complex_I*x[1][i])*scaling;
} }
break; break;
case 3: case 3:
@ -1739,7 +1751,7 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers, int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], int nof_layers,
int nof_ports, int codebook_idx, int nof_symbols, srslte_mimo_type_t type) { int nof_ports, int codebook_idx, int nof_symbols, float scaling, srslte_mimo_type_t type) {
if (nof_ports > SRSLTE_MAX_PORTS) { if (nof_ports > SRSLTE_MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS, fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS,
@ -1754,10 +1766,10 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
switch (type) { switch (type) {
case SRSLTE_MIMO_TYPE_CDD: case SRSLTE_MIMO_TYPE_CDD:
return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols); return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols, scaling);
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(x[0], y[0], nof_symbols); return srslte_precoding_single(x[0], y[0], nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports\n"); "Number of ports and layers must be 1 for transmission on single antenna ports\n");
@ -1766,14 +1778,14 @@ int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS],
break; break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY: case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) { if (nof_ports == nof_layers) {
return srslte_precoding_diversity(x, y, nof_ports, nof_symbols); return srslte_precoding_diversity(x, y, nof_ports, nof_symbols, scaling);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n"); "Error number of layers must equal number of ports in transmit diversity\n");
return -1; return -1;
} }
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, nof_symbols); return srslte_precoding_multiplex(x, y, nof_layers, nof_ports, codebook_idx, (uint32_t) nof_symbols, scaling);
default: default:
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -44,14 +44,16 @@ int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
char decoder_type_name [16] = "zf"; char decoder_type_name [16] = "zf";
float snr_db = 100.0f; float snr_db = 100.0f;
float scaling = 0.1f;
void usage(char *prog) { void usage(char *prog) {
printf( printf(
"Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
" -r [nof_rx_ports]\n", prog); " -r [nof_rx_ports] -g [scaling]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
printf("\t-c codebook_idx [Default %d]\n", codebook_idx); printf("\t-c codebook_idx [Default %d]\n", codebook_idx);
printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db); printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db);
printf("\t-g Scaling [Default %.1f]*\n", scaling);
printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name); printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name);
printf("\n"); printf("\n");
printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name); printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name);
@ -59,7 +61,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { while ((opt = getopt(argc, argv, "mplnrcdsg")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_symbols = atoi(argv[optind]); nof_symbols = atoi(argv[optind]);
@ -85,6 +87,9 @@ void parse_args(int argc, char **argv) {
case 's': case 's':
snr_db = (float) atof(argv[optind]); snr_db = (float) atof(argv[optind]);
break; break;
case 'g':
scaling = (float) atof(argv[optind]);
break;
default: default:
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
@ -149,7 +154,7 @@ void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_
static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) { static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) {
int i; int i;
float std_dev = powf(10, - (snr + 3.0f) / 20.0f); float std_dev = powf(10, - (snr + 3.0f) / 20.0f) * scaling;
for (i = 0; i < nof_rx_ports; i++) { for (i = 0; i < nof_rx_ports; i++) {
srslte_ch_awgn_c(y[i], y[i], std_dev, n); srslte_ch_awgn_c(y[i], y[i], std_dev, n);
@ -250,7 +255,7 @@ int main(int argc, char **argv) {
} }
/* Execute Precoding (Tx) */ /* Execute Precoding (Tx) */
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) { if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, scaling, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
@ -285,8 +290,8 @@ int main(int argc, char **argv) {
/* predecoding / equalization */ /* predecoding / equalization */
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
codebook_idx, nof_re, type, powf(10, -snr_db/10)); codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10));
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);

@ -497,10 +497,10 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (nant == 1) { if (nant == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols); q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant); srslte_layerdemap_diversity(x, q->d, nant, q->nof_symbols / nant);
} }
@ -591,7 +591,7 @@ int srslte_pbch_encode(srslte_pbch_t *q, uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
q->nof_symbols / q->cell.nof_ports); q->nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
} }

@ -219,9 +219,9 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, noise_estimate); srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols); srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
} }
@ -278,7 +278,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, q->nof_symbols);
srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_precoding_diversity(x, q_symbols, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t));
} }

@ -485,9 +485,9 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, noise_estimate/2); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
} else { } else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols); srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
} }
@ -618,7 +618,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc
/* layer mapping & precoding */ /* layer mapping & precoding */
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols); srslte_layermap_diversity(q->d, x, q->cell.nof_ports, nof_symbols);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports, 1.0f);
} else { } else {
memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t));
} }

@ -386,6 +386,12 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) {
if (q) {
q->rho_a = rho_a;
}
}
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
{ {
uint32_t rnti_idx = q->is_ue?0:rnti; uint32_t rnti_idx = q->is_ue?0:rnti;
@ -680,9 +686,14 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers)); memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
} }
float pdsch_scaling = 1.0f;
if (q->rho_a != 0.0f) {
pdsch_scaling = 1/q->rho_a;
}
// Pre-decoder // Pre-decoder
if (srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, if (srslte_predecoding_type(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate)<0) { cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
return -1; return -1;
} }
@ -822,7 +833,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
/* Precode */ /* Precode */
srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx, srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx,
nof_symbols, cfg->mimo_type); nof_symbols, 1.0f, cfg->mimo_type);
} else { } else {
memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t));
} }

@ -239,9 +239,9 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
} }
DEBUG("Recv!!: \n", 0); DEBUG("Recv!!: \n", 0);
@ -405,7 +405,7 @@ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_
if (q->cell.nof_ports > 1) { if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB);
srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports, srslte_precoding_diversity(x, symbols_precoding, q->cell.nof_ports,
SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports, 1.0f);
/**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */
} else { } else {
memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t));

@ -378,7 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
} }
// No tx diversity in MBSFN // No tx diversity in MBSFN
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate);
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); DEBUG("SAVED FILE subframe.dat: received subframe symbols\n");

@ -787,7 +787,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
} }
// Equalization // Equalization
srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, noise_estimate); srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, 1.0f, noise_estimate);
// Perform ML-decoding // Perform ML-decoding
float corr=0, corr_max=-1e9; float corr=0, corr_max=-1e9;

@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
} }
// Equalization // Equalization
srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, noise_estimate); srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, 1.0f, noise_estimate);
// DFT predecoding // DFT predecoding
srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb);

@ -53,7 +53,7 @@ srslte_cell_t cell = {
char mimo_type_str [32] = "single"; char mimo_type_str [32] = "single";
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t cfi = 2; uint32_t cfi = 1;
uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0}; uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0};
uint32_t subframe = 1; uint32_t subframe = 1;
int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1};
@ -496,7 +496,9 @@ int main(int argc, char **argv) {
if (grant.tb_en[tb]) { if (grant.tb_en[tb]) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) { for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
if (data_tx[tb][byte] != data_rx[tb][byte]) { if (data_tx[tb][byte] != data_rx[tb][byte]) {
ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]); ERROR("Found BYTE (%d) error in TB %d (%02X != %02X), quiting...", byte, tb, data_tx[tb][byte], data_rx[tb][byte]);
printf("Tx: "); srslte_vec_fprint_byte(stdout, data_tx[tb], grant.mcs[tb].tbs / 8);
printf("Rx: "); srslte_vec_fprint_byte(stdout, data_rx[tb], grant.mcs[tb].tbs / 8);
ret = SRSLTE_ERROR; ret = SRSLTE_ERROR;
goto quit; goto quit;
} }

@ -308,7 +308,12 @@ void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q,
srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length);
} }
void srslte_ue_dl_set_power_alloc (srslte_ue_dl_t *q, float rho_a, float rho_b) {
if (q) {
srslte_pdsch_set_power_allocation(&q->pdsch, rho_a);
q->rho_b = rho_b;
}
}
void srslte_ue_dl_reset(srslte_ue_dl_t *q) { void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){

Loading…
Cancel
Save