PUSCH + CQI (short and long) + HARQ + RI working in test

master
Ismael Gomez 9 years ago
parent 26a51bd86a
commit b934a27075

@ -57,10 +57,18 @@ IF(VOLK_FOUND)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_multiply_32f HAVE_VOLK_MULT_REAL2_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_16i_max_star_16i HAVE_VOLK_MAX_STAR_S_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_8i_convert_16i HAVE_VOLK_CONVERT_CI_FUNCTION)
SET(VOLK_DEFINITIONS "HAVE_VOLK")
IF(${HAVE_VOLK_CONVERT_CI_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_CI_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAX_STAR_S_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_STAR_S_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAX_ABS_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION")
ENDIF()

@ -17,6 +17,8 @@ enbConfig.NDLRB = 100;
enbConfig.CFI = 1;
enbConfig.DuplexMode='FDD';
lteCQIDecode
% Transmission mode configuration for PDSCH
pdschConfig.NLayers = 1;
pdschConfig.TxScheme = 'Port0';

@ -55,4 +55,12 @@ SRSLTE_API int srslte_rm_conv_rx(float *input,
float *output,
uint32_t out_len);
/************* FIX THIS. MOVE ALL PROCESSING TO INT16 AND HAVE ONLY 1 IMPLEMENTATION ******/
SRSLTE_API int srslte_rm_conv_rx_s(int16_t *input,
uint32_t in_len,
int16_t *output,
uint32_t out_len);
#endif

@ -55,6 +55,7 @@ typedef struct SRSLTE_API{
uint32_t framebits;
bool tail_biting;
float gain_quant;
int16_t gain_quant_s;
uint32_t poly[3];
int (*decode) (void*, uint8_t*, uint8_t*, uint32_t);
int (*decode_f) (void*, float*, uint8_t*, uint32_t);
@ -72,6 +73,9 @@ SRSLTE_API int srslte_viterbi_init(srslte_viterbi_t *q,
SRSLTE_API void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q,
float gain_quant);
SRSLTE_API void srslte_viterbi_set_gain_quant_s(srslte_viterbi_t *q,
int16_t gain_quant);
SRSLTE_API void srslte_viterbi_free(srslte_viterbi_t *q);
SRSLTE_API int srslte_viterbi_decode_f(srslte_viterbi_t *q,
@ -79,6 +83,11 @@ SRSLTE_API int srslte_viterbi_decode_f(srslte_viterbi_t *q,
uint8_t *data,
uint32_t frame_length);
SRSLTE_API int srslte_viterbi_decode_s(srslte_viterbi_t *q,
int16_t *symbols,
uint8_t *data,
uint32_t frame_length);
SRSLTE_API int srslte_viterbi_decode_uc(srslte_viterbi_t *q,
uint8_t *symbols,
uint8_t *data,

@ -147,6 +147,15 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q,
float noise_estimate,
uint8_t *data);
SRSLTE_API int srslte_pusch_uci_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce,
float noise_estimate,
uint8_t *data,
srslte_uci_data_t *uci_data);
SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q);
SRSLTE_API uint32_t srslte_pusch_last_noi(srslte_pusch_t *q);

@ -124,6 +124,21 @@ SRSLTE_API int srslte_ulsch_decode(srslte_sch_t *q,
int16_t *g_bits,
uint8_t *data);
SRSLTE_API int srslte_ulsch_uci_decode(srslte_sch_t *q,
srslte_pusch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
int16_t *q_bits,
int16_t *g_bits,
uint8_t *data,
srslte_uci_data_t *uci_data);
SRSLTE_API int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q,
srslte_pusch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
int16_t *q_bits,
uint8_t *c_seq,
srslte_uci_data_t *uci_data);
SRSLTE_API float srslte_sch_beta_cqi(uint32_t I_cqi);
SRSLTE_API uint32_t srslte_sch_find_Ioffset_ack(float beta);

@ -39,6 +39,7 @@
#include "srslte/common/phy_common.h"
#include "srslte/phch/pusch_cfg.h"
#include "srslte/fec/crc.h"
#include "srslte/fec/viterbi.h"
#include "srslte/phch/cqi.h"
#define SRSLTE_UCI_MAX_CQI_LEN_PUSCH 512
@ -47,8 +48,12 @@
typedef struct SRSLTE_API {
srslte_crc_t crc;
srslte_viterbi_t viterbi;
uint8_t tmp_cqi[SRSLTE_UCI_MAX_CQI_LEN_PUSCH];
uint8_t encoded_cqi[3*SRSLTE_UCI_MAX_CQI_LEN_PUSCH];
int16_t encoded_cqi_s[3*SRSLTE_UCI_MAX_CQI_LEN_PUSCH];
uint8_t *cqi_table[11];
int16_t *cqi_table_s[11];
} srslte_uci_cqi_pusch_t;
typedef struct SRSLTE_API {
@ -61,6 +66,7 @@ typedef struct SRSLTE_API {
uint32_t uci_ack_len;
bool scheduling_request;
bool channel_selection;
bool cqi_ack;
} srslte_uci_data_t;
typedef enum {
@ -84,6 +90,15 @@ SRSLTE_API int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q,
uint32_t Q_prime_ri,
uint8_t *q_bits);
SRSLTE_API int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q,
srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
float beta,
uint32_t Q_prime_ri,
uint32_t cqi_len,
uint8_t *cqi_data,
bool *cqi_ack);
SRSLTE_API int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data,
uint32_t cqi_len,
uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B]);
@ -95,6 +110,15 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg,
uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ack_bits,
uint8_t *data);
SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t data,
uint32_t O_cqi,
@ -102,5 +126,14 @@ SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ri_bits,
uint8_t *data);
#endif

