Merge with next_with_matlab

master
Xavier Arteaga 7 years ago
parent 6a45147f45
commit 1d00e1acaa

@ -70,6 +70,8 @@ uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1;
char mimo_type_str[32] = "single";
uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
@ -104,7 +106,7 @@ uint8_t *data[2], data2[DATA_BUFF_SZ];
uint8_t data_tmp[DATA_BUFF_SZ];
void usage(char *prog) {
printf("Usage: %s [agmfoncvpuM]\n", prog);
printf("Usage: %s [agmfoncvpuxb]\n", prog);
#ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", rf_args);
printf("\t-l RF amplitude [Default %.2f]\n", rf_amp);
@ -118,14 +120,18 @@ void usage(char *prog) {
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-M Transmission mode[single|diversity|cdd] [Default %s]\n", mimo_type_str);
printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\n");
printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvutM")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) {
switch (opt) {
case 'a':
rf_args = argv[optind];
@ -157,9 +163,15 @@ void parse_args(int argc, char **argv) {
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'M':
case 'x':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'b':
multiplex_pmi = (uint32_t) atoi(argv[optind]);
break;
case 'w':
multiplex_nof_layers = (uint32_t) atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -202,6 +214,11 @@ void base_init() {
pdsch_cfg.nof_layers = 2;
nof_tb = 2;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
cell.nof_ports = 2;
pdsch_cfg.nof_layers = multiplex_nof_layers;
nof_tb = multiplex_nof_layers;
break;
default:
ERROR("Transmission mode not implemented.");
exit(-1);
@ -695,7 +712,7 @@ int main(int argc, char **argv) {
}
if (send_data) {
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1;
srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
dci_format = SRSLTE_DCI_FORMAT1;
@ -705,6 +722,13 @@ int main(int argc, char **argv) {
dci_format = SRSLTE_DCI_FORMAT2A;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
dci_format = SRSLTE_DCI_FORMAT2;
if (multiplex_nof_layers == 1) {
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
} else {
ra_dl.pinfo = (uint8_t) multiplex_pmi;
}
break;
default:
fprintf(stderr, "Wrong MIMO configuration\n");
exit(SRSLTE_ERROR);
@ -720,7 +744,7 @@ int main(int argc, char **argv) {
/* Configure pdsch_cfg parameters */
srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant);
if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0)) {
if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0, pdsch_cfg.mimo_type, multiplex_pmi)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}

@ -511,7 +511,8 @@ int main(int argc, char **argv) {
// Variables for measurements
uint32_t nframes=0;
float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0;
uint32_t ri = 0, pmi = 0;
float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0, sinr = 0.0;
bool decode_pdsch = false;
#ifndef DISABLE_RF
@ -616,6 +617,16 @@ int main(int argc, char **argv) {
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05);
enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0, enodebrate, 0.05);
uerate = SRSLTE_VEC_EMA((n>0)?(ue_dl.pdsch_cfg.grant.mcs.tbs + ue_dl.pdsch_cfg.grant.mcs2.tbs)/1000.0:0.0, uerate, 0.01);
if (ue_dl.cell.nof_ports == 2 && ue_dl.pdsch.nof_rx_antennas == 2) {
float _sinr;
srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, &_sinr);
if (!isinff(_sinr) && !isnanf(_sinr)) {
sinr = SRSLTE_VEC_EMA(_sinr, sinr, 0.05f);
}
}
nframes++;
if (isnan(rsrq)) {
rsrq = 0;
@ -651,7 +662,8 @@ int main(int argc, char **argv) {
"SNR: %+5.1f dB | %+5.1f dB, "
"Rb: %6.2f / %6.2f Mbps, "
"PDCCH-Miss: %5.2f%%, "
"PDSCH-BLER: %5.2f%%\r",
"PDSCH-BLER: %5.2f%%, "
"SINR: %3.1f dB RI: %d PMI: %d \r",
srslte_ue_sync_get_cfo(&ue_sync) / 1000,
10 * log10(rsrp0 / noise),
@ -659,7 +671,10 @@ int main(int argc, char **argv) {
uerate,
enodebrate,
100 * (1 - (float) ue_dl.nof_detected / nof_trials),
(float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total);
(float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total,
10 * log10(sinr),
ri,
pmi);
}
}
break;

@ -55,6 +55,8 @@
#define SRSLTE_MAX_CODEBLOCKS 32
#define SRSLTE_MAX_CODEBOOKS 4
#define SRSLTE_LTE_CRC24A 0x1864CFB
#define SRSLTE_LTE_CRC24B 0X1800063
#define SRSLTE_LTE_CRC16 0x11021

@ -65,8 +65,9 @@ SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS],
SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS],
int nof_layers,
int nof_ports,
int nof_symbols,
int nof_ports,
int codebook_idx,
int nof_symbols,
srslte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
@ -112,8 +113,16 @@ SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS],
int nof_rxant,
int nof_ports,
int nof_layers,
int codebook_idx,
int nof_symbols,
srslte_mimo_type_t type,
float noise_estimate);
int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t nof_symbols,
float noise_estimate,
int nof_layers,
uint32_t *pmi,
float sinr[SRSLTE_MAX_CODEBOOKS]);
#endif /* PRECODING_H_ */

@ -115,7 +115,9 @@ SRSLTE_API int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg,
uint32_t cfi,
uint32_t sf_idx,
uint32_t rvidx,
uint32_t rvidx2);
uint32_t rvidx2,
srslte_mimo_type_t mimo_type,
uint32_t pmi);
SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,

@ -49,6 +49,7 @@ typedef struct SRSLTE_API {
uint32_t rv2;
uint32_t sf_idx;
uint32_t nof_layers;
uint32_t codebook_idx;
srslte_mimo_type_t mimo_type;
} srslte_pdsch_cfg_t;

@ -216,6 +216,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant,
srslte_ra_nbits_t *nbits,
srslte_ra_nbits_t *nbits2);
SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant,
uint32_t cfi,
srslte_cell_t cell,
uint32_t sf_idx,
srslte_ra_nbits_t *nbits,
srslte_ra_nbits_t *nbits2);
SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell,
uint32_t nof_prb,
uint32_t nof_ctrl_symbols);

@ -80,6 +80,11 @@ SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h,
uint32_t nof_tx_antennas,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h,
char *args,
uint32_t nof_tx_antennas,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
char *devname,
char *args);

@ -147,7 +147,9 @@ SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q,
uint32_t cfi,
uint32_t sf_idx,
uint32_t rvidx,
uint32_t rvidx2);
uint32_t rvidx2,
srslte_mimo_type_t mimo_type,
uint32_t pinfo);
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
uint32_t cfi,

