Merge with next_with_matlab
This commit is contained in:
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_qam64 pdsch_test -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)
|
||||
# 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)
|
||||
|
||||
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)
|
||||
# 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)
|
||||
|
||||
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)
|
||||
# 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…
Reference in New Issue