@ -96,6 +96,7 @@ SRSLTE_API void srslte_vec_square_dist(cf_t symbol, cf_t *points, float *distanc
SRSLTE_API void srslte_vec_sc_add_fff(float *x, float h, float *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
SRSLTE_API void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len);
/* scalar product */
SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
@ -109,6 +110,7 @@ SRSLTE_API void srslte_vec_norm_cfc(cf_t *x, float amplitude, cf_t *y, uint32_t
SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len);
SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len);
SRSLTE_API void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len);
SRSLTE_API void srslte_vec_lut_fuf(float *x, uint32_t *lut, float *y, uint32_t len);
SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len);
@ -136,6 +138,7 @@ SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len);
SRSLTE_API cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len);
SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len);
SRSLTE_API float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len);
SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len);
/* z=x/y vector division (element-wise) */
SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len);
@ -151,12 +154,14 @@ SRSLTE_API float srslte_vec_avg_power_cf(cf_t *x, uint32_t len);
/* return the index of the maximum value in the vector */
SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len);
SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len);
SRSLTE_API int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len);
/* maximum between two vectors */
SRSLTE_API void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len);
/* quantify vector of floats and convert to uint8_t */
/* quantify vector of floats or int16 and convert to uint8_t */
SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len);
SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len);
/* magnitude of each vector element */
SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len);

@ -35,6 +35,7 @@ extern "C" {
#include <stdint.h>
#include "srslte/config.h"
SRSLTE_API int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len);
SRSLTE_API void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len);

@ -152,3 +152,70 @@ int srslte_rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out
return 0;
}
/************* FIX THIS. MOVE ALL PROCESSING TO INT16 AND HAVE ONLY 1 IMPLEMENTATION ******/
/* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
*/
int srslte_rm_conv_rx_s(int16_t *input, uint32_t in_len, int16_t *output, uint32_t out_len) {
int nrows, ndummy, K_p;
int i, j, k;
int d_i, d_j;
int16_t tmp[3 * NCOLS * NROWS_MAX];
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n",
3 * NCOLS * NROWS_MAX);
return -1;
}
K_p = nrows * NCOLS;
ndummy = K_p - out_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < 3 * K_p; i++) {
tmp[i] = SRSLTE_RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
k = 0;
j = 0;
while (k < in_len) {
d_i = (j % K_p) / nrows;
d_j = (j % K_p) % nrows;
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
if (tmp[j] == SRSLTE_RX_NULL) {
tmp[j] = input[k];
} else if (input[k] != SRSLTE_RX_NULL) {
tmp[j] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
if (j == 3 * K_p) {
j = 0;
}
}
/* interleaving and bit selection */
for (i = 0; i < out_len / 3; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < 3; j++) {
int16_t o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i];
if (o != SRSLTE_RX_NULL) {
output[i * 3 + j] = o;
} else {
output[i * 3 + j] = 0;
}
}
}
return 0;
}