@ -0,0 +1,70 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_ALGEBRA_H
#define SRSLTE_ALGEBRA_H
#include "srslte/config.h"
#ifdef LV_HAVE_SSE
#define _MM_MULJ_PS(X) _mm_permute_ps(_MM_CONJ_PS(X), 0b10110001)
#define _MM_CONJ_PS(X) (_mm_xor_ps(X, (__m128){0.0f, -0.0f, 0.0f, -0.0f}))
#define _MM_PROD_PS(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)))
SRSLTE_API void srslte_algebra_2x2_zf_sse(__m128 y0,
__m128 y1,
__m128 h00,
__m128 h01,
__m128 h10,
__m128 h11,
__m128 *x0,
__m128 *x1,
float norm);
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001)
#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, (__m256){0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f}))
#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\
_mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b)))
SRSLTE_API void srslte_algebra_2x2_zf_avx(__m256 y0,
__m256 y1,
__m256 h00,
__m256 h01,
__m256 h10,
__m256 h11,
__m256 *x0,
__m256 *x1,
float norm);
#endif /* LV_HAVE_AVX */
#endif //SRSLTE_ALGEBRA_H

@ -436,7 +436,7 @@ int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) {
*type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "TxDiversity")) {
*type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
} else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "SpatialMux")) {
*type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) {
*type = SRSLTE_MIMO_TYPE_CDD;

@ -33,6 +33,7 @@
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/mimo/precoding.h"
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/debug.h"
#ifdef LV_HAVE_SSE
#include <xmmintrin.h>
@ -43,6 +44,9 @@ int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_
#ifdef LV_HAVE_AVX
#include <immintrin.h>
#include <srslte/srslte.h>
#include <srslte/phy/utils/algebra.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);
#endif
@ -527,7 +531,7 @@ int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE
h[i][0] = h_[i];
}
y[0] = y_;
return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, type, noise_estimate);
return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, 0, nof_symbols, type, noise_estimate);
}
@ -565,11 +569,46 @@ int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t
return SRSLTE_SUCCESS;
}
// SSE implementation of ZF 2x2 CCD equalizer
#ifdef LV_HAVE_AVX
int srslte_predecoding_ccd_2x2_zf_avx(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) {
uint32_t i = 0;
for (i = 0; i < nof_symbols; i += 4) {
/* Load channel */
__m256 h00i = _mm256_load_ps((float *) &h[0][0][i]);
__m256 h01i = _mm256_load_ps((float *) &h[0][1][i]);
__m256 h10i = _mm256_load_ps((float *) &h[1][0][i]);
__m256 h11i = _mm256_load_ps((float *) &h[1][1][i]);
/* Apply precoding */
__m256 h00 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i,
(__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f}));
__m256 h10 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i,
(__m256) {+0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f}));
__m256 h01 = _mm256_add_ps(h00i, _mm256_xor_ps(h10i,
(__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f}));
__m256 h11 = _mm256_add_ps(h01i, _mm256_xor_ps(h11i,
(__m256) {-0.0f, -0.0f, +0.0f, +0.0f, -0.0f, -0.0f, +0.0f, +0.0f}));
__m256 y0 = _mm256_load_ps((float *) &y[0][i]);
__m256 y1 = _mm256_load_ps((float *) &y[1][i]);
__m256 x0, x1;
srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f);
_mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1);
}
return nof_symbols;
}
#endif /* LV_HAVE_AVX */
// SSE implementation of ZF 2x2 CCD equalizer
#ifdef LV_HAVE_SSE
@ -580,9 +619,6 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
uint32_t nof_symbols) {
uint32_t i = 0;
/* Conjugate mask */
__m128 conj_mask = (__m128) {+0.0f, -0.0f, +0.0f, -0.0f};
for (i = 0; i < nof_symbols; i += 2) {
/* Load channel */
__m128 h00i = _mm_load_ps((float *) &h[0][0][i]);
@ -596,21 +632,12 @@ int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
__m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f}));
__m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f}));
__m128 detmult1 = PROD(h00, h11);
__m128 detmult2 = PROD(h01, h10);
__m128 det = _mm_sub_ps(detmult1, detmult2);
__m128 detconj = _mm_xor_ps(det, conj_mask);
__m128 detabs2 = PROD(det, detconj);
__m128 detabs2rec = _mm_rcp_ps(detabs2);
detabs2rec = _mm_shuffle_ps(detabs2rec, detabs2rec, _MM_SHUFFLE(2, 2, 0, 0));
__m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec), (__m128) {2.0f, 2.0f, 2.0f, 2.0f});
__m128 y0 = _mm_load_ps((float *) &y[0][i]);
__m128 y1 = _mm_load_ps((float *) &y[1][i]);
__m128 x0 = PROD(_mm_sub_ps(PROD(h11, y0), PROD(h01, y1)), detrec);
__m128 x1 = PROD(_mm_sub_ps(PROD(h00, y1), PROD(h10, y0)), detrec);
__m128 x0, x1;
srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, 2.0f);
_mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1);
@ -659,11 +686,15 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT
{
if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) {
#ifdef LV_HAVE_AVX
return srslte_predecoding_ccd_2x2_zf_avx(y, h, x, nof_symbols);
#else
#ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols);
#else
return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols);
#endif
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX */
} else {
fprintf(stderr, "Error predecoding CCD: Invalid number of layers %d\n", nof_layers);
return -1;
@ -676,11 +707,535 @@ int srslte_predecoding_ccd_zf(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORT
return SRSLTE_ERROR;
}
/* PMI Select for 1 layer */
int srslte_precoding_pmi_select_1l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols,
float noise_estimate, uint32_t *pmi,
float sinr_list[SRSLTE_MAX_CODEBOOKS]) {
#define SQRT1_2 ((float)M_SQRT1_2);
float max_sinr = 0.0;
uint32_t i, count;
for (i = 0; i < 4; i++) {
sinr_list[i] = 0;
count = 0;
for (uint32_t j = 0; j < nof_symbols; j += 100) {
/* 0. Load channel matrix */
cf_t h00 = h[0][0][j];
cf_t h01 = h[1][0][j];
cf_t h10 = h[0][1][j];
cf_t h11 = h[1][1][j];
/* 1. B = W'* H' */
cf_t a0, a1;
switch(i) {
case 0:
a0 = conjf(h00) + conjf(h01);
a1 = conjf(h10) + conjf(h11);
break;
case 1:
a0 = conjf(h00) - conjf(h01);
a1 = conjf(h10) - conjf(h11);
break;
case 2:
a0 = conjf(h00) - _Complex_I * conjf(h01);
a1 = conjf(h10) - _Complex_I * conjf(h11);
break;
case 3:
a0 = conjf(h00) + _Complex_I * conjf(h01);
a1 = conjf(h10) + _Complex_I * conjf(h11);
break;
}
a0 *= SQRT1_2;
a1 *= SQRT1_2;
/* 2. B = W' * H' * H = A * H */
cf_t b0 = a0*h00 + a1*h10;
cf_t b1 = a0*h01 + a1*h11;
/* 3. C = W' * H' * H * W' = B * W */
cf_t c;
switch(i) {
case 0:
c = b0 + b1;
break;
case 1:
c = b0 - b1;
break;
case 2:
c = b0 + _Complex_I*b1;
break;
case 3:
c = b0 - _Complex_I*b1;
break;
default:
return SRSLTE_ERROR;
}
c *= SQRT1_2;
/* Add for averaging */
sinr_list[i] += crealf(c);
count ++;
}
/* Divide average by noise */
sinr_list[i] /= noise_estimate*count;
if (sinr_list[i] > max_sinr) {
max_sinr = sinr_list[i];
*pmi = i;
}
}
INFO("Precoder PMI Select for 1 layer SINR=[%.1fdB; %.1fdB; %.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]),
10*log10(sinr_list[2]), 10*log10(sinr_list[3]), *pmi);
return i;
}
/* PMI Select for 2 layers */
int srslte_precoding_pmi_select_2l (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols,
float noise_estimate, uint32_t *pmi,
float sinr_list[SRSLTE_MAX_CODEBOOKS]) {
float max_sinr = 0.0;
uint32_t i, count;
for (i = 0; i < 2; i++) {
sinr_list[i] = 0;
count = 0;
for (uint32_t j = 0; j < nof_symbols; j += 100) {
/* 0. Load channel matrix */
cf_t h00 = h[0][0][j];
cf_t h01 = h[1][0][j];
cf_t h10 = h[0][1][j];
cf_t h11 = h[1][1][j];
/* 1. B = W'* H' */
cf_t a00, a01, a10, a11;
switch(i) {
case 0:
a00 = conjf(h00) + conjf(h01);
a01 = conjf(h10) + conjf(h11);
a10 = conjf(h00) - conjf(h01);
a11 = conjf(h10) - conjf(h11);
break;
case 1:
a00 = conjf(h00) - _Complex_I*conjf(h01);
a01 = conjf(h10) - _Complex_I*conjf(h11);
a10 = conjf(h00) + _Complex_I*conjf(h01);
a11 = conjf(h10) + _Complex_I*conjf(h11);
break;
default:
return SRSLTE_ERROR;
}
a00 *= 0.5f;
a01 *= 0.5f;
a10 *= 0.5f;
a11 *= 0.5f;
/* 2. B = W' * H' * H = A * H */
cf_t b00 = a00*h00 + a01*h10;
cf_t b01 = a00*h01 + a01*h11;
cf_t b10 = a10*h00 + a11*h10;
cf_t b11 = a10*h01 + a11*h11;
/* 3. C = W' * H' * H * W' = B * W */
cf_t c00, c01, c10, c11;
switch(i) {
case 0:
c00 = b00 + b01;
c01 = b00 - b01;
c10 = b10 + b11;
c11 = b10 - b11;
break;
case 1:
c00 = b00 + _Complex_I*b01;
c01 = b00 - _Complex_I*b01;
c10 = b10 + _Complex_I*b11;
c11 = b10 - _Complex_I*b11;
break;
default:
return SRSLTE_ERROR;
}
c00 *= 0.5;
c01 *= 0.5;
c10 *= 0.5;
c11 *= 0.5;
/* 4. C += noise * I */
c00 += noise_estimate;
c11 += noise_estimate;
/* 5. detC */
cf_t detC = c00*c11 - c01*c10;
cf_t inv_detC = conjf(detC)/(crealf(detC)*crealf(detC) + cimagf(detC)*cimagf(detC));
cf_t den0 = noise_estimate*c00*inv_detC;
cf_t den1 = noise_estimate*c11*inv_detC;
float gamma0 = crealf((conjf(den0)/(crealf(den0)*crealf(den0) + cimagf(den0)*cimagf(den0))) - 1);
float gamma1 = crealf((conjf(den1)/(crealf(den1)*crealf(den1) + cimagf(den1)*cimagf(den1))) - 1);
/* Add for averaging */
sinr_list[i] += (gamma0 + gamma1);
count ++;
}
/* Divide average by noise */
sinr_list[i] /= (2*count);
if (sinr_list[i] > max_sinr) {
max_sinr = sinr_list[i];
*pmi = i;
}
}
INFO("Precoder PMI Select for 2 layers SINR=[%.1fdB; %.1fdB] PMI=%d\n", 10*log10(sinr_list[0]), 10*log10(sinr_list[1]), *pmi);
return i;
}
int srslte_precoding_pmi_select (cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_symbols,
float noise_estimate, int nof_layers, uint32_t *pmi,
float sinr[SRSLTE_MAX_CODEBOOKS]) {
int ret;
if (sinr == NULL || pmi == NULL) {
ERROR("Null pointer");
ret = SRSLTE_ERROR_INVALID_INPUTS;
} else if (nof_layers == 1) {
ret = srslte_precoding_pmi_select_1l(h, nof_symbols, noise_estimate, pmi, sinr);
} else if (nof_layers == 2) {
ret = srslte_precoding_pmi_select_2l(h, nof_symbols, noise_estimate, pmi, sinr);
} else {
ERROR("Wrong number of layers");
ret = SRSLTE_ERROR_INVALID_INPUTS;
}
return ret;
}
// Generic implementation of ZF 2x2 Spatial Multiplexity equalizer
int srslte_predecoding_multiplex_2x2_zf(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) {
int i = 0;
float norm = 1.0;
switch(codebook_idx) {
case 0:
norm = (float) M_SQRT2;
break;
case 1:
case 2:
norm = 2.0f;
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
#ifdef LV_HAVE_AVX
for (/* i = 0*/; i < nof_symbols; i += 4) {
__m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i]));
__m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i]));
__m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i]));
__m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i]));
__m256 h00, h01, h10, h11;
switch (codebook_idx) {
case 0:
h00 = _h00;
h01 = _h10;
h10 = _h01;
h11 = _h11;
break;
case 1:
h00 = _mm256_add_ps(_h00, _h10);
h01 = _mm256_sub_ps(_h00, _h10);
h10 = _mm256_add_ps(_h01, _h11);
h11 = _mm256_sub_ps(_h01, _h11);
break;
case 2:
h00 = _mm256_add_ps(_h00, _MM256_MULJ_PS(_h10));
h01 = _mm256_sub_ps(_h00, _MM256_MULJ_PS(_h10));
h10 = _mm256_add_ps(_h01, _MM256_MULJ_PS(_h11));
h11 = _mm256_sub_ps(_h01, _MM256_MULJ_PS(_h11));
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
__m256 y0 = _mm256_load_ps((float *) &y[0][i]);
__m256 y1 = _mm256_load_ps((float *) &y[1][i]);
__m256 x0, x1;
srslte_algebra_2x2_zf_avx(y0, y1, h00, h01, h10, h11, &x0, &x1, norm);
_mm256_store_ps((float *) &x[0][i], x0);
_mm256_store_ps((float *) &x[1][i], x1);
}
if (i > nof_symbols) {
i -= 4;
}
#endif /* LV_HAVE_AVX */
#ifdef LV_HAVE_SSE
for (/* i = 0*/; i < nof_symbols; i += 2) {
__m128 _h00 = _mm_load_ps((float*)&(h[0][0][i]));
__m128 _h01 = _mm_load_ps((float*)&(h[0][1][i]));
__m128 _h10 = _mm_load_ps((float*)&(h[1][0][i]));
__m128 _h11 = _mm_load_ps((float*)&(h[1][1][i]));
__m128 h00, h01, h10, h11;
switch (codebook_idx) {
case 0:
h00 = _h00;
h01 = _h10;
h10 = _h01;
h11 = _h11;
break;
case 1:
h00 = _mm_add_ps(_h00, _h10);
h01 = _mm_sub_ps(_h00, _h10);
h10 = _mm_add_ps(_h01, _h11);
h11 = _mm_sub_ps(_h01, _h11);
break;
case 2:
h00 = _mm_add_ps(_h00, _MM_MULJ_PS(_h10));
h01 = _mm_sub_ps(_h00, _MM_MULJ_PS(_h10));
h10 = _mm_add_ps(_h01, _MM_MULJ_PS(_h11));
h11 = _mm_sub_ps(_h01, _MM_MULJ_PS(_h11));
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
__m128 y0 = _mm_load_ps((float *) &y[0][i]);
__m128 y1 = _mm_load_ps((float *) &y[1][i]);
__m128 x0, x1;
srslte_algebra_2x2_zf_sse(y0, y1, h00, h01, h10, h11, &x0, &x1, norm);
_mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1);
}
if (i > nof_symbols) {
i -= 2;
}
#endif /* LV_HAVE_SSE */
for (/*int i = 0*/; i < nof_symbols; i++) {
cf_t h00, h01, h10, h11, det;
switch(codebook_idx) {
case 0:
h00 = h[0][0][i];
h01 = h[1][0][i];
h10 = h[0][1][i];
h11 = h[1][1][i];
break;
case 1:
h00 = h[0][0][i] + h[1][0][i];
h01 = h[0][0][i] - h[1][0][i];
h10 = h[0][1][i] + h[1][1][i];
h11 = h[0][1][i] - h[1][1][i];
break;
case 2:
h00 = h[0][0][i] + _Complex_I*h[1][0][i];
h01 = h[0][0][i] - _Complex_I*h[1][0][i];
h10 = h[0][1][i] + _Complex_I*h[1][1][i];
h11 = h[0][1][i] - _Complex_I*h[1][1][i];
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
det = (h00 * h11 - h01 * h10);
det = conjf(det) * (norm / (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;
}
return SRSLTE_SUCCESS;
}
// Generic implementation of MRC 2x1 (two antennas into one layer) Spatial Multiplexing equalizer
int srslte_predecoding_multiplex_2x1_mrc(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) {
int i = 0;
#ifdef LV_HAVE_AVX
for (/* i = 0*/; i < nof_symbols; i += 4) {
__m256 _h00 = _mm256_load_ps((float*)&(h[0][0][i]));
__m256 _h01 = _mm256_load_ps((float*)&(h[0][1][i]));
__m256 _h10 = _mm256_load_ps((float*)&(h[1][0][i]));
__m256 _h11 = _mm256_load_ps((float*)&(h[1][1][i]));
__m256 h0, h1;
switch (codebook_idx) {
case 0:
h0 = _mm256_add_ps(_h00, _h10);
h1 = _mm256_add_ps(_h01, _h11);
break;
case 1:
h0 = _mm256_sub_ps(_h00, _h10);
h1 = _mm256_sub_ps(_h01, _h11);
break;
case 2:
h0 = _mm256_add_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001));
h1 = _mm256_add_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001));
break;
case 3:
h0 = _mm256_sub_ps(_h00, _mm256_permute_ps(_MM256_CONJ_PS(_h10), 0b10110001));
h1 = _mm256_sub_ps(_h01, _mm256_permute_ps(_MM256_CONJ_PS(_h11), 0b10110001));
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
__m256 h0_2 = _mm256_mul_ps(h0, h0);
__m256 h1_2 = _mm256_mul_ps(h1, h1);
__m256 hh0 = _mm256_add_ps(_mm256_movehdup_ps(h0_2), _mm256_moveldup_ps(h0_2));
__m256 hh1 = _mm256_add_ps(_mm256_movehdup_ps(h1_2), _mm256_moveldup_ps(h1_2));
__m256 hh = _mm256_add_ps(hh0, hh1);
__m256 hhrec = _mm256_rcp_ps(hh);
hhrec = _mm256_mul_ps(hhrec, (__m256){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2,
(float) M_SQRT2,(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2});
__m256 y0 = _mm256_load_ps((float*)&y[0][i]);
__m256 y1 = _mm256_load_ps((float*)&y[1][i]);
__m256 x0 = _mm256_add_ps(_MM256_PROD_PS(_MM256_CONJ_PS(h0), y0), _MM256_PROD_PS(_MM256_CONJ_PS(h1), y1));
x0 = _mm256_mul_ps(hhrec, x0);
_mm256_store_ps((float*)&x[0][i], x0);
}
if (i > nof_symbols) {
i -= 4;
}
#endif /* LV_HAVE_AVX */
#ifdef LV_HAVE_SSE
for (/* i = 0*/; i < nof_symbols; i += 2) {
__m128 _h00 = _mm_load_ps((float*)&(h[0][0][i]));
__m128 _h01 = _mm_load_ps((float*)&(h[0][1][i]));
__m128 _h10 = _mm_load_ps((float*)&(h[1][0][i]));
__m128 _h11 = _mm_load_ps((float*)&(h[1][1][i]));
__m128 h0, h1;
switch (codebook_idx) {
case 0:
h0 = _mm_add_ps(_h00, _h10);
h1 = _mm_add_ps(_h01, _h11);
break;
case 1:
h0 = _mm_sub_ps(_h00, _h10);
h1 = _mm_sub_ps(_h01, _h11);
break;
case 2:
h0 = _mm_add_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001));
h1 = _mm_add_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001));
break;
case 3:
h0 = _mm_sub_ps(_h00, _mm_permute_ps(_MM_CONJ_PS(_h10), 0b10110001));
h1 = _mm_sub_ps(_h01, _mm_permute_ps(_MM_CONJ_PS(_h11), 0b10110001));
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
__m128 h0_2 = _mm_mul_ps(h0, h0);
__m128 h1_2 = _mm_mul_ps(h1, h1);
__m128 hh0 = _mm_add_ps(_mm_movehdup_ps(h0_2), _mm_moveldup_ps(h0_2));
__m128 hh1 = _mm_add_ps(_mm_movehdup_ps(h1_2), _mm_moveldup_ps(h1_2));
__m128 hh = _mm_add_ps(hh0, hh1);
__m128 hhrec = _mm_rcp_ps(hh);
hhrec = _mm_mul_ps(hhrec, (__m128){(float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2, (float) M_SQRT2});
__m128 y0 = _mm_load_ps((float*)&y[0][i]);
__m128 y1 = _mm_load_ps((float*)&y[1][i]);
__m128 x0 = _mm_add_ps(_MM_PROD_PS(_MM_CONJ_PS(h0), y0), _MM_PROD_PS(_MM_CONJ_PS(h1), y1));
x0 = _mm_mul_ps(hhrec, x0);
_mm_store_ps((float*)&x[0][i], x0);
}
if (i > nof_symbols) {
i -= 2;
}
#endif /* LV_HAVE_SSE */
for (/*i = 0*/; i < nof_symbols; i += 1) {
cf_t h0, h1;
float hh;
switch(codebook_idx) {
case 0:
h0 = h[0][0][i] + h[1][0][i];
h1 = h[0][1][i] + h[1][1][i];
break;
case 1:
h0 = h[0][0][i] - h[1][0][i];
h1 = h[0][1][i] - h[1][1][i];
break;
case 2:
h0 = h[0][0][i] + _Complex_I * h[1][0][i];
h1 = h[0][1][i] + _Complex_I * h[1][1][i];
break;
case 3:
h0 = h[0][0][i] - _Complex_I * h[1][0][i];
h1 = h[0][1][i] - _Complex_I * h[1][1][i];
break;
default:
fprintf(stderr, "Wrong codebook_idx=%d\n", codebook_idx);
return SRSLTE_ERROR;
}
hh = (float) M_SQRT2/(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;
}
return SRSLTE_SUCCESS;
}
int srslte_predecoding_multiplex_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 codebook_idx, int nof_symbols)
{
if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) {
return srslte_predecoding_multiplex_2x2_zf(y, h, x, codebook_idx, nof_symbols);
} else {
return srslte_predecoding_multiplex_2x1_mrc(y, h, x, codebook_idx, nof_symbols);
}
} else if (nof_ports == 4) {
fprintf(stderr, "Error predecoding CCD: Only 2 ports supported\n");
} else {
fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant);
}
return SRSLTE_ERROR;
}
/* 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], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) {
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) {
if (nof_ports > SRSLTE_MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", SRSLTE_MAX_PORTS,
@ -722,10 +1277,11 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
}
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
fprintf(stderr, "Spatial multiplexing not supported\n");
return -1;
return srslte_predecoding_multiplex_zf(y, h, x, nof_rxant, nof_ports, nof_layers, codebook_idx, nof_symbols);
default:
return SRSLTE_ERROR;
}
return 0;
return SRSLTE_ERROR;
}
@ -813,9 +1369,70 @@ 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 i;
if (nof_ports == 2) {
if (nof_layers == 1) {
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);
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);
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);
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);
break;
default:
fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n",
codebook_idx, nof_layers, nof_ports);
return SRSLTE_ERROR;
}
} 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);
break;
case 1:
for (i = 0; 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];
}
break;
case 2:
for (i = 0; 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];
}
break;
case 3:
default:
fprintf(stderr, "Invalid multiplex combination: codebook_idx=%d, nof_layers=%d, nof_ports=%d\n",
codebook_idx, nof_layers, nof_ports);
return SRSLTE_ERROR;
}
} else {
ERROR("Not implemented");
}
} else {
ERROR("Not implemented");
}
return SRSLTE_SUCCESS;
}
/* 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 nof_symbols, srslte_mimo_type_t type) {
int nof_ports, int codebook_idx, int nof_symbols, 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,
@ -829,29 +1446,30 @@ 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);
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(x[0], y[0], nof_symbols);
} else {
fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) {
return srslte_precoding_diversity(x, y, nof_ports, nof_symbols);
} else {
fprintf(stderr,
"Error number of layers must equal number of ports in transmit diversity\n");
return -1;
}
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
fprintf(stderr, "Spatial multiplexing not supported\n");
return -1;
case SRSLTE_MIMO_TYPE_CDD:
return srslte_precoding_cdd(x, y, nof_layers, nof_ports, nof_symbols);
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) {
return srslte_precoding_single(x[0], y[0], nof_symbols);
} else {
fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports\n");
return -1;
}
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (nof_ports == nof_layers) {
return srslte_precoding_diversity(x, y, nof_ports, nof_symbols);
} 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);
default:
return SRSLTE_ERROR;
}
return 0;
return SRSLTE_ERROR;
}

@ -52,7 +52,14 @@ add_test(precoding_single precoding_test -n 1000 -m single)
add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2)
add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)
add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2)
add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000)
add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0)
add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1)
add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2)
add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3)
add_test(precoding_multiplex_2l_cb0 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0)
add_test(precoding_multiplex_2l_cb1 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1)
add_test(precoding_multiplex_2l_cb2 precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2)

@ -38,6 +38,7 @@
#define MSE_THRESHOLD 0.0005
int nof_symbols = 1000;
uint32_t codebook_idx = 0;
int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
char *mimo_type_name = NULL;
@ -46,11 +47,12 @@ void usage(char *prog) {
"Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
" -r [nof_rx_ports]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols);
printf("\t-c codebook_idx [Default %d]\n\n", codebook_idx);
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "mplnr")) != -1) {
while ((opt = getopt(argc, argv, "mplnrc")) != -1) {
switch (opt) {
case 'n':
nof_symbols = atoi(argv[optind]);
@ -67,6 +69,9 @@ void parse_args(int argc, char **argv) {
case 'm':
mimo_type_name = argv[optind];
break;
case 'c':
codebook_idx = (uint32_t) atoi(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
@ -116,16 +121,13 @@ void populate_channel_single(cf_t *h) {
void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) {
switch (type) {
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
case SRSLTE_MIMO_TYPE_CDD:
populate_channel_cdd(h, (uint32_t) nof_re);
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
populate_channel_diversity(h, (uint32_t) nof_re);
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
fprintf(stderr, "Error: not implemented channel emulator\n");
exit(-1);
//break;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
default:
populate_channel_single(h[0][0]);
@ -158,6 +160,9 @@ int main(int argc, char **argv) {
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
nof_re = nof_layers*nof_symbols;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
nof_re = nof_symbols;
break;
case SRSLTE_MIMO_TYPE_CDD:
nof_re = nof_symbols*nof_tx_ports/nof_layers;
if (nof_rx_ports != 2 || nof_tx_ports != 2) {
@ -223,7 +228,7 @@ int main(int argc, char **argv) {
}
/* Execute Precoding (Tx) */
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols, type) < 0) {
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n");
exit(-1);
}
@ -246,7 +251,7 @@ int main(int argc, char **argv) {
struct timeval t[3];
gettimeofday(&t[1], NULL);
srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
nof_re, type, 0);
codebook_idx, nof_re, type, 0);
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("Execution Time: %ld us\n", t[0].tv_usec);

