From 91c9ddf244612e7235a67c969287d468cee7d9e7 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 21 Nov 2017 10:14:09 +0100 Subject: [PATCH 1/3] Added scaling factor to predecoder --- lib/include/srslte/phy/mimo/precoding.h | 48 +-- lib/include/srslte/phy/phch/pdsch.h | 6 + lib/include/srslte/phy/ue/ue_dl.h | 6 + .../phy/ch_estimation/test/chest_test_dl.c | 4 +- lib/src/phy/mimo/precoding.c | 394 +++++++++--------- lib/src/phy/mimo/test/precoder_test.c | 17 +- lib/src/phy/phch/pbch.c | 6 +- lib/src/phy/phch/pcfich.c | 6 +- lib/src/phy/phch/pdcch.c | 6 +- lib/src/phy/phch/pdsch.c | 17 +- lib/src/phy/phch/phich.c | 6 +- lib/src/phy/phch/pmch.c | 2 +- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/phch/pusch.c | 2 +- lib/src/phy/phch/test/pdsch_test.c | 6 +- lib/src/phy/ue/ue_dl.c | 7 +- 16 files changed, 291 insertions(+), 244 deletions(-) diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index 58fe22a40..f8463d1cb 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -49,18 +49,21 @@ */ SRSLTE_API int srslte_precoding_single(cf_t *x, cf_t *y, - int nof_symbols); + int nof_symbols, + float scaling); SRSLTE_API 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); SRSLTE_API 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 nof_symbols, + float scaling); SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], 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 codebook_idx, int nof_symbols, + float scaling, srslte_mimo_type_t type); /* 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 *x, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], @@ -83,42 +88,37 @@ SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, + float scaling, float noise_estimate); SRSLTE_API 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_symbols, + float scaling); SRSLTE_API 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); - -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, - srslte_mimo_type_t type, - float noise_estimate); + int nof_symbols, + float scaling); 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], - 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, - srslte_mimo_type_t type, - float noise_estimate); +SRSLTE_API 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, + int codebook_idx, + int nof_symbols, + srslte_mimo_type_t type, + float scaling, + float noise_estimate); SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols, diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 459bcc209..dab900d77 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -65,6 +65,9 @@ typedef struct SRSLTE_API { uint16_t ue_rnti; bool is_ue; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_a; + /* buffers */ // void buffers are shared for tx and rx 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, 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, uint16_t rnti); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 0486ad7d4..a60761a37 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -104,6 +104,9 @@ typedef struct SRSLTE_API { uint32_t pmi[SRSLTE_MAX_LAYERS]; uint32_t ri; + /* Power allocation parameter 3GPP 36.213 Clause 5.2 Rho_b */ + float rho_b; + srslte_dci_format_t dci_format; uint64_t pkt_errors; 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, 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, diff --git a/lib/src/phy/ch_estimation/test/chest_test_dl.c b/lib/src/phy/ch_estimation/test/chest_test_dl.c index 0f5a6d6ea..62f7e1c86 100644 --- a/lib/src/phy/ch_estimation/test/chest_test_dl.c +++ b/lib/src/phy/ch_estimation/test/chest_test_dl.c @@ -173,7 +173,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); 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); get_time_interval(t); @@ -188,7 +188,7 @@ int main(int argc, char **argv) { gettimeofday(&t[1], NULL); 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); get_time_interval(t); diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 5d96bed27..31ba2ca0a 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -37,13 +37,13 @@ #ifdef LV_HAVE_SSE #include -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_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_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, float scaling); #endif #ifdef LV_HAVE_AVX #include -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 #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))) -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; const float *hPtr1 = (const float*) h[0]; @@ -122,7 +122,10 @@ int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ x1Val1 = _mm_div_ps(x1Val1, h1square); 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, 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]); hh += conj(h[p][i])*h[p][i]; } - x[i] = r/(hh+noise_estimate); + x[i] = scaling*r/(hh+noise_estimate); } 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; 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 h1Val1, h2Val1, y1Val1, y2Val1, h12square, h1square, h2square, h1_p, h2_p, h1conj1, h2conj1, x1Val, x2Val; __m256 h1Val2, h2Val2, y1Val2, y2Val2, h1conj2, h2conj2; + __m256 avx_scaling = _mm256_set1_ps(1/scaling); + for (int i=0;i 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 { - 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 #ifdef LV_HAVE_SSE 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 { - 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 - 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 } /* 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 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 { - 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 #ifdef LV_HAVE_SSE 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 { - 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 - 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 } @@ -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 */ 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], - 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; 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)); x1 += (-h10 * conj(r0) + conj(h01) * r1); } + hh *= scaling; x[0][i] = x0 / 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)); x3 += (-h3 * conjf(r2) + conjf(h1) * r3); } + + hh02 *= scaling; + hh13 *= scaling; + x[0][i] = x0 / hh02 * sqrt(2); x[1][i] = x1 / hh02 * 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], cf_t *x[SRSLTE_MAX_LAYERS], - int nof_rxant, int nof_ports, int nof_symbols) { - return srslte_predecoding_diversity_gen_(y, h, x, nof_rxant, nof_ports, nof_symbols, 0); + 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, scaling); } /* SSE implementation of the 2-port SFBC equalizer */ #ifdef LV_HAVE_SSE 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 nof_rxant, int nof_symbols, float scaling) { float *x0Ptr = (float*) x[0]; 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]; __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_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; } // 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; } #endif 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 *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 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 { - 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 - 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 } 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 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 { - 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 - 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 } - -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 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) { switch (mimo_decoder) { 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; 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; } } else { @@ -1451,7 +1452,7 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ return -1; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: 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 { fprintf(stderr, "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; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: 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 { fprintf(stderr, "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; case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: return srslte_predecoding_multiplex(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols, - noise_estimate); + scaling, noise_estimate); default: 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) { - memcpy(y, x, nof_symbols * sizeof(cf_t)); +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)); + } else { + srslte_vec_sc_prod_cfc(x, scaling, y, (uint32_t) 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 nof_symbols) { + int nof_symbols, float scaling) { int i; if (nof_ports == 2) { 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]); } // normalize - srslte_vec_sc_prod_cfc(y[0], 1.0/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[0], scaling/sqrtf(2), y[0], 2*nof_symbols); + srslte_vec_sc_prod_cfc(y[1], scaling/sqrtf(2), y[1], 2*nof_symbols); return 2 * i; } else if (nof_ports == 4) { + scaling /= sqrtf(2); + //int m_ap = (nof_symbols%4)?(nof_symbols*4-2):nof_symbols*4; int m_ap = 4 * nof_symbols; 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[2][4 * i] = -conjf(x[1][i]) / sqrtf(2); + y[2][4 * i] = -conjf(x[1][i]) * scaling; 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[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[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[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[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[3][4 * i + 3] = conjf(x[2][i]) / sqrtf(2); + y[3][4 * i + 3] = conjf(x[2][i]) * scaling; } return 4 * i; } 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 -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) { __m256 x0 = _mm256_load_ps((float*) &x[0][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 -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) { __m128 x0 = _mm_load_ps((float*) &x[0][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 */ -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++) { - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][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]) * scaling; i++; - y[0][i] = (x[0][i]+x[1][i])/2.0f; - y[1][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]) * scaling; } 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_layers != 2) { @@ -1607,12 +1615,12 @@ int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PORTS], return -1; } #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 #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 - 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_AVX */ } 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 codebook_idx, uint32_t nof_symbols) + int codebook_idx, uint32_t nof_symbols, float scaling) { int i = 0; if (nof_ports == 2) { if (nof_layers == 1) { + scaling /= sqrtf(2.0f); switch(codebook_idx) { 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], 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[0], scaling, y[1], nof_symbols); break; 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], -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[0], -scaling, y[1], nof_symbols); break; case 2: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], _Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], _Complex_I * scaling, y[1], nof_symbols); break; case 3: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_ccc(x[0], -_Complex_I/sqrtf(2.0f), y[1], nof_symbols); + srslte_vec_sc_prod_cfc(x[0], scaling, y[0], nof_symbols); + srslte_vec_sc_prod_ccc(x[0], -_Complex_I * scaling, y[1], nof_symbols); break; default: fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n", @@ -1655,49 +1664,52 @@ int srslte_precoding_multiplex(cf_t *x[SRSLTE_MAX_LAYERS], cf_t *y[SRSLTE_MAX_PO } else if (nof_layers == 2) { switch(codebook_idx) { case 0: - srslte_vec_sc_prod_cfc(x[0], 1.0f/sqrtf(2.0f), y[0], nof_symbols); - srslte_vec_sc_prod_cfc(x[1], 1.0f/sqrtf(2.0f), y[1], nof_symbols); + scaling /= sqrtf(2.0f); + 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; case 1: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { - __m256 x0 = _mm256_load_ps((float*)&x[0][i]); - __m256 x1 = _mm256_load_ps((float*)&x[1][i]); + __m256 x0 = _mm256_load_ps((float *) &x[0][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 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _mm256_sub_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(scaling), _mm256_sub_ps(x0, x1)); - _mm256_store_ps((float*)&y[0][i], y0); - _mm256_store_ps((float*)&y[1][i], y1); + _mm256_store_ps((float *) &y[0][i], y0); + _mm256_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_AVX */ #ifdef LV_HAVE_SSE for (; i < nof_symbols - 1; i += 2) { - __m128 x0 = _mm_load_ps((float*)&x[0][i]); - __m128 x1 = _mm_load_ps((float*)&x[1][i]); + __m128 x0 = _mm_load_ps((float *) &x[0][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 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_sub_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(scaling), _mm_sub_ps(x0, x1)); - _mm_store_ps((float*)&y[0][i], y0); - _mm_store_ps((float*)&y[1][i], y1); + _mm_store_ps((float *) &y[0][i], y0); + _mm_store_ps((float *) &y[1][i], y1); } #endif /* LV_HAVE_SSE */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*x[0][i] - 0.5f*x[1][i]; + y[0][i] = (x[0][i] + x[1][i]) * scaling; + y[1][i] = (x[0][i] - x[1][i]) * scaling; } break; case 2: + scaling /= 2.0f; #ifdef LV_HAVE_AVX for (; i < nof_symbols - 3; i += 4) { __m256 x0 = _mm256_load_ps((float*)&x[0][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 y1 = _mm256_mul_ps(_mm256_set1_ps(0.5f), _MM256_MULJ_PS(_mm256_sub_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(scaling), _MM256_MULJ_PS(_mm256_sub_ps(x0, x1))); _mm256_store_ps((float*)&y[0][i], y0); _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 x1 = _mm_load_ps((float*)&x[1][i]); - __m128 y0 = _mm_mul_ps(_mm_set1_ps(0.5f), _mm_add_ps(x0, x1)); - __m128 y1 = _mm_mul_ps(_mm_set1_ps(0.5f), _MM_MULJ_PS(_mm_sub_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(scaling), _MM_MULJ_PS(_mm_sub_ps(x0, x1))); _mm_store_ps((float*)&y[0][i], y0); _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 */ for (; i < nof_symbols; i++) { - y[0][i] = 0.5f*x[0][i] + 0.5f*x[1][i]; - y[1][i] = 0.5f*_Complex_I*x[0][i] - 0.5f*_Complex_I*x[1][i]; + y[0][i] = (x[0][i] + x[1][i])*scaling; + y[1][i] = (_Complex_I*x[0][i] - _Complex_I*x[1][i])*scaling; } break; 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 */ 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) { 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) { 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: 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 { fprintf(stderr, "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; case SRSLTE_MIMO_TYPE_TX_DIVERSITY: 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 { fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); return -1; } 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: return SRSLTE_ERROR; } diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index 1bbd9e3c0..589e3d51c 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -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 decoder_type_name [16] = "zf"; float snr_db = 100.0f; +float scaling = 0.1f; void usage(char *prog) { printf( "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-c codebook_idx [Default %d]\n", codebook_idx); 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("\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); @@ -59,7 +61,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mplnrcds")) != -1) { + while ((opt = getopt(argc, argv, "mplnrcdsg")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); @@ -85,6 +87,9 @@ void parse_args(int argc, char **argv) { case 's': snr_db = (float) atof(argv[optind]); break; + case 'g': + scaling = (float) atof(argv[optind]); + break; default: usage(argv[0]); 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) { 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++) { srslte_ch_awgn_c(y[i], y[i], std_dev, n); @@ -250,7 +255,7 @@ int main(int argc, char **argv) { } /* 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"); exit(-1); } @@ -285,8 +290,8 @@ int main(int argc, char **argv) { /* predecoding / equalization */ struct timeval t[3]; gettimeofday(&t[1], NULL); - srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, - codebook_idx, nof_re, type, powf(10, -snr_db/10)); + srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, + codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10)); gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lib/src/phy/phch/pbch.c b/lib/src/phy/phch/pbch.c index 2eaa20501..c72b12c60 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -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 */ if (nant == 1) { /* 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 { 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); } @@ -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) { 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); + q->nof_symbols / q->cell.nof_ports, 1.0f); } else { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index d960504fe..7269000a8 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -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 */ if (q->cell.nof_ports == 1) { /* 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 { - 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); } @@ -278,7 +278,7 @@ int srslte_pcfich_encode(srslte_pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[SR /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { 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 { memcpy(q->symbols[0], q->d, q->nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 215324e6b..58d5bf6db 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -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 */ if (q->cell.nof_ports == 1) { /* 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 { - 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); } @@ -618,7 +618,7 @@ int srslte_pdcch_encode(srslte_pdcch_t *q, srslte_dci_msg_t *msg, srslte_dci_loc /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { 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 { memcpy(q->symbols[0], q->d, nof_symbols * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index b984adee3..3fb57fbbd 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -386,6 +386,12 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) { 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) { 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)); } + float pdsch_scaling = 1.0f; + if (q->rho_a != 0.0f) { + pdsch_scaling = 1/q->rho_a; + } + // Pre-decoder - if (srslte_predecoding_type_multi(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) { + 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, pdsch_scaling, noise_estimate)<0) { return -1; } @@ -822,7 +833,7 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, /* Precode */ 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 { memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t)); } diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 14a0d5426..37b8e1b7a 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -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 */ if (q->cell.nof_ports == 1) { /* 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 { - 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); } 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) { 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_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! */ } else { memcpy(q->sf_symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c index aa7fd77b1..c1c322f34 100644 --- a/lib/src/phy/phch/pmch.c +++ b/lib/src/phy/phch/pmch.c @@ -378,7 +378,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q, } // 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()) { DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 498d34f3a..f9c6bebc1 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -787,7 +787,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } // 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 float corr=0, corr_max=-1e9; diff --git a/lib/src/phy/phch/pusch.c b/lib/src/phy/phch/pusch.c index ba1195507..a8c6064fc 100644 --- a/lib/src/phy/phch/pusch.c +++ b/lib/src/phy/phch/pusch.c @@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q, } // 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 srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index b97e8b299..0b18d8b10 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -53,7 +53,7 @@ srslte_cell_t cell = { char mimo_type_str [32] = "single"; 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 subframe = 1; int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1}; @@ -496,7 +496,9 @@ int main(int argc, char **argv) { if (grant.tb_en[tb]) { for (int byte = 0; byte < grant.mcs[tb].tbs / 8; 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; goto quit; } diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 1c3b79440..137756da1 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -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); } - +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) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ From 4ecd73c984fa2887f41b10a11849639eee76d30e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 21 Nov 2017 11:51:18 +0100 Subject: [PATCH 2/3] Added power allocation p_a in UE --- lib/include/srslte/asn1/liblte_rrc.h | 2 +- lib/src/phy/phch/pdsch.c | 2 +- srsue/src/phy/phch_worker.cc | 8 ++++++++ srsue/src/upper/rrc.cc | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/include/srslte/asn1/liblte_rrc.h b/lib/include/srslte/asn1/liblte_rrc.h index c5c3b60e2..d508f3697 100644 --- a/lib/include/srslte/asn1/liblte_rrc.h +++ b/lib/include/srslte/asn1/liblte_rrc.h @@ -3926,7 +3926,7 @@ typedef enum{ }LIBLTE_RRC_PDSCH_CONFIG_P_A_ENUM; static const char liblte_rrc_pdsch_config_p_a_text[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS][20] = { "-6", "-4.77", "-3", "-1.77", "0", "1", "2", "3"}; -static const double liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77, -3, -1.77, 0, 1, 2, 3}; +static const float liblte_rrc_pdsch_config_p_a_num[LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS] = {-6, -4.77f, -3, -1.77f, 0, 1, 2, 3}; // Structs // PDSCH Config Common struct defined above // Functions diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 3fb57fbbd..f9899ef99 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -688,7 +688,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, float pdsch_scaling = 1.0f; if (q->rho_a != 0.0f) { - pdsch_scaling = 1/q->rho_a; + pdsch_scaling = q->rho_a; } // Pre-decoder diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 97fad0720..529dd92f2 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -601,6 +601,14 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL valid_config = false; } + /* Set power allocation */ + float rho_a = 1.0f, rho_b = 1.0f; + if (phy->config->dedicated.pdsch_cnfg_ded < LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS) { + float rho_a_db = liblte_rrc_pdsch_config_p_a_num[(int) phy->config->dedicated.pdsch_cnfg_ded]; + rho_a = powf(10.0f, rho_a_db / 20.0f) * sqrtf(2.0f); + } + srslte_ue_dl_set_power_alloc(&ue_dl, rho_a, rho_b); + Debug("DL Buffer TTI %d: Decoding PDSCH\n", tti); /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index 7b4bef710..0127514f7 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -1472,8 +1472,10 @@ void rrc::apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT } if (phy_cnfg->pdsch_cnfg_ded_present) { current_cfg->pdsch_cnfg_ded = phy_cnfg->pdsch_cnfg_ded; + rrc_log->info("Set PDSCH-Config=%s (present)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]); } else if (apply_defaults) { current_cfg->pdsch_cnfg_ded = LIBLTE_RRC_PDSCH_CONFIG_P_A_DB_0; + rrc_log->info("Set PDSCH-Config=%s (default)\n", liblte_rrc_pdsch_config_p_a_text[(int) current_cfg->pdsch_cnfg_ded]); } if (phy_cnfg->cqi_report_cnfg_present) { From 58aac96a6e0597615fab0c18db56b1ee383d8a43 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 21 Nov 2017 16:11:08 +0100 Subject: [PATCH 3/3] Added Power Allocation from HL in UE side --- lib/include/srslte/phy/phch/pdsch_cfg.h | 7 +++++++ lib/src/phy/ue/ue_dl.c | 28 ++++++++++++++++++++++++- srsue/src/phy/phch_worker.cc | 9 ++++++-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 63b3fefcc..569d1ef7e 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -39,6 +39,13 @@ #include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/fec/cbsegm.h" +/* 3GPP 36.213 Table 5.2-1: The cell-specific ratio rho_B / rho_A for 1, 2, or 4 cell specific antenna ports */ +static const float pdsch_cfg_cell_specific_ratio_table[2][4] = + { /* One antenna port */ {1.0f / 1.0f, 4.0f / 5.0f, 3.0f / 5.0f, 2.0f / 5.0f}, + /* Two or more antenna port */ {5.0f / 4.0f, 1.0f / 1.0f, 3.0f / 4.0f, 1.0f / 2.0f} + }; + + typedef struct SRSLTE_API { srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 137756da1..494eecba7 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -308,10 +308,36 @@ 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); } -void srslte_ue_dl_set_power_alloc (srslte_ue_dl_t *q, float rho_a, float rho_b) { +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; + + uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); + uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; + + /* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */ + if (rho_b != 0.0f && rho_b != 1.0f) { + float scaling = 1.0f / rho_b; + for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { + for (uint32_t j = 0; j < 2; j++) { + cf_t *ptr; + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + if (q->cell.cp == SRSLTE_CP_NORM) { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } else { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } + if (q->cell.nof_ports == 4) { + ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1); + srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); + } + } + } + } } } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 529dd92f2..7b4ec48bd 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -601,11 +601,16 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL valid_config = false; } - /* Set power allocation */ + /* Set power allocation according to 3GPP 36.213 clause 5.2 Downlink power allocation */ float rho_a = 1.0f, rho_b = 1.0f; if (phy->config->dedicated.pdsch_cnfg_ded < LIBLTE_RRC_PDSCH_CONFIG_P_A_N_ITEMS) { float rho_a_db = liblte_rrc_pdsch_config_p_a_num[(int) phy->config->dedicated.pdsch_cnfg_ded]; - rho_a = powf(10.0f, rho_a_db / 20.0f) * sqrtf(2.0f); + rho_a = powf(10.0f, rho_a_db / 20.0f) * ((cell.nof_ports == 1) ? 1.0f : sqrtf(2.0f)); + } + if (phy->config->common.pdsch_cnfg.p_b < 4) { + uint32_t idx0 = (cell.nof_ports == 1) ? 0 : 1; + float cell_specific_ratio = pdsch_cfg_cell_specific_ratio_table[idx0][phy->config->common.pdsch_cnfg.p_b]; + rho_b = sqrtf(cell_specific_ratio); } srslte_ue_dl_set_power_alloc(&ue_dl, rho_a, rho_b);