@ -133,6 +133,7 @@ int init37(srslte_viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_
q->R = 3;
q->framebits = framebits;
q->gain_quant = 32;
q->gain_quant_s = 4;
q->tail_biting = tail_biting;
q->decode = decode37;
q->free = free37;
@ -169,6 +170,7 @@ int init37_sse(srslte_viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool t
q->R = 3;
q->framebits = framebits;
q->gain_quant = 20;
q->gain_quant_s = 4;
q->tail_biting = tail_biting;
q->decode = decode37_sse;
q->free = free37_sse;
@ -203,6 +205,10 @@ void srslte_viterbi_set_gain_quant(srslte_viterbi_t *q, float gain_quant) {
q->gain_quant = gain_quant;
}
void srslte_viterbi_set_gain_quant_s(srslte_viterbi_t *q, int16_t gain_quant) {
q->gain_quant_s = gain_quant;
}
int srslte_viterbi_init(srslte_viterbi_t *q, srslte_viterbi_type_t type, uint32_t poly[3], uint32_t max_frame_length, bool tail_bitting)
{
switch (type) {
@ -254,6 +260,24 @@ int srslte_viterbi_decode_f(srslte_viterbi_t *q, float *symbols, uint8_t *data,
}
}
/* symbols are int16 */
int srslte_viterbi_decode_s(srslte_viterbi_t *q, int16_t *symbols, uint8_t *data, uint32_t frame_length)
{
uint32_t len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (q->tail_biting) {
len = 3 * frame_length;
} else {
len = 3 * (frame_length + q->K - 1);
}
srslte_vec_quant_suc(symbols, q->symbols_uc, q->gain_quant_s, 127, 255, len);
return srslte_viterbi_decode_uc(q, q->symbols_uc, data, frame_length);
}
int srslte_viterbi_decode_uc(srslte_viterbi_t *q, uint8_t *symbols, uint8_t *data, uint32_t frame_length)
{

@ -224,14 +224,14 @@ int srslte_pusch_init(srslte_pusch_t *q, srslte_cell_t cell) {
q->rnti_is_set = false;
// Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission
q->q = srslte_vec_malloc(sizeof(float) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
// Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission
q->q = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->q) {
goto clean;
}
// Allocate floats for reception (LLRs). Buffer casted to uint8_t for transmission
q->g = srslte_vec_malloc(sizeof(float) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
// Allocate int16 for reception (LLRs). Buffer casted to uint8_t for transmission
q->g = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->g) {
goto clean;
}
@ -460,10 +460,6 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs
return SRSLTE_ERROR;
}
uint8_t tx_bits[10000];
srslte_bit_unpack_vector(q->q, tx_bits, cfg->nbits.nof_bits);
srslte_vec_save_file("tx_bits", tx_bits, sizeof(uint8_t)*cfg->nbits.nof_bits);
if (rnti != q->rnti || !q->rnti_is_set) {
srslte_sequence_t seq;
if (srslte_sequence_pusch(&seq, rnti, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
@ -475,7 +471,7 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs
srslte_scrambling_bytes(&q->seq[cfg->sf_idx], (uint8_t*) q->q, cfg->nbits.nof_bits);
}
// Correct UCI placeholder bits
// Correct UCI placeholder/repetition bits
uint8_t *d = q->q;
for (int i = 0; i < q->dl_sch.nof_ri_ack_bits; i++) {
if (q->dl_sch.ack_ri_bits[i].type == UCI_BIT_PLACEHOLDER) {
@ -492,14 +488,10 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs
}
}
}
srslte_bit_unpack_vector(q->q, tx_bits, cfg->nbits.nof_bits);
srslte_vec_save_file("tx_bits_scram", tx_bits, sizeof(uint8_t)*cfg->nbits.nof_bits);
// Bit mapping
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->q, q->d, cfg->nbits.nof_bits);
srslte_vec_save_file("tx_symbols", q->d, sizeof(cf_t)*cfg->nbits.nof_re);
// DFT precoding
srslte_dft_precoding(&q->dft_precoding, q->d, q->z, cfg->grant.L_prb, cfg->nbits.nof_symb);
@ -511,14 +503,25 @@ int srslte_pusch_uci_encode_rnti(srslte_pusch_t *q, srslte_pusch_cfg_t *cfg, srs
return ret;
}
int srslte_pusch_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce, float noise_estimate,
uint8_t *data)
{
srslte_uci_data_t uci_data;
bzero(&uci_data, sizeof(srslte_uci_data_t));
return srslte_pusch_uci_decode(q, cfg, softbuffer, sf_symbols, ce, noise_estimate, data, &uci_data);
}
/** Decodes the PUSCH from the received symbols
*/
int srslte_pusch_decode(srslte_pusch_t *q,
int srslte_pusch_uci_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce, float noise_estimate,
uint8_t *data)
uint8_t *data, srslte_uci_data_t *uci_data)
{
uint32_t n;
@ -554,19 +557,19 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// DFT predecoding
srslte_dft_predecoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb);
srslte_vec_save_file("rx_symbols", q->d, sizeof(cf_t)*cfg->nbits.nof_re);
// Soft demodulation
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->q, cfg->nbits.nof_re);
srslte_vec_save_file("rx_bits_scram", q->q, sizeof(int16_t)*cfg->nbits.nof_bits);
// Decode RI/HARQ bits before descrambling
if (srslte_ulsch_uci_decode_ri_ack(&q->dl_sch, cfg, softbuffer, q->q, q->seq[cfg->sf_idx].c, uci_data)) {
fprintf(stderr, "Error decoding RI/HARQ bits\n");
return SRSLTE_ERROR;
}
// Descrambling
srslte_scrambling_s_offset(&q->seq[cfg->sf_idx], q->q, 0, cfg->nbits.nof_bits);
srslte_vec_save_file("rx_bits", q->q, sizeof(int16_t)*cfg->nbits.nof_bits);
return srslte_ulsch_decode(&q->dl_sch, cfg, softbuffer, q->q, q->g, data);
return srslte_ulsch_uci_decode(&q->dl_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
} else {
fprintf(stderr, "Must call srslte_pusch_set_rnti() before calling srslte_pusch_decode()\n");
return SRSLTE_ERROR;

@ -519,9 +519,6 @@ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs,
}
}
}
printf("rows=%d, cols=%d, Qm=%d, total=%d, symb=%d\n", rows, cols, Qm, H_prime_total, N_pusch_symbs);
}
/* UL-SCH channel interleaver according to 5.2.2.8 of 36.212 */
@ -554,34 +551,130 @@ void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total,
uint32_t N_pusch_symbs, int16_t *g_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits,
uint8_t *ri_present, uint16_t *inteleaver_lut)
{
// Prepare ri_bits for fast search using temp_buffer
if (nof_ri_bits > 0) {
for (uint32_t i=0;i<nof_ri_bits;i++) {
ri_present[ri_bits[i].position] = 1;
}
}
// Generate interleaver table and interleave samples
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut);
srslte_vec_lut_sss(q_bits, inteleaver_lut, g_bits, H_prime_total*Qm);
}
// Reset temp_buffer because will be reused next time
if (nof_ri_bits > 0) {
for (uint32_t i=0;i<nof_ri_bits;i++) {
ri_present[ri_bits[i].position] = 0;
}
}
}
int srslte_ulsch_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *q_bits, int16_t *g_bits, uint8_t *data)
{
srslte_uci_data_t uci_data;
bzero(&uci_data, sizeof(srslte_uci_data_t));
return srslte_ulsch_uci_decode(q, cfg, softbuffer, q_bits, g_bits, data, &uci_data);
}
/* This is done before scrambling */
int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *q_bits, uint8_t *c_seq, srslte_uci_data_t *uci_data)
{
int ret = 0;
uint32_t Q_prime_ri = 0;
uint32_t Q_prime_ack = 0;
uint32_t nb_q = cfg->nbits.nof_bits;
uint32_t Qm = cfg->grant.Qm;
// Interleave UL-SCH (and RI and CQI)
cfg->last_O_cqi = uci_data->uci_cqi_len;
// Deinterleave and decode HARQ bits
if (uci_data->uci_ack_len > 0) {
float beta = beta_harq_offset[cfg->uci_cfg.I_offset_ack];
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ack);
if (ret < 0) {
return ret;
}
Q_prime_ack = (uint32_t) ret;
// Set zeros to HARQ bits
for (uint32_t i=0;i<Q_prime_ack;i++) {
q_bits[q->ack_ri_bits[i].position] = 0;
}
}
// Deinterleave and decode RI bits
if (uci_data->uci_ri_len > 0) {
float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri];
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri);
if (ret < 0) {
return ret;
}
Q_prime_ri = (uint32_t) ret;
}
q->nof_ri_ack_bits = Q_prime_ri;
return SRSLTE_SUCCESS;
}
int srslte_ulsch_uci_decode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *q_bits, int16_t *g_bits, uint8_t *data, srslte_uci_data_t *uci_data)
{
int ret = 0;
uint32_t Q_prime_ri = q->nof_ri_ack_bits;
uint32_t Q_prime_cqi = 0;
uint32_t e_offset = 0;
uint32_t nb_q = cfg->nbits.nof_bits;
uint32_t Qm = cfg->grant.Qm;
// Deinterleave data and CQI in ULSCH
ulsch_deinterleave(q_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, g_bits, q->ack_ri_bits, Q_prime_ri*Qm,
q->temp_g_bits, q->ul_interleaver);
printf("g_bits=[");
for (int i=0;i<nb_q;i++) {
printf("%d, ", g_bits[i]>0);
// Decode CQI (multiplexed at the front of ULSCH)
if (uci_data->uci_cqi_len > 0) {
struct timeval t[3];
gettimeofday(&t[1], NULL);
ret = srslte_uci_decode_cqi_pusch(&q->uci_cqi, cfg, g_bits,
beta_cqi_offset[cfg->uci_cfg.I_offset_cqi],
Q_prime_ri, uci_data->uci_cqi_len,
uci_data->uci_cqi, &uci_data->cqi_ack);
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("texec=%d us\n", t[0].tv_usec);
if (ret < 0) {
return ret;
}
Q_prime_cqi = (uint32_t) ret;
}
printf("];\n");
return decode_tb(q, softbuffer, &cfg->cb_segm,
cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits,
g_bits, data);
e_offset += Q_prime_cqi*Qm;
// Decode ULSCH
if (cfg->cb_segm.tbs > 0) {
uint32_t G = nb_q/Qm - Q_prime_ri - Q_prime_cqi;
ret = decode_tb(q, softbuffer, &cfg->cb_segm,
Qm, cfg->rv, G*Qm,
&g_bits[e_offset], data);
if (ret) {
return ret;
}
}
return SRSLTE_SUCCESS;
}
int srslte_ulsch_encode(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
@ -619,8 +712,9 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
}
Q_prime_ri = (uint32_t) ret;
}
cfg->last_O_cqi = uci_data.uci_cqi_len;
// Encode CQI
cfg->last_O_cqi = uci_data.uci_cqi_len;
if (uci_data.uci_cqi_len > 0) {
ret = srslte_uci_encode_cqi_pusch(&q->uci_cqi, cfg,
uci_data.uci_cqi, uci_data.uci_cqi_len,
@ -648,12 +742,6 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
}
}
uint8_t kk[10000];
srslte_bit_unpack_vector(g_bits, kk, nb_q);
srslte_vec_save_file("g_bits_tx", kk, nb_q);
printf("g_bits_tx=");
srslte_vec_fprint_b(stdout, kk, nb_q);
// Interleave UL-SCH (and RI and CQI)
ulsch_interleave(g_bits, Qm, nb_q/Qm, cfg->nbits.nof_symb, q_bits, q->ack_ri_bits, Q_prime_ri*Qm,
q->temp_g_bits, q->ul_interleaver);