@ -387,7 +387,7 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
*/
int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi,
uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2)
uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pmi)
{
if (cfg) {
if (grant) {
@ -399,7 +399,7 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r
}
if (srslte_cbsegm(&cfg->cb_segm2, (uint32_t) cfg->grant.mcs2.tbs)) {
fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs.tbs);
fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs2.tbs);
return SRSLTE_ERROR;
}
@ -407,19 +407,41 @@ int srslte_pdsch_cfg_multi(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_r
cfg->sf_idx = sf_idx;
cfg->rv = rvidx;
cfg->rv2 = rvidx2;
cfg->mimo_type = mimo_type;
if (cell.nof_ports == 1 && grant->nof_tb == 1) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
cfg->nof_layers = 1;
} else if (cell.nof_ports == 2 && grant->nof_tb == 1) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
cfg->nof_layers = 2;
} else if (cell.nof_ports == 2 && grant->nof_tb == 2) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_CDD;
cfg->nof_layers = 2;
} else {
INFO("nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, grant->nof_tb);
return SRSLTE_ERROR;
/* Check and configure PDSCH transmission modes */
switch(mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (grant->nof_tb != 1) {
ERROR("Number of transport blocks is not supported for single transmission mode.");
return SRSLTE_ERROR;
}
cfg->nof_layers = 1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (grant->nof_tb != 1) {
ERROR("Number of transport blocks is not supported for transmit diversity mode.");
return SRSLTE_ERROR;
}
cfg->nof_layers = 2;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
if (grant->nof_tb == 1) {
cfg->codebook_idx = pmi;
cfg->nof_layers = 1;
} else {
cfg->codebook_idx = pmi + 1;
cfg->nof_layers = 2;
}
INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n", grant->nof_tb, cfg->nof_layers, cfg->codebook_idx);
break;
case SRSLTE_MIMO_TYPE_CDD:
if (grant->nof_tb != 2) {
ERROR("Number of transport blocks is not supported for CDD transmission mode.");
return SRSLTE_ERROR;
}
cfg->nof_layers = 2;
break;
}
return SRSLTE_SUCCESS;
@ -498,9 +520,9 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
cfg != NULL)
{
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d\n",
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: [%d %d], C_prb=%d\n",
cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re,
cfg->nbits.nof_bits, cfg->rv, cfg->grant.nof_prb);
cfg->nbits.nof_bits, cfg->rv, cfg->rv2, cfg->grant.nof_prb);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
@ -525,17 +547,19 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
}
}
}
INFO("PDSCH Layer demapper and predecode: mimo_type=%d, nof_layers=%d, nof_tb=%d\n", cfg->mimo_type,
cfg->nof_layers, cfg->grant.nof_tb);
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, cfg->nbits.nof_re, noise_estimate);
} else {
int nof_symbols [SRSLTE_MAX_CODEWORDS];
nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / q->cell.nof_ports;
nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / q->cell.nof_ports;
nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / cfg->nof_layers;
nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / cfg->nof_layers;
srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->nbits.nof_re, cfg->mimo_type, 0.0);
cfg->codebook_idx, cfg->nbits.nof_re, cfg->mimo_type, 0.0);
srslte_layerdemap_type(x, (cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, cfg->nof_layers, cfg->grant.nof_tb,
nof_symbols[0], nof_symbols, cfg->mimo_type);
}
@ -616,6 +640,79 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
}
}
int srslte_pdsch_ri_pmi_select(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce,
uint32_t *ri, uint32_t *pmi,
float *current_sinr) {
uint32_t best_pmi_1l;
uint32_t best_pmi_2l;
float sinr_1l[SRSLTE_MAX_CODEBOOKS];
float sinr_2l[SRSLTE_MAX_CODEBOOKS];
float best_sinr_1l = 0.0;
float best_sinr_2l = 0.0;
int n1, n2;
if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) {
n1 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 1, &best_pmi_1l, sinr_1l);
if (n1 < 0) {
ERROR("PMI Select for 1 layer");
return SRSLTE_ERROR;
}
n2 = srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, 2, &best_pmi_2l, sinr_2l);
if (n2 < 0) {
ERROR("PMI Select for 2 layer");
return SRSLTE_ERROR;
}
for (int i = 0; i < n1; i++) {
if (sinr_1l[i] > best_sinr_1l) {
best_sinr_1l = sinr_1l[i];
}
}
for (int i = 0; i < n2; i++) {
if (sinr_2l[i] > best_sinr_2l) {
best_sinr_2l = sinr_2l[i];
}
}
/* Set RI */
if (ri != NULL) {
*ri = (best_sinr_1l > best_sinr_2l) ? 1 : 2;
}
/* Set PMI */
if (pmi != NULL) {
*pmi = (best_sinr_1l > best_sinr_2l) ? best_pmi_1l : best_pmi_2l;
}
/* Set current condition number */
if (current_sinr != NULL) {
if (cfg->nof_layers == 1) {
*current_sinr = sinr_1l[cfg->codebook_idx];
} else if (cfg->nof_layers == 2) {
*current_sinr = sinr_2l[cfg->codebook_idx - 1];
}else {
ERROR("Not implemented number of layers");
return SRSLTE_ERROR;
}
}
/* Print Trace */
if (ri != NULL && pmi != NULL && current_sinr != NULL) {
INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi,
10*log10(*current_sinr), cfg->nof_layers, cfg->codebook_idx);
}
} else {
ERROR("Not implemented configuration");
return SRSLTE_ERROR_INVALID_INPUTS;
}
return SRSLTE_SUCCESS;
}
int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS])
@ -785,7 +882,7 @@ int srslte_pdsch_encode_multi(srslte_pdsch_t *q,
if (q->cell.nof_ports > 1) {
int nof_symbols = srslte_layermap_type((cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, x, cfg->grant.nof_tb, cfg->nof_layers,
(int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type);
srslte_precoding_type(x, q->symbols, q->cell.nof_ports, cfg->nof_layers,
srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx,
nof_symbols, cfg->mimo_type);
} else {
memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t));

@ -85,28 +85,79 @@ target_link_libraries(pdsch_test srslte_phy)
add_test(pdsch_test_qpsk pdsch_test -m 10 -n 50 -r 1)
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100)
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2)
add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100)
add_test(pdsch_test_sin_6 pdsch_test -p 1 -a 2 -w 1 -n 6)
add_test(pdsch_test_sin_12 pdsch_test -p 1 -a 2 -w 1 -n 12)
add_test(pdsch_test_sin_25 pdsch_test -p 1 -a 2 -w 1 -n 25)
add_test(pdsch_test_sin_50 pdsch_test -p 1 -a 2 -w 1 -n 50)
add_test(pdsch_test_sin_75 pdsch_test -p 1 -a 2 -w 1 -n 75)
add_test(pdsch_test_sin_100 pdsch_test -p 1 -a 2 -w 1 -n 100 -m 28)
add_test(pdsch_test_div_6 pdsch_test -p 2 -a 2 -w 1 -n 6)
add_test(pdsch_test_div_12 pdsch_test -p 2 -a 2 -w 1 -n 12)
add_test(pdsch_test_div_25 pdsch_test -p 2 -a 2 -w 1 -n 25)
add_test(pdsch_test_div_50 pdsch_test -p 2 -a 2 -w 1 -n 50)
add_test(pdsch_test_div_75 pdsch_test -p 2 -a 2 -w 1 -n 75)
add_test(pdsch_test_div_100 pdsch_test -p 2 -a 2 -w 1 -n 100 -m 28)
add_test(pdsch_test_cdd_6 pdsch_test -p 2 -a 2 -w 2 -n 6)
add_test(pdsch_test_cdd_12 pdsch_test -p 2 -a 2 -w 2 -n 12)
add_test(pdsch_test_cdd_25 pdsch_test -p 2 -a 2 -w 2 -n 25)
add_test(pdsch_test_cdd_50 pdsch_test -p 2 -a 2 -w 2 -n 50)
add_test(pdsch_test_cdd_75 pdsch_test -p 2 -a 2 -w 2 -n 75)
add_test(pdsch_test_cdd_100 pdsch_test -p 2 -a 2 -w 2 -n 100 -m 28 -M 28)
add_test(pdsch_test_qam64 pdsch_test -n 100)
# PDSCH test for single transmision mode and 2 Rx antennas
add_test(pdsch_test_sin_6 pdsch_test -x single -a 2 -n 6)
add_test(pdsch_test_sin_12 pdsch_test -x single -a 2 -n 12)
add_test(pdsch_test_sin_25 pdsch_test -x single -a 2 -n 25)
add_test(pdsch_test_sin_50 pdsch_test -x single -a 2 -n 50)
add_test(pdsch_test_sin_75 pdsch_test -x single -a 2 -n 75)
add_test(pdsch_test_sin_100 pdsch_test -x single -a 2 -n 100)
# PDSCH test for transmit diversity transmision mode (1 codeword)
add_test(pdsch_test_div_6 pdsch_test -x diversity -a 2 -n 6)
add_test(pdsch_test_div_12 pdsch_test -x diversity -a 2 -n 12)
add_test(pdsch_test_div_25 pdsch_test -x diversity -a 2 -n 25)
add_test(pdsch_test_div_50 pdsch_test -x diversity -a 2 -n 50)
add_test(pdsch_test_div_75 pdsch_test -x diversity -a 2 -n 75)
add_test(pdsch_test_div_100 pdsch_test -x diversity -a 2 -n 100)
# PDSCH test for CDD transmision mode (2 codeword)
add_test(pdsch_test_cdd_6 pdsch_test -x cdd -a 2 -t 0 -n 6)
add_test(pdsch_test_cdd_12 pdsch_test -x cdd -a 2 -t 0 -n 12)
add_test(pdsch_test_cdd_25 pdsch_test -x cdd -a 2 -t 0 -n 25)
add_test(pdsch_test_cdd_50 pdsch_test -x cdd -a 2 -t 0 -n 50)
add_test(pdsch_test_cdd_75 pdsch_test -x cdd -a 2 -t 0 -n 75)
add_test(pdsch_test_cdd_100 pdsch_test -x cdd -a 2 -t 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword)
add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x multiplex -a 2 -p 0 -n 6)
add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x multiplex -a 2 -p 0 -n 12)
add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x multiplex -a 2 -p 0 -n 25)
add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50)
add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75)
add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword)
add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6)
add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12)
add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x multiplex -a 2 -p 1 -n 25)
add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x multiplex -a 2 -p 1 -n 50)
add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x multiplex -a 2 -p 1 -n 75)
add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x multiplex -a 2 -p 1 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 2 (1 codeword)
add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x multiplex -a 2 -p 2 -n 6)
add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x multiplex -a 2 -p 2 -n 12)
add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x multiplex -a 2 -p 2 -n 25)
add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x multiplex -a 2 -p 2 -n 50)
add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x multiplex -a 2 -p 2 -n 75)
add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x multiplex -a 2 -p 2 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 3 (1 codeword)
add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x multiplex -a 2 -p 3 -n 6)
add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x multiplex -a 2 -p 3 -n 12)
add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x multiplex -a 2 -p 3 -n 25)
add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x multiplex -a 2 -p 3 -n 50)
add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x multiplex -a 2 -p 3 -n 75)
add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x multiplex -a 2 -p 3 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword)
add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 6)
add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 12)
add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 25)
add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 50)
add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75)
add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword)
add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6)
add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12)
add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 25)
add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 50)
add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75)
add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100)
########################################################################
# FILE TEST

