From 6fc9c96c58b7856c3a23ec87a3ceccd0a0e3129f Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 28 Feb 2018 12:02:17 +0100 Subject: [PATCH] Added CSI softbits weightening for Single antenna transmission --- lib/include/srslte/phy/mimo/precoding.h | 3 + lib/include/srslte/phy/phch/pdsch.h | 6 ++ lib/include/srslte/phy/utils/simd.h | 12 +++- .../phy/ch_estimation/test/chest_test_dl.c | 4 +- lib/src/phy/mimo/precoding.c | 58 +++++++++++++++++-- lib/src/phy/mimo/test/precoder_test.c | 2 +- lib/src/phy/phch/pbch.c | 2 +- lib/src/phy/phch/pcfich.c | 2 +- lib/src/phy/phch/pdcch.c | 2 +- lib/src/phy/phch/pdsch.c | 52 ++++++++++++++++- lib/src/phy/phch/phich.c | 2 +- lib/src/phy/phch/pmch.c | 2 +- lib/src/phy/phch/pucch.c | 2 +- lib/src/phy/phch/pusch.c | 2 +- 14 files changed, 135 insertions(+), 16 deletions(-) diff --git a/lib/include/srslte/phy/mimo/precoding.h b/lib/include/srslte/phy/mimo/precoding.h index f8463d1cb..27395085c 100644 --- a/lib/include/srslte/phy/mimo/precoding.h +++ b/lib/include/srslte/phy/mimo/precoding.h @@ -79,6 +79,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS], SRSLTE_API int srslte_predecoding_single(cf_t *y, cf_t *h, cf_t *x, + float *csi, int nof_symbols, float scaling, float noise_estimate); @@ -86,6 +87,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y, SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, + float *csi, int nof_rxant, int nof_symbols, float scaling, @@ -111,6 +113,7 @@ SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo 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], + float *csi, int nof_rxant, int nof_ports, int nof_layers, diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index dab900d77..1889078e6 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -76,6 +76,9 @@ typedef struct SRSLTE_API { cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */ void *e[SRSLTE_MAX_CODEWORDS]; + bool csi_enabled; + float *csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */ + /* tx & rx objects */ srslte_modem_table_t mod[4]; @@ -107,6 +110,9 @@ SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a); +SRSLTE_API int srslte_pdsch_enable_csi(srslte_pdsch_t *q, + bool enable); + SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, uint16_t rnti); diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h index e22a9ef09..3b5a00a8a 100644 --- a/lib/include/srslte/phy/utils/simd.h +++ b/lib/include/srslte/phy/utils/simd.h @@ -530,7 +530,7 @@ static inline simd_cf_t srslte_simd_cfi_loadu(const cf_t *ptr) { 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F), in2); #else /* LV_HAVE_AVX512 */ - #ifdef LV_HAVE_AVX2 +#ifdef LV_HAVE_AVX2 __m256 in1 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr)), 0b11011000); __m256 in2 = _mm256_permute_ps(_mm256_loadu_ps((float*)(ptr + 4)), 0b11011000); ret.re = _mm256_unpacklo_ps(in1, in2); @@ -705,6 +705,16 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg #endif /* LV_HAVE_AVX512 */ } +static inline simd_f_t srslte_simd_cf_re(simd_cf_t in) { + simd_f_t out = in.re; +#ifdef LV_HAVE_AVX2 + /* Permute for AVX registers (mis SSE registers) */ + const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); + out = _mm256_permutevar8x32_ps(out, idx); +#endif /* LV_HAVE_AVX2 */ + return out; +} + static inline simd_cf_t srslte_simd_cf_set1 (cf_t x) { simd_cf_t ret; #ifdef LV_HAVE_AVX512 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 62f7e1c86..222263c7e 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, 1.0f, 0); + srslte_predecoding_single(input, ce, output, NULL, 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, 1.0f, srslte_chest_dl_get_noise_estimate(&est)); + srslte_predecoding_single(input, ce, output, NULL, 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 6d50e3ed2..f8faeda75 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -34,6 +34,7 @@ #include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/mat.h" +#include "srslte/phy/utils/simd.h" #ifdef LV_HAVE_SSE #include @@ -252,8 +253,49 @@ int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_ return nof_symbols; } +int srslte_predecoding_single_csi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { + int i = 0; + +#if SRSLTE_SIMD_CF_SIZE + const simd_f_t _noise = srslte_simd_f_set1(noise_estimate); + const simd_f_t _scaling = srslte_simd_f_set1(1.0f / scaling); + + for (; i < nof_symbols - SRSLTE_SIMD_CF_SIZE + 1; i += SRSLTE_SIMD_CF_SIZE) { + simd_cf_t _r = srslte_simd_cf_zero(); + simd_f_t _hh = srslte_simd_f_zero(); + + for (int p = 0; p < nof_rxant; p++) { + simd_cf_t _y = srslte_simd_cfi_load(&y[p][i]); + simd_cf_t _h = srslte_simd_cfi_load(&h[p][i]); + + _r = srslte_simd_cf_add(_r, srslte_simd_cf_conjprod(_y, _h)); + _hh = srslte_simd_f_add(_hh, srslte_simd_cf_re(srslte_simd_cf_conjprod(_h, _h))); + } + + simd_f_t _csi = srslte_simd_f_add(_hh, _noise); + simd_cf_t _x = srslte_simd_cf_mul(srslte_simd_cf_mul(_r, _scaling), srslte_simd_f_rcp(_csi)); + + srslte_simd_f_store(&csi[i], _csi); + srslte_simd_cfi_store(&x[i], _x); + } +#endif + + for (; i < nof_symbols; i++) { + cf_t r = 0; + float hh = 0; + float _scaling = 1.0f / scaling; + for (int p = 0; p < nof_rxant; p++) { + r += y[p][i] * conj(h[p][i]); + hh += (__real__ h[p][i] * __real__ h[p][i]) + (__imag__ h[p][i] * __imag__ h[p][i]); + } + csi[i] = hh + noise_estimate; + x[i] = r * _scaling / csi[i]; + } + return nof_symbols; +} + /* 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 scaling, float noise_estimate) { +int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, float *csi, int nof_symbols, float scaling, float noise_estimate) { cf_t *y[SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS]; @@ -261,6 +303,10 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa h[0] = h_; int nof_rxant = 1; + if (csi) { + return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate); + } + #ifdef LV_HAVE_AVX if (nof_symbols > 32 && nof_rxant <= 2) { return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); @@ -281,8 +327,12 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa } /* 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 srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { + if (csi) { + return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate); + } + #ifdef LV_HAVE_AVX if (nof_symbols > 32) { return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); @@ -1418,7 +1468,7 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) { /* 36.211 v10.3.0 Section 6.3.4 */ 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], float *csi, 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) { @@ -1451,7 +1501,7 @@ int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS] 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, scaling, noise_estimate); + return srslte_predecoding_single_multi(y, h[0], x[0], csi, 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); diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index 1054545c3..a6925f318 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -291,7 +291,7 @@ int main(int argc, char **argv) { /* predecoding / equalization */ struct timeval t[3]; gettimeofday(&t[1], NULL); - srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, + srslte_predecoding_type(r, h, xr, NULL, 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 c72b12c60..e7c0c33af 100644 --- a/lib/src/phy/phch/pbch.c +++ b/lib/src/phy/phch/pbch.c @@ -497,7 +497,7 @@ 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, 1.0f, noise_estimate); + srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, q->nof_symbols, 1.0f, noise_estimate); } else { srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, q->nof_symbols, 1.0f); diff --git a/lib/src/phy/phch/pcfich.c b/lib/src/phy/phch/pcfich.c index 7269000a8..6b00e768a 100644 --- a/lib/src/phy/phch/pcfich.c +++ b/lib/src/phy/phch/pcfich.c @@ -219,7 +219,7 @@ 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, 1.0f, noise_estimate); + srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, 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, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index 206ef1be6..83f681f8f 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -490,7 +490,7 @@ 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, 1.0f, noise_estimate/2); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, 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, 1.0f); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 1cf4af4e2..4cfa5c75c 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -294,6 +294,10 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { if (q->d[i]) { free(q->d[i]); } + + if (q->csi[i]) { + free(q->csi[i]); + } } /* Free sch objects */ @@ -394,6 +398,22 @@ void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) { } } +int srslte_pdsch_enable_csi(srslte_pdsch_t *q, bool enable) { + if (enable) { + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (!q->csi[i]) { + q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re); + if (!q->csi[i]) { + return SRSLTE_ERROR; + } + } + } + } + q->csi_enabled = enable; + + return SRSLTE_SUCCESS; +} + void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) { uint32_t rnti_idx = q->is_ue?0:rnti; @@ -617,6 +637,36 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c /* Bit scrambling */ srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); + uint32_t qm = nbits->nof_bits/nbits->nof_re; + switch(cfg->grant.mcs[tb_idx].mod) { + + case SRSLTE_MOD_BPSK: + qm = 1; + break; + case SRSLTE_MOD_QPSK: + qm = 2; + break; + case SRSLTE_MOD_16QAM: + qm = 4; + break; + case SRSLTE_MOD_64QAM: + qm = 6; + break; + default: + ERROR("No modulation"); + } + + int16_t *e = q->e[codeword_idx]; + + if (q->csi_enabled) { + for (int i = 0; i < nbits->nof_bits / qm; i++) { + float csi = q->csi[codeword_idx][i]; + for (int k = 0; k < qm; k++) { + e[qm * i + k] = (int16_t) ((float) e[qm * i + k] * csi); + } + } + } + /* Return */ ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx); @@ -702,7 +752,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, } // Pre-decoder - if (srslte_predecoding_type(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->csi[0], 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) { DEBUG("Error predecoding\n"); return SRSLTE_ERROR; diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index 6990d69e2..15aa4db88 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -239,7 +239,7 @@ 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, 1.0f, noise_estimate); + srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, 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, 1.0f); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c index c1c322f34..c7ec0b204 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, 1.0f, noise_estimate); + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, 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 b1317de3e..dd3977757 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, 1.0f, noise_estimate); + srslte_predecoding_single(q->z_tmp, q->ce, q->z, NULL, 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 feb4e8b4f..aa049f7c0 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, 1.0f, noise_estimate); + srslte_predecoding_single(q->d, q->ce, q->z, NULL, 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);