@ -155,7 +155,7 @@ int main(int argc, char **argv) {
printf("Encoding rv_idx=%d\n",rv_idx);
srslte_uci_cfg_t uci_cfg;
uci_cfg.I_offset_cqi = 7;
uci_cfg.I_offset_cqi = 6;
uci_cfg.I_offset_ri = 2;
uci_cfg.I_offset_ack = 4;
@ -166,19 +166,19 @@ int main(int argc, char **argv) {
srslte_pusch_set_rnti(&pusch, 1234);
srslte_uci_data_t uci_data;
bzero(&uci_data, sizeof(srslte_uci_data_t));
uci_data.uci_cqi_len = 0;
uci_data.uci_ri_len = 0;
uci_data.uci_ack_len = 0;
srslte_uci_data_t uci_data_tx;
srslte_uci_data_t uci_data_rx;
bzero(&uci_data_tx, sizeof(srslte_uci_data_t));
uci_data_tx.uci_cqi_len = 9;
uci_data_tx.uci_ri_len = 0;
uci_data_tx.uci_ack_len = 0;
memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t));
for (uint32_t i=0;i<20;i++) {
uci_data.uci_cqi [i] = 1;
uci_data_tx.uci_cqi [i] = 1;
}
uci_data.uci_ri = 0;
uci_data.uci_ack = 0;
uci_data_tx.uci_ri = 1;
uci_data_tx.uci_ack = 1;
uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp);
sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re);
@ -208,13 +208,13 @@ int main(int argc, char **argv) {
uint32_t ntrials = 100;
if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data, sf_symbols)) {
if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
if (rv_idx > 0) {
cfg.rv = rv_idx;
if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data, sf_symbols)) {
if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
@ -230,22 +230,37 @@ int main(int argc, char **argv) {
}
gettimeofday(&t[1], NULL);
int r = srslte_pusch_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data);
int r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data, &uci_data_rx);
gettimeofday(&t[2], NULL);
get_time_interval(t);
if (r) {
printf("Error decoding\n");
ret = -1;
goto quit;
} else {
ret = 0;
printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec,
(int) t[0].tv_usec/ntrials,
cfg.grant.mcs.tbs,
(float) cfg.grant.mcs.tbs/1000,
(float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials);
}
if (uci_data_tx.uci_ack_len) {
if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) {
printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack);
}
}
if (uci_data_tx.uci_ri_len) {
if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) {
printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri);
}
}
if (uci_data_tx.uci_cqi_len) {
printf("cqi_tx=");
srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len);
printf("cqi_rx=");
srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len);
}
ret = 0;
quit:
srslte_pusch_free(&pusch);
srslte_softbuffer_tx_free(&softbuffer_tx);