@ -52,15 +52,17 @@ srslte_cell_t cell = {
SRSLTE_PHICH_R_1_6 // PHICH resources
};
char mimo_type_str [32] = "single";
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t cfi = 2;
uint32_t mcs = 0;
uint32_t mcs2 = 0;
uint32_t subframe = 1;
uint32_t rv_idx = 0;
uint32_t rv_idx2 = 0;
uint32_t rv_idx2 = 1;
uint16_t rnti = 1234;
uint32_t nof_tb = 1;
uint32_t nof_rx_antennas = 1;
uint32_t pmi = 0;
char *input_file = NULL;
void usage(char *prog) {
@ -74,16 +76,16 @@ void usage(char *prog) {
printf("\t-t rv_idx2 [Default %d]\n", rv_idx2);
printf("\t-R rnti [Default %d]\n", rnti);
printf("\t-F cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-w nof_tb [Default %d]\n", nof_tb);
printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-p pmi (multiplex only) [Default %d]\n", pmi);
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "fmMcsrtRFpnwav")) != -1) {
while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) {
switch(opt) {
case 'f':
input_file = argv[optind];
@ -109,8 +111,11 @@ void parse_args(int argc, char **argv) {
case 'F':
cfi = atoi(argv[optind]);
break;
case 'x':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'p':
cell.nof_ports = atoi(argv[optind]);
pmi = (uint32_t) atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
@ -118,9 +123,6 @@ void parse_args(int argc, char **argv) {
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'w':
nof_tb = (uint32_t) atoi(argv[optind]);
break;
case 'a':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
@ -165,14 +167,43 @@ int main(int argc, char **argv) {
bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(softbuffers_tx, sizeof(srslte_softbuffer_tx_t)*SRSLTE_MAX_CODEWORDS);
bzero(softbuffers_rx, sizeof(srslte_softbuffer_rx_t)*SRSLTE_MAX_CODEWORDS);
/* Parse transmission mode */
if (srslte_str2mimotype(mimo_type_str, &mimo_type)) {
ERROR("Wrong transmission mode.");
goto quit;
}
switch(mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
cell.nof_ports = 1;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
case SRSLTE_MIMO_TYPE_CDD:
if (nof_rx_antennas < 2) {
ERROR("At least two receiving antennas are required");
goto quit;
}
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
default:
cell.nof_ports = 2;
break;
}
srslte_ra_dl_dci_t dci;
bzero(&dci, sizeof(srslte_ra_dl_dci_t));
dci.mcs_idx = mcs;
dci.rv_idx = rv_idx;
dci.type0_alloc.rbg_bitmask = 0xffffffff;
dci.tb_en[0] = true;
if (nof_tb > 1) {
/* If transport block 0 is enabled */
if (mcs != 0 || rv_idx != 1) {
dci.mcs_idx = mcs;
dci.rv_idx = rv_idx;
dci.tb_en[0] = true;
}
/* If transport block 0 is disabled */
if (mcs2 != 0 || rv_idx2 != 1) {
dci.mcs_idx_1 = mcs2;
dci.rv_idx_1 = rv_idx2;
dci.tb_en[1] = true;
@ -183,7 +214,9 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error computing resource allocation\n");
return ret;
}
#ifdef DO_OFDM
srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb);
srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb);
@ -201,24 +234,9 @@ int main(int argc, char **argv) {
#endif /* DO_OFDM */
/* Configure PDSCH */
if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2)) {
if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2, mimo_type, pmi)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
/* Select MIMO mode */
if (cell.nof_ports == 1 && nof_tb == 1) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
pdsch_cfg.nof_layers = 1;
} else if (cell.nof_ports == 2 && nof_tb == 1) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
pdsch_cfg.nof_layers = 2;
} else if (cell.nof_ports == 2 && nof_tb == 2) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD;
pdsch_cfg.nof_layers = 2;
} else {
fprintf(stderr, "nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, nof_tb);
exit(-1);
goto quit;
}
/* init memory */
@ -250,7 +268,7 @@ int main(int argc, char **argv) {
}
if (grant.mcs2.tbs) {
data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs);
data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs);
if (!data[1]) {
perror("srslte_vec_malloc");
goto quit;
@ -264,7 +282,7 @@ int main(int argc, char **argv) {
srslte_pdsch_set_rnti(&pdsch_rx, rnti);
for (i = 0; i < nof_tb; i++) {
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (srslte_softbuffer_rx_init(&softbuffers_rx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating RX soft buffer\n");
goto quit;
@ -306,7 +324,7 @@ int main(int argc, char **argv) {
srslte_filesource_t fsrc;
if (srslte_filesource_init(&fsrc, input_file, SRSLTE_COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file);
exit(-1);
goto quit;
}
#ifdef DO_OFDM
srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb));
@ -332,7 +350,7 @@ int main(int argc, char **argv) {
srslte_pdsch_set_rnti(&pdsch_tx, rnti);
for (i = 0; i < nof_tb; i++) {
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (srslte_softbuffer_tx_init(&softbuffers_tx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating TX soft buffer\n");
goto quit;
@ -438,7 +456,7 @@ int main(int argc, char **argv) {
quit:
srslte_pdsch_free(&pdsch_tx);
srslte_pdsch_free(&pdsch_rx);
for (i = 0; i < nof_tb; i++) {
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_free(&softbuffers_tx[i]);
srslte_softbuffer_rx_free(&softbuffers_rx[i]);

@ -202,10 +202,17 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
ce[i][j] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
}
}
uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
if (!data_bytes) {
uint8_t *data_bytes[SRSLTE_MAX_CODEWORDS];
data_bytes[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
if (!data_bytes[0]) {
return;
}
data_bytes[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs/8);
if (!data_bytes[1]) {
return;
}
srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations);
bool input_fft_allocated = false;
@ -272,7 +279,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
uint8_t *data = malloc(grant.mcs.tbs);
srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs);
srslte_bit_unpack_vector(data_bytes[0], data, grant.mcs.tbs);
if (nlhs >= 1) {
plhs[0] = mxCreateLogicalScalar(r == 0);
@ -323,7 +330,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
}
}
free(data_bytes);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data_bytes[i]) {
free(data_bytes[i]);
}
}
free(data);
return;

@ -38,8 +38,8 @@
#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A}; // Only TM1 and TM2 are currently supported
const uint32_t nof_ue_formats = 3;
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A, SRSLTE_DCI_FORMAT2}; // Only TM1, TM2, TM3 and TM4 are currently supported
const uint32_t nof_ue_formats = 4;
static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2;
@ -284,12 +284,33 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c
int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx)
{
return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0);
return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0);
}
int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2)
int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx,
uint32_t rvidx, uint32_t rvidx2, srslte_mimo_type_t mimo_type, uint32_t pinfo)
{
return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2);
uint32_t pmi = 0;
/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */
if (q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
if (q->pdsch_cfg.grant.nof_tb == 1) {
if (pinfo > 0 && pinfo < 5) {
pmi = pinfo - 1;
} else {
ERROR("Not Implemented");
return SRSLTE_ERROR;
}
} else {
if (pinfo < 2) {
pmi = pinfo;
} else {
ERROR("Not Implemented");
return SRSLTE_ERROR;
}
}
}
return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, pmi);
}
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti)
@ -303,6 +324,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint
int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti)
{
srslte_mimo_type_t mimo_type;
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
srslte_ra_dl_grant_t grant;
@ -355,7 +377,39 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
}
}
if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2)) {
switch(dci_msg.format) {
case SRSLTE_DCI_FORMAT1:
case SRSLTE_DCI_FORMAT1A:
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
break;
case SRSLTE_DCI_FORMAT2:
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
break;
case SRSLTE_DCI_FORMAT2A:
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_CDD;
}
break;
/* Not implemented formats */
case SRSLTE_DCI_FORMAT0:
case SRSLTE_DCI_FORMAT1C:
case SRSLTE_DCI_FORMAT1B:
case SRSLTE_DCI_FORMAT1D:
case SRSLTE_DCI_FORMAT2B:
default:
ERROR("Transmission mode not supported.");
return SRSLTE_ERROR;
}
if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2, mimo_type, dci_unpacked.pinfo)) {
ERROR("Configuing PDSCH");
return SRSLTE_ERROR;
}
@ -374,7 +428,10 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
q->pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling srslte_pdsch_decode()\n");
}
}
/* If we are in TM4 (Closed-Loop MIMO), compute condition number */
}
/*
@ -395,6 +452,13 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
}
}
int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) {
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
return srslte_pdsch_ri_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate,
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp),
ri, pmi, current_sinr);
}
uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) {
return q->last_location.ncce;
}

@ -0,0 +1,72 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <immintrin.h>
#include "srslte/phy/utils/algebra.h"
#ifdef LV_HAVE_SSE
inline void srslte_algebra_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11,
__m128 *x0, __m128 *x1, float norm) {
__m128 detmult1 = _MM_PROD_PS(h00, h11);
__m128 detmult2 = _MM_PROD_PS(h01, h10);
__m128 det = _mm_sub_ps(detmult1, detmult2);
__m128 detconj = _MM_CONJ_PS(det);
__m128 detabs2 = _MM_PROD_PS(det, detconj);
__m128 detabs2rec = _mm_rcp_ps(detabs2);
detabs2rec = _mm_moveldup_ps(detabs2rec);
__m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec),
(__m128) {norm, norm, norm, norm});
*x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec);
*x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec);
}
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
inline void srslte_algebra_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11,
__m256 *x0, __m256 *x1, float norm) {
__m256 detmult1 = _MM256_PROD_PS(h00, h11);
__m256 detmult2 = _MM256_PROD_PS(h01, h10);
__m256 det = _mm256_sub_ps(detmult1, detmult2);
__m256 detconj = _MM256_CONJ_PS(det);
__m256 sqdet = _mm256_mul_ps(det, det);
__m256 detabs2 = _mm256_add_ps(_mm256_movehdup_ps(sqdet), _mm256_moveldup_ps(sqdet));
__m256 detabs2rec = _mm256_rcp_ps(detabs2);
__m256 detrec = _mm256_mul_ps(_mm256_mul_ps(detconj, detabs2rec),
(__m256) {norm, norm, norm, norm, norm, norm, norm, norm});
*x0 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h11, y0), _MM256_PROD_PS(h01, y1)), detrec);
*x1 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h00, y1), _MM256_PROD_PS(h10, y0)), detrec);
}
#endif /* LV_HAVE_AVX */
Loading…
Cancel
Save