@ -40,8 +40,10 @@
#include "srslte/fec/rm_conv.h"
#include "srslte/common/phy_common.h"
#include "srslte/utils/vector.h"
#include "srslte/utils/bit.h"
#include "srslte/utils/debug.h"
/* Table 5.2.2.6.4-1: Basis sequence for (32, O) code */
static uint8_t M_basis_seq[32][11]={
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
@ -102,15 +104,64 @@ static uint8_t M_basis_seq_pucch[20][13]={
{1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
};
void encode_cqi_pusch_block(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t output[32]) {
for (int i=0;i<32;i++) {
output[i] = 0;
for (int n=0;n<nof_bits;n++) {
output[i] = (output[i] + data[n] * M_basis_seq[i][n])%2;
}
}
}
void cqi_pusch_pregen(srslte_uci_cqi_pusch_t *q) {
uint8_t word[11];
for (int i=0;i<11;i++) {
uint32_t nwords = (1<<(i+1));
q->cqi_table[i] = srslte_vec_malloc(sizeof(uint8_t)*nwords*32);
q->cqi_table_s[i] = srslte_vec_malloc(sizeof(int16_t)*nwords*32);
for (uint32_t w=0;w<nwords;w++) {
uint8_t *ptr = word;
srslte_bit_unpack(w, &ptr, i);
encode_cqi_pusch_block(q, word, i, &q->cqi_table[i][32*w]);
for (int j=0;j<32;j++) {
q->cqi_table_s[i][32*w+j] = 2*q->cqi_table[i][32*w+j]-1;
}
}
}
}
void cqi_pusch_pregen_free(srslte_uci_cqi_pusch_t *q) {
for (int i=0;i<11;i++) {
if (q->cqi_table[i]) {
free(q->cqi_table[i]);
}
if (q->cqi_table_s[i]) {
free(q->cqi_table_s[i]);
}
}
}
int srslte_uci_cqi_init(srslte_uci_cqi_pusch_t *q) {
if (srslte_crc_init(&q->crc, SRSLTE_LTE_CRC8, 8)) {
return SRSLTE_ERROR;
}
uint32_t poly[3] = { 0x6D, 0x4F, 0x57 };
if (srslte_viterbi_init(&q->viterbi, SRSLTE_VITERBI_37, poly, SRSLTE_UCI_MAX_CQI_LEN_PUSCH, true)) {
return SRSLTE_ERROR;
}
cqi_pusch_pregen(q);
return SRSLTE_SUCCESS;
}
void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q) {
void srslte_uci_cqi_free(srslte_uci_cqi_pusch_t *q)
{
srslte_viterbi_free(&q->viterbi);
cqi_pusch_pregen_free(q);
}
static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg,
@ -136,21 +187,58 @@ static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg,
*/
int encode_cqi_short(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q)
{
if (nof_bits < SRSLTE_UCI_MAX_CQI_LEN_PUSCH &&
if (nof_bits <= 11 &&
nof_bits > 0 &&
q != NULL &&
data != NULL &&
q_bits != NULL)
{
for (int i=0;i<32;i++) {
q->encoded_cqi[i] = 0;
for (int n=0;n<nof_bits;n++) {
q->encoded_cqi[i] += (data[n] * M_basis_seq[i][n]);
uint8_t *ptr = data;
uint32_t w = srslte_bit_pack(&ptr, nof_bits);
for (int i=0;i<Q;i++) {
q_bits[i] = q->cqi_table[nof_bits-1][w*32+(i%32)];
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
for (int i=0;i<Q;i++) {
q_bits[i] = q->encoded_cqi[i%32]%2;
// For decoding the block-encoded CQI we use ML decoding
int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uint8_t *data, uint32_t nof_bits)
{
if (nof_bits <= 11 &&
nof_bits > 0 &&
q != NULL &&
data != NULL &&
q_bits != NULL)
{
// Accumulate all copies of the 32-length sequence
if (Q>32) {
int i=1;
for (;i<Q/32;i++) {
srslte_vec_sum_sss(&q_bits[i*32], q_bits, q_bits, 32);
}
srslte_vec_sum_sss(&q_bits[i*32], q_bits, q_bits, Q%32);
}
uint32_t max_w = 0;
int32_t max_corr = INT32_MIN;
for (uint32_t w=0;w<(1<<nof_bits);w++) {
// Calculate correlation with pregenerated word and select maximum
int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, 32);
if (corr > max_corr) {
max_corr = corr;
max_w = w;
}
}
// Convert word to bits again
uint8_t *ptr = data;
srslte_bit_unpack(max_w, &ptr, nof_bits);
INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr);
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
@ -168,8 +256,6 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits,
data != NULL &&
q_bits != NULL)
{
int poly[3] = { 0x6D, 0x4F, 0x57 };
encoder.K = 7;
encoder.R = 3;
@ -179,10 +265,14 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits,
memcpy(q->tmp_cqi, data, sizeof(uint8_t) * nof_bits);
srslte_crc_attach(&q->crc, q->tmp_cqi, nof_bits);
srslte_convcoder_encode(&encoder, q->tmp_cqi, q->encoded_cqi, nof_bits + 8);
DEBUG("cqi_crc_tx=", 0);
if (SRSLTE_VERBOSE_ISDEBUG()) {
srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8);
}
DEBUG("CConv output: ", 0);
srslte_convcoder_encode(&encoder, q->tmp_cqi, q->encoded_cqi, nof_bits + 8);
DEBUG("cconv_tx=", 0);
if (SRSLTE_VERBOSE_ISDEBUG()) {
srslte_vec_fprint_b(stdout, q->encoded_cqi, 3 * (nof_bits + 8));
}
@ -195,6 +285,45 @@ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits,
}
}
int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q,
uint8_t *data, uint32_t nof_bits)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (nof_bits + 8 < SRSLTE_UCI_MAX_CQI_LEN_PUSCH &&
q != NULL &&
data != NULL &&
q_bits != NULL)
{
srslte_rm_conv_rx_s(q_bits, Q, q->encoded_cqi_s, 3 * (nof_bits + 8));
// Set viterbi normalization based on amplitude
int16_t max = srslte_vec_max_star_si(q->encoded_cqi_s, 3 * (nof_bits + 8));
srslte_viterbi_set_gain_quant_s(&q->viterbi, max/36);
DEBUG("cconv_rx=", 0);
if (SRSLTE_VERBOSE_ISDEBUG()) {
srslte_vec_fprint_s(stdout, q->encoded_cqi_s, 3 * (nof_bits + 8));
}
srslte_viterbi_decode_s(&q->viterbi, q->encoded_cqi_s, q->tmp_cqi, nof_bits + 8);
DEBUG("cqi_crc_rx=", 0);
if (SRSLTE_VERBOSE_ISDEBUG()) {
srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8);
}
ret = srslte_crc_checksum(&q->crc, q->tmp_cqi, nof_bits + 8);
if (ret == 0) {
memcpy(data, q->tmp_cqi, nof_bits*sizeof(uint8_t));
ret = 1;
} else {
ret = 0;
}
}
return ret;
}
/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212
*/
int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B])
@ -213,6 +342,44 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b
}
}
/* Encode UCI CQI/PMI
*/
int srslte_uci_decode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
float beta, uint32_t Q_prime_ri, uint32_t cqi_len,
uint8_t *cqi_data, bool *cqi_ack)
{
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Q_prime = Q_prime_cqi(cfg, cqi_len, beta, Q_prime_ri);
int ret = SRSLTE_ERROR;
if (cqi_len <= 11) {
ret = decode_cqi_short(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len);
} else {
ret = decode_cqi_long(q, q_bits, Q_prime*cfg->grant.Qm, cqi_data, cqi_len);
if (ret == 1) {
if (cqi_ack) {
*cqi_ack = true;
}
ret = 0;
} else if (ret == 0) {
if (cqi_ack) {
*cqi_ack = false;
}
}
}
if (ret) {
return ret;
} else {
return (int) Q_prime;
}
return Q_prime;
}
/* Encode UCI CQI/PMI as described in 5.2.2.6 of 36.212
*/
int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *cfg,
@ -240,22 +407,28 @@ int srslte_uci_encode_cqi_pusch(srslte_uci_cqi_pusch_t *q, srslte_pusch_cfg_t *c
}
}
static void uci_ulsch_interleave_put(srslte_uci_bit_type_t ack_coded_bits[6], uint32_t Qm, srslte_uci_bit_t *ack_bits)
{
for(uint32_t k=0; k<Qm; k++) {
ack_bits[k].type = ack_coded_bits[k];
}
}
/* Generates UCI-ACK bits and computes position in q bits */
static int uci_ulsch_interleave_ack(srslte_uci_bit_type_t ack_coded_bits[6], uint32_t ack_q_bit_idx,
static int uci_ulsch_interleave_ack_gen(uint32_t ack_q_bit_idx,
uint32_t Qm, uint32_t H_prime_total, uint32_t N_pusch_symbs, srslte_cp_t cp,
srslte_uci_bit_t *ack_bits) {
srslte_uci_bit_t *ack_bits)
{
const uint32_t ack_column_set_norm[4] = {2, 3, 8, 9};
const uint32_t ack_column_set_ext[4] = {1, 2, 6, 7};
if (H_prime_total/N_pusch_symbs >= 1+ack_q_bit_idx/4) {
uint32_t row = H_prime_total/N_pusch_symbs-1-ack_q_bit_idx/4;
uint32_t colidx = (3*ack_q_bit_idx)%4;
uint32_t col = SRSLTE_CP_ISNORM(cp)?ack_column_set_norm[colidx]:ack_column_set_ext[colidx];
for(uint32_t k=0; k<Qm; k++) {
ack_bits[k].position = row *Qm + (H_prime_total/N_pusch_symbs)*col*Qm + k;
ack_bits[k].type = ack_coded_bits[k];
}
return SRSLTE_SUCCESS;
} else {
@ -266,9 +439,10 @@ static int uci_ulsch_interleave_ack(srslte_uci_bit_type_t ack_coded_bits[6], uin
}
/* Inserts UCI-RI bits into the correct positions in the g buffer before interleaving */
static int uci_ulsch_interleave_ri(srslte_uci_bit_type_t ri_coded_bits[6], uint32_t ri_q_bit_idx,
static int uci_ulsch_interleave_ri_gen(uint32_t ri_q_bit_idx,
uint32_t Qm, uint32_t H_prime_total, uint32_t N_pusch_symbs, srslte_cp_t cp,
srslte_uci_bit_t *ri_bits) {
srslte_uci_bit_t *ri_bits)
{
static uint32_t ri_column_set_norm[4] = {1, 4, 7, 10};
static uint32_t ri_column_set_ext[4] = {0, 3, 5, 8};
@ -280,7 +454,6 @@ static int uci_ulsch_interleave_ri(srslte_uci_bit_type_t ri_coded_bits[6], uint3
for(uint32_t k=0; k<Qm; k++) {
ri_bits[k].position = row *Qm + (H_prime_total/N_pusch_symbs)*col*Qm + k;
ri_bits[k].type = ri_coded_bits[k];
}
return SRSLTE_SUCCESS;
} else {
@ -317,7 +490,8 @@ static uint32_t Q_prime_ri_ack(srslte_pusch_cfg_t *cfg,
return Q_prime;
}
static void encode_ri_ack(uint8_t data, srslte_uci_bit_type_t q_encoded_bits[6], uint8_t Qm) {
static void encode_ri_ack(uint8_t data, srslte_uci_bit_type_t q_encoded_bits[6], uint8_t Qm)
{
q_encoded_bits[0] = data?UCI_BIT_1:UCI_BIT_0;
q_encoded_bits[1] = UCI_BIT_REPETITION;
for (uint32_t i=2;i<Qm;i++) {
@ -325,6 +499,46 @@ static void encode_ri_ack(uint8_t data, srslte_uci_bit_type_t q_encoded_bits[6],
}
}
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{
uint32_t p0 = pos[0].position;
uint32_t p1 = pos[1].position;
uint32_t q0 = c_seq[p0]?q_bits[p0]:-q_bits[p0];
uint32_t q1 = c_seq[p0]?q_bits[p1]:-q_bits[p1];
return -(q0+q1);
}
/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t *data)
{
int32_t rx_ack = 0;
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, ack_bits);
}
if (data) {
*data = rx_ack>0;
}
return (int) Qprime;
}
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
@ -343,7 +557,37 @@ int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t data,
encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack(q_encoded_bits, i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]);
}
return (int) Qprime;
}
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data)
{
int32_t rx_ri = 0;
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
rx_ri += (int32_t) decode_ri_ack(q_bits, c_seq, ri_bits);
}
if (data) {
*data = rx_ri>0;
}
return (int) Qprime;
@ -368,7 +612,8 @@ int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
encode_ri_ack(data, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ri(q_encoded_bits, i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(q_encoded_bits, cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]);
}
return (int) Qprime;

@ -171,6 +171,13 @@ void srslte_vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) {
}
}
void srslte_vec_sc_add_sss(int16_t *x, int16_t h, int16_t *z, uint32_t len) {
int i;
for (i=0;i<len;i++) {
z[i] += h;
}
}
void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) {
#ifndef HAVE_VOLK_MULT_FLOAT_FUNCTION
int i;
@ -248,6 +255,18 @@ void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len) {
#endif
}
void srslte_vec_convert_ci(int8_t *x, int16_t *z, uint32_t len) {
#ifndef HAVE_VOLK_CONVERT_CI_FUNCTION
int i;
for (i=0;i<len;i++) {
z[i] = ((int16_t) x[i]);
}
#else
volk_8i_convert_16i(z,x,len);
#endif
}
void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len) {
#ifndef LV_HAVE_SSE
int i;
@ -603,6 +622,18 @@ float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len) {
#endif
}
int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len) {
#ifndef LV_HAVE_SSE
uint32_t i;
int32_t res = 0;
for (i=0;i<len;i++) {
res += x[i]*y[i];
}
return res;
#else
return srslte_vec_dot_prod_sss_simd(x, y, len);
#endif
}
float srslte_vec_avg_power_cf(cf_t *x, uint32_t len) {
return crealf(srslte_vec_dot_prod_conj_ccc(x,x,len)) / len;
@ -663,6 +694,24 @@ uint32_t srslte_vec_max_fi(float *x, uint32_t len) {
#endif
}
int16_t srslte_vec_max_star_si(int16_t *x, uint32_t len) {
#ifdef HAVE_VOLK_MAX_STAR_S_FUNCTION
int16_t target=0;
volk_16i_max_star_16i(&target,x,len);
return target;
#else
uint32_t i;
int16_t m=-INT16_MIN;
for (i=0;i<len;i++) {
if (x[i]>m) {
m=x[i];
}
}
return m;
#endif
}
void srslte_vec_max_fff(float *x, float *y, float *z, uint32_t len) {
#ifdef HAVE_VOLK_MAX_VEC_FUNCTION
volk_32f_x2_max_32f(z,x,y,len);
@ -715,3 +764,17 @@ void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, flo
}
}
void srslte_vec_quant_suc(int16_t *in, uint8_t *out, int16_t norm, int16_t offset, int16_t clip, uint32_t len) {
int i;
int16_t tmp;
for (i=0;i<len;i++) {
tmp = (int16_t) (offset + in[i]/norm);
if (tmp < 0)
tmp = 0;
if (tmp > clip)
tmp = clip;
out[i] = (uint8_t) tmp;
}
}

@ -41,6 +41,48 @@
#endif
int srslte_vec_dot_prod_sss_simd(short *x, short *y, uint32_t len)
{
int result = 0;
#ifdef LV_HAVE_SSE
unsigned int number = 0;
const unsigned int points = len / 8;
const __m128i* xPtr = (const __m128i*) x;
const __m128i* yPtr = (const __m128i*) y;
__m128i dotProdVal = _mm_setzero_si128();
__m128i xVal, yVal, zVal;
for(;number < points; number++){
xVal = _mm_load_si128(xPtr);
yVal = _mm_load_si128(yPtr);
zVal = _mm_mullo_epi16(xVal, yVal);
dotProdVal = _mm_add_epi16(dotProdVal, zVal);
xPtr ++;
yPtr ++;
}
short dotProdVector[8];
_mm_store_si128((__m128i*) dotProdVector, dotProdVal);
for (int i=0;i<8;i++) {
result += dotProdVector[i];
}
number = points * 8;
for(;number < len; number++){
result += (x[number] * y[number]);
}
#endif
return result;
}
void srslte_vec_sum_sss_simd(short *x, short *y, short *z, uint32_t len)
{
#ifdef LV_HAVE_SSE

Loading…
Cancel
Save