diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index fafc9b8c9..d9b8d14f7 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -250,9 +250,11 @@ typedef enum SRSLTE_API { SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM, - SRSLTE_MOD_256QAM, + SRSLTE_MOD_256QAM } srslte_mod_t; +#define SRSLTE_NOF_MODULATIONS (SRSLTE_MOD_256QAM + 1) + typedef enum { SRSLTE_DCI_FORMAT0 = 0, SRSLTE_DCI_FORMAT1, diff --git a/lib/include/srslte/phy/modem/demod_hard.h b/lib/include/srslte/phy/modem/demod_hard.h index fe601c3d3..1f940ca0c 100644 --- a/lib/include/srslte/phy/modem/demod_hard.h +++ b/lib/include/srslte/phy/modem/demod_hard.h @@ -36,8 +36,6 @@ #include "modem_table.h" #include "srslte/config.h" -typedef _Complex float cf_t; - typedef struct SRSLTE_API { srslte_mod_t mod; /* In this implementation, mapping table is hard-coded */ } srslte_demod_hard_t; diff --git a/lib/include/srslte/phy/modem/evm.h b/lib/include/srslte/phy/modem/evm.h new file mode 100644 index 000000000..4a6c9552a --- /dev/null +++ b/lib/include/srslte/phy/modem/evm.h @@ -0,0 +1,247 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * 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_EVM_H_ +#define SRSLTE_EVM_H_ + +#include +#include +#include + +/** @struct srslte_evm_buffer_t + * This structure carries the necessary temporary data required for calculating the EVM. + * + * @var max_bits maximum of bits which can support + * @var hard_bits vector that stores hard bits after decision + * @var symbols vector that stores the modulated symbols from the hard bits + */ +typedef struct { + uint32_t max_bits; + uint8_t* hard_bits; + cf_t* symbols; +} srslte_evm_buffer_t; + +/** + * Allocates the EVM calculation buffer + * @param nof_prb that provides the maximum number of bits + * @return EVM buffer pointer + */ +static inline srslte_evm_buffer_t* srslte_evm_buffer_alloc(uint32_t nof_prb) +{ + srslte_evm_buffer_t* q = (srslte_evm_buffer_t*)srslte_vec_malloc(sizeof(srslte_evm_buffer_t)); + + // Check allocation result and number of PRB + if (!q || !nof_prb) { + ERROR("Malloc"); + return q; + } + + // Zero memory the buffer fields + memset(q, 0, sizeof(srslte_evm_buffer_t)); + + // Set max number of bits + q->max_bits = srslte_ra_tbs_from_idx(SRSLTE_RA_NOF_TBS_IDX - 1, nof_prb); + + // Allocate hard bits + q->hard_bits = srslte_vec_u8_malloc(q->max_bits); + if (!q->hard_bits) { + ERROR("Malloc"); + return q; + } + + // Allocate symbols assuming BPSK + q->symbols = srslte_vec_cf_malloc(q->max_bits); + if (!q->symbols) { + ERROR("Malloc"); + return q; + } + + return q; +} + +/** + * Allocates the EVM calculation buffer + * @param nof_prb that provides the maximum number of bits + * @return EVM buffer pointer + */ +static inline void srslte_evm_buffer_resize(srslte_evm_buffer_t* q, uint32_t nof_prb) +{ + + // Assert pointer and number of PRB + if (!q || !nof_prb) { + ERROR("Invalid inputs"); + return; + } + + // Get new number of max bits + uint32_t new_max_bits = srslte_ra_tbs_from_idx(SRSLTE_RA_NOF_TBS_IDX - 1, nof_prb); + + // Return if no resize is required + if (q->max_bits >= new_max_bits) { + return; + } + + // Update with greater value + q->max_bits = new_max_bits; + + // Free hard bits if it was allocated + if (q->hard_bits) { + free(q->hard_bits); + } + + // Allocate hard bits again + q->hard_bits = srslte_vec_u8_malloc(q->max_bits); + if (!q->hard_bits) { + ERROR("Malloc"); + return; + } + + // Free symbols if it was allocated + if (q->symbols) { + free(q->symbols); + } + + // Allocate symbols again + q->symbols = srslte_vec_cf_malloc(q->max_bits); + if (!q->symbols) { + ERROR("Malloc"); + return; + } +} + +/** + * Template for hard decision taking + */ +#define HARD_DECISION(SOFTBITS, HARDBITS, NOF_SOFTBITS) \ + do { \ + for (uint32_t i = 0, k = 0; k < NOF_SOFTBITS; i++) { \ + uint8_t w = 0; \ + for (int j = 0; j < 8 && k < NOF_SOFTBITS; j++, k++) { \ + w |= (SOFTBITS[k] > 0) ? ((uint32_t)1 << (uint32_t)(7 - j)) : 0; \ + } \ + HARDBITS[i] = w; \ + } \ + } while (false) + +/** + * Template RMS EVM calculation for different LLR + */ +#define EVM_RUN_TEMPLATE(LLR_T, SUFFIX) \ + static inline float srslte_evm_run_##SUFFIX(srslte_evm_buffer_t* q, \ + const srslte_modem_table_t* modem_table, \ + const cf_t* symbols, \ + const LLR_T* llr, \ + uint32_t nof_bits) \ + { \ + float evm_rms = NAN; \ + \ + /* Return NAN if EVM buffers, modem table, LLR, symbols or bits missing*/ \ + if (!q || !modem_table || !modem_table->nbits_x_symbol || !llr || !symbols || !nof_bits) { \ + ERROR("Invalid inputs %p %p %p %p %d\n", q, modem_table, llr, symbols, nof_bits); \ + return evm_rms; \ + } \ + \ + /* Limit number of bits to the one supported by the buffer */ \ + nof_bits = SRSLTE_MIN(q->max_bits, nof_bits); \ + \ + /* Calculate number of symbols */ \ + uint32_t nsymbols = nof_bits / modem_table->nbits_x_symbol; \ + \ + /* Hard decision */ \ + HARD_DECISION(llr, q->hard_bits, nof_bits); \ + \ + /* Modulate */ \ + srslte_mod_modulate_bytes(modem_table, q->hard_bits, q->symbols, nof_bits); \ + \ + /* Compute symbol difference */ \ + srslte_vec_sub_ccc(symbols, q->symbols, q->symbols, nsymbols); \ + \ + /* Average squares */ \ + float evm_pow = srslte_vec_avg_power_cf(q->symbols, nsymbols); \ + \ + /* Convert measure to RMS */ \ + evm_rms = sqrtf(evm_pow); \ + \ + return evm_rms; \ + } + +/** @function srslte_evm_run_f + * Calculates the Root Mean Squared EVM given a modulation table, complex symbols, floating point LLR (soft bits) and + * the number of bits. + * + * @param q is the EVM buffers, need to be preallocated + * @param modem_table points at the modulator table + * @param symbols vector carrying the modulated complex symbols + * @param llr softbits + * @param nof_bits number of bits + * @return the measured RMS EVM if no error occurs, otherwise it returns NAN + */ +EVM_RUN_TEMPLATE(float, f) + +/** @function srslte_evm_run_s + * Calculates the Root Mean Squared EVM given a modulation table, complex symbols, fixed integer 16 bit LLR (soft bits) + * and the number of bits. + * + * @param q is the EVM buffers, need to be preallocated + * @param modem_table points at the modulator table + * @param symbols vector carrying the modulated complex symbols + * @param llr softbits + * @param nof_bits number of bits + * @return the measured RMS EVM if no error occurs, otherwise it returns NAN + */ +EVM_RUN_TEMPLATE(int16_t, s) + +/** @function srslte_evm_run_b + * Calculates the Root Mean Squared EVM given a modulation table, complex symbols, fixed integer 8 bit LLR (soft bits) + * and the number of bits. + * + * @param q is the EVM buffers, need to be preallocated + * @param modem_table points at the modulator table + * @param symbols vector carrying the modulated complex symbols + * @param llr softbits + * @param nof_bits number of bits + * @return the measured RMS EVM if no error occurs, otherwise it returns NAN + */ +EVM_RUN_TEMPLATE(int8_t, b) + +#undef EVM_RUN_TEMPLATE +#undef HARD_DECISION + +static inline void srslte_evm_free(srslte_evm_buffer_t* q) +{ + // Check EVM buffer object exist + if (q) { + // Check hard bits were allocated + if (q->hard_bits) { + free(q->hard_bits); + } + + // Check symbols were allocated + if (q->symbols) { + free(q->symbols); + } + + // Free buffer object + free(q); + } +} + +#endif // SRSLTE_EVM_H_ diff --git a/lib/include/srslte/phy/modem/mod.h b/lib/include/srslte/phy/modem/mod.h index 14f7695e9..2cfc54c46 100644 --- a/lib/include/srslte/phy/modem/mod.h +++ b/lib/include/srslte/phy/modem/mod.h @@ -23,7 +23,7 @@ * File: mod.h * * Description: Modulation. - * Supports BPSK, QPSK, 16QAM and 64QAM. + * Supports BPSK, QPSK, 16QAM, 64QAM and 256QAM. * * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 7.1 *****************************************************************************/ @@ -36,8 +36,9 @@ #include "modem_table.h" #include "srslte/config.h" -SRSLTE_API int srslte_mod_modulate(srslte_modem_table_t* table, uint8_t* bits, cf_t* symbols, uint32_t nbits); +SRSLTE_API int srslte_mod_modulate(const srslte_modem_table_t* table, uint8_t* bits, cf_t* symbols, uint32_t nbits); -SRSLTE_API int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits); +SRSLTE_API int +srslte_mod_modulate_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits); #endif // SRSLTE_MOD_H diff --git a/lib/include/srslte/phy/modem/modem_table.h b/lib/include/srslte/phy/modem/modem_table.h index 692ac95a5..37951f5bb 100644 --- a/lib/include/srslte/phy/modem/modem_table.h +++ b/lib/include/srslte/phy/modem/modem_table.h @@ -62,7 +62,6 @@ typedef struct SRSLTE_API { bpsk_packed_t* symbol_table_bpsk; qpsk_packed_t* symbol_table_qpsk; qam16_packed_t* symbol_table_16qam; - qam256_packed_t* symbol_table_256qam; } srslte_modem_table_t; SRSLTE_API void srslte_modem_table_init(srslte_modem_table_t* q); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 9d1138f5e..6a220a060 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -36,6 +36,7 @@ #include "srslte/phy/mimo/layermap.h" #include "srslte/phy/mimo/precoding.h" #include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/modem/evm.h" #include "srslte/phy/modem/mod.h" #include "srslte/phy/phch/dci.h" #include "srslte/phy/phch/pdsch_cfg.h" @@ -72,7 +73,10 @@ typedef struct SRSLTE_API { float* csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */ /* tx & rx objects */ - srslte_modem_table_t mod[5]; + srslte_modem_table_t mod[SRSLTE_NOF_MODULATIONS]; + + // EVM buffers, one for each codeword (avoid concurrency issue with coworker) + srslte_evm_buffer_t* evm_buffer[SRSLTE_MAX_CODEWORDS]; // This is to generate the scrambling seq for multiple CRNTIs srslte_pdsch_user_t** users; @@ -89,6 +93,7 @@ typedef struct { uint8_t* payload; bool crc; float avg_iterations_block; + float evm; } srslte_pdsch_res_t; SRSLTE_API int srslte_pdsch_init_ue(srslte_pdsch_t* q, uint32_t max_prb, uint32_t nof_rx_antennas); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index e1995e222..0d6394f95 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -67,9 +67,9 @@ typedef struct SRSLTE_API { srslte_softbuffer_rx_t* rx[SRSLTE_MAX_CODEWORDS]; } softbuffers; + bool meas_evm_en; bool meas_time_en; uint32_t meas_time_value; - } srslte_pdsch_cfg_t; #endif // SRSLTE_PDSCH_CFG_H diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 7d1debef3..0fefd12d4 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -75,6 +75,8 @@ typedef struct SRSLTE_API { enum { SRSLTE_RA_TYPE2_LOC = 0, SRSLTE_RA_TYPE2_DIST = 1 } mode; } srslte_ra_type2_t; +#define SRSLTE_RA_NOF_TBS_IDX 34 + SRSLTE_API uint32_t srslte_ra_type0_P(uint32_t nof_prb); SRSLTE_API uint32_t srslte_ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1); diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index a22af0141..c06c15504 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -95,13 +95,13 @@ SRSLTE_API void srslte_vec_cf_zero(cf_t* ptr, uint32_t nsamples); SRSLTE_API void srslte_vec_f_zero(float* ptr, uint32_t nsamples); /* print vectors */ -SRSLTE_API void srslte_vec_fprint_c(FILE* stream, cf_t* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_f(FILE* stream, float* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_b(FILE* stream, uint8_t* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_bs(FILE* stream, int8_t* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_byte(FILE* stream, uint8_t* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_i(FILE* stream, int* x, const uint32_t len); -SRSLTE_API void srslte_vec_fprint_s(FILE* stream, short* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_c(FILE* stream, const cf_t* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_f(FILE* stream, const float* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_b(FILE* stream, const uint8_t* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_bs(FILE* stream, const int8_t* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_byte(FILE* stream, const uint8_t* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_i(FILE* stream, const int* x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_s(FILE* stream, const int16_t* x, const uint32_t len); SRSLTE_API void srslte_vec_fprint_hex(FILE* stream, uint8_t* x, const uint32_t len); SRSLTE_API void srslte_vec_sprint_hex(char* str, const uint32_t max_str_len, uint8_t* x, const uint32_t len); diff --git a/lib/src/phy/fec/softbuffer.c b/lib/src/phy/fec/softbuffer.c index 2bb24d0e6..9390006d1 100644 --- a/lib/src/phy/fec/softbuffer.c +++ b/lib/src/phy/fec/softbuffer.c @@ -45,7 +45,7 @@ int srslte_softbuffer_rx_init(srslte_softbuffer_rx_t* q, uint32_t nof_prb) if (q != NULL) { bzero(q, sizeof(srslte_softbuffer_rx_t)); - ret = srslte_ra_tbs_from_idx(33, nof_prb); + ret = srslte_ra_tbs_from_idx(SRSLTE_RA_NOF_TBS_IDX - 1, nof_prb); if (ret != SRSLTE_ERROR) { q->max_cb = (uint32_t)ret / (SRSLTE_TCOD_MAX_LEN_CB - 24) + 1; ret = SRSLTE_ERROR; @@ -163,7 +163,7 @@ int srslte_softbuffer_tx_init(srslte_softbuffer_tx_t* q, uint32_t nof_prb) bzero(q, sizeof(srslte_softbuffer_tx_t)); - ret = srslte_ra_tbs_from_idx(33, nof_prb); + ret = srslte_ra_tbs_from_idx(SRSLTE_RA_NOF_TBS_IDX - 1, nof_prb); if (ret != SRSLTE_ERROR) { q->max_cb = (uint32_t)ret / (SRSLTE_TCOD_MAX_LEN_CB - 24) + 1; diff --git a/lib/src/phy/modem/lte_tables.h b/lib/src/phy/modem/lte_tables.h index 04a10e925..143a785fd 100644 --- a/lib/src/phy/modem/lte_tables.h +++ b/lib/src/phy/modem/lte_tables.h @@ -19,7 +19,7 @@ * */ -typedef _Complex float cf_t; +#include #define BPSK_LEVEL M_SQRT1_2 diff --git a/lib/src/phy/modem/mod.c b/lib/src/phy/modem/mod.c index c7667198e..5bc6c66fb 100644 --- a/lib/src/phy/modem/mod.c +++ b/lib/src/phy/modem/mod.c @@ -30,7 +30,7 @@ /** Low-level API */ -int srslte_mod_modulate(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +int srslte_mod_modulate(const srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) { uint32_t i, j, idx; uint8_t* b_ptr = (uint8_t*)bits; @@ -47,7 +47,7 @@ int srslte_mod_modulate(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, u return j; } -void mod_bpsk_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +static void mod_bpsk_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { uint8_t mask_bpsk[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; uint8_t shift_bpsk[8] = {7, 6, 5, 4, 3, 2, 1, 0}; @@ -60,7 +60,7 @@ void mod_bpsk_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint3 } } -void mod_qpsk_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +static void mod_qpsk_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { uint8_t mask_qpsk[4] = {0xc0, 0x30, 0x0c, 0x03}; uint8_t shift_qpsk[4] = {6, 4, 2, 0}; @@ -73,7 +73,7 @@ void mod_qpsk_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint3 } } -void mod_16qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +static void mod_16qam_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { for (int i = 0; i < nbits / 8; i++) { memcpy(&symbols[2 * i], &q->symbol_table_16qam[bits[i]], sizeof(qam16_packed_t)); @@ -84,7 +84,7 @@ void mod_16qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint } } -void mod_64qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +static void mod_64qam_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { uint8_t in0, in1, in2, in3; uint32_t in80, in81, in82; @@ -124,7 +124,7 @@ void mod_64qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint } } -void mod_256qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +static void mod_256qam_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { for (int i = 0; i < nbits / 8; i++) { symbols[i] = q->symbol_table[bits[i]]; @@ -132,12 +132,12 @@ void mod_256qam_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uin } /* Assumes packet bits as input */ -int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symbols, uint32_t nbits) +int srslte_mod_modulate_bytes(const srslte_modem_table_t* q, const uint8_t* bits, cf_t* symbols, uint32_t nbits) { if (!q->byte_tables_init) { ERROR("Error need to initiated modem tables for packeted bits before calling srslte_mod_modulate_bytes()\n"); - return -1; + return SRSLTE_ERROR; } if (nbits % q->nbits_x_symbol) { ERROR("Error modulator expects number of bits (%d) to be multiple of %d\n", nbits, q->nbits_x_symbol); @@ -161,7 +161,7 @@ int srslte_mod_modulate_bytes(srslte_modem_table_t* q, uint8_t* bits, cf_t* symb break; default: ERROR("srslte_mod_modulate_bytes() accepts QPSK/16QAM/64QAM modulations only\n"); - return -1; + return SRSLTE_ERROR; } return nbits / q->nbits_x_symbol; } diff --git a/lib/src/phy/modem/modem_table.c b/lib/src/phy/modem/modem_table.c index d4c689313..d8f5e7fd8 100644 --- a/lib/src/phy/modem/modem_table.c +++ b/lib/src/phy/modem/modem_table.c @@ -56,9 +56,6 @@ void srslte_modem_table_free(srslte_modem_table_t* q) if (q->symbol_table_16qam) { free(q->symbol_table_16qam); } - if (q->symbol_table_256qam) { - free(q->symbol_table_256qam); - } bzero(q, sizeof(srslte_modem_table_t)); } void srslte_modem_table_reset(srslte_modem_table_t* q) diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 853166461..ed27bd012 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -64,7 +64,7 @@ typedef struct { srslte_sch_t dl_sch; /* Encoder/Decoder data pointers: they must be set before posting start semaphore */ - uint8_t* data; + srslte_pdsch_res_t* data; /* Execution status */ int ret_status; @@ -254,7 +254,7 @@ static int pdsch_init(srslte_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t INFO("Init PDSCH: %d PRBs, max_symbols: %d\n", max_prb, q->max_re); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < SRSLTE_NOF_MODULATIONS; i++) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { goto clean; } @@ -268,29 +268,38 @@ static int pdsch_init(srslte_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { // Allocate int16_t for reception (LLRs) - q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM)); + q->e[i] = srslte_vec_i16_malloc(q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_256QAM)); if (!q->e[i]) { goto clean; } - q->d[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + q->d[i] = srslte_vec_cf_malloc(q->max_re); if (!q->d[i]) { goto clean; } + + // If it is the UE, allocate EVM buffer, for only minimum PRB + if (is_ue) { + q->evm_buffer[i] = srslte_evm_buffer_alloc(6); + if (!q->evm_buffer[i]) { + ERROR("Allocating EVM buffer\n"); + goto clean; + } + } } for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + q->x[i] = srslte_vec_cf_malloc(q->max_re); if (!q->x[i]) { goto clean; } - q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + q->symbols[i] = srslte_vec_cf_malloc(q->max_re); if (!q->symbols[i]) { goto clean; } if (q->is_ue) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { - q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + q->ce[i][j] = srslte_vec_cf_malloc(q->max_re); if (!q->ce[i][j]) { goto clean; } @@ -310,7 +319,7 @@ static int pdsch_init(srslte_pdsch_t* q, uint32_t max_prb, bool is_ue, uint32_t for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (!q->csi[i]) { - q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re * 2); + q->csi[i] = srslte_vec_f_malloc(q->max_re * 2); if (!q->csi[i]) { return SRSLTE_ERROR; } @@ -413,6 +422,10 @@ void srslte_pdsch_free(srslte_pdsch_t* q) if (q->csi[i]) { free(q->csi[i]); } + + if (q->evm_buffer[i]) { + srslte_evm_free(q->evm_buffer[i]); + } } /* Free sch objects */ @@ -448,7 +461,7 @@ void srslte_pdsch_free(srslte_pdsch_t* q) srslte_sequence_free(&q->tmp_seq); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < SRSLTE_NOF_MODULATIONS; i++) { srslte_modem_table_free(&q->mod[i]); } @@ -463,6 +476,13 @@ int srslte_pdsch_set_cell(srslte_pdsch_t* q, srslte_cell_t cell) q->cell = cell; q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); + // Resize EVM buffer, only for UE + if (q->is_ue) { + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + srslte_evm_buffer_resize(q->evm_buffer[i], cell.nof_prb); + } + } + INFO("PDSCH: Cell config PCI=%d, %d ports, %d PRBs, max_symbols: %d\n", q->cell.id, q->cell.nof_ports, @@ -740,7 +760,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q, srslte_dl_sf_cfg_t* sf, srslte_pdsch_cfg_t* cfg, srslte_sch_t* dl_sch, - uint8_t* data, + srslte_pdsch_res_t* data, uint32_t tb_idx, bool* ack) { @@ -772,6 +792,23 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q, } else { srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], cfg->grant.nof_re); } + if (cfg->meas_evm_en && q->evm_buffer[codeword_idx]) { + if (q->llr_is_8bit) { + data[tb_idx].evm = srslte_evm_run_b(q->evm_buffer[codeword_idx], + &q->mod[mcs->mod], + q->d[codeword_idx], + q->e[codeword_idx], + cfg->grant.tb[tb_idx].nof_bits); + } else { + data[tb_idx].evm = srslte_evm_run_s(q->evm_buffer[codeword_idx], + &q->mod[mcs->mod], + q->d[codeword_idx], + q->e[codeword_idx], + cfg->grant.tb[tb_idx].nof_bits); + } + } else { + data[tb_idx].evm = NAN; + } /* Select scrambling sequence */ srslte_sequence_t* seq = @@ -793,7 +830,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t* q, } /* Return */ - ret = srslte_dlsch_decode2(dl_sch, cfg, q->e[codeword_idx], data, tb_idx, nof_layers); + ret = srslte_dlsch_decode2(dl_sch, cfg, q->e[codeword_idx], data[tb_idx].payload, tb_idx, nof_layers); if (ret == SRSLTE_SUCCESS) { *ack = true; @@ -957,7 +994,7 @@ int srslte_pdsch_decode(srslte_pdsch_t* q, h->pdsch_ptr = q; h->cfg = cfg; h->sf = sf; - h->data = data[tb_idx].payload; + h->data = &data[tb_idx]; h->tb_idx = tb_idx; h->ack = &data[tb_idx].crc; h->dl_sch.max_iterations = q->dl_sch.max_iterations; @@ -965,7 +1002,7 @@ int srslte_pdsch_decode(srslte_pdsch_t* q, sem_post(&h->start); } else { - ret = srslte_pdsch_codeword_decode(q, sf, cfg, &q->dl_sch, data[tb_idx].payload, tb_idx, &data[tb_idx].crc); + ret = srslte_pdsch_codeword_decode(q, sf, cfg, &q->dl_sch, data, tb_idx, &data[tb_idx].crc); data[tb_idx].avg_iterations_block = srslte_sch_last_noi(&q->dl_sch); } @@ -1100,7 +1137,7 @@ int srslte_pdsch_encode(srslte_pdsch_t* q, return SRSLTE_ERROR_INVALID_INPUTS; } - if (cfg->grant.nof_re > q->max_re || cfg->grant.nof_re > q->max_re) { + if (cfg->grant.nof_re > q->max_re) { ERROR("Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", cfg->grant.nof_re, q->max_re, @@ -1255,6 +1292,21 @@ srslte_pdsch_rx_info(srslte_pdsch_cfg_t* cfg, srslte_pdsch_res_t res[SRSLTE_MAX_ uint32_t len = srslte_print_check(str, str_len, 0, "rnti=0x%x", cfg->rnti); len += srslte_pdsch_grant_rx_info(&cfg->grant, res, &str[len], str_len - len); + if (cfg->meas_evm_en) { + len = srslte_print_check(str, str_len, len, ", evm={", 0); + for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (cfg->grant.tb[i].enabled && !isnan(res[i].evm)) { + len = srslte_print_check(str, str_len, len, "%.2f", res[i].evm); + if (i < SRSLTE_MAX_CODEWORDS - 1) { + if (cfg->grant.tb[i + 1].enabled) { + len = srslte_print_check(str, str_len, len, "/", 0); + } + } + } + } + len = srslte_print_check(str, str_len, len, "}", 0); + } + if (cfg->meas_time_en) { len = srslte_print_check(str, str_len, len, ", t=%d us\n", cfg->meas_time_value); } diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 274bf46c1..efea00159 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -33,8 +33,6 @@ #include "tbs_tables.h" -#define min(a, b) (a < b ? a : b) - /* Convert Type2 scheduling L_crb and RB_start to RIV value */ uint32_t srslte_ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { @@ -201,7 +199,7 @@ int srslte_ra_mcs_from_tbs_idx(uint32_t tbs_idx, bool is_ul) /* Table 7.1.7.2.1-1: Transport block size table on 36.213 */ int srslte_ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { - if (tbs_idx < 34 && n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) { + if (tbs_idx < SRSLTE_RA_NOF_TBS_IDX && n_prb > 0 && n_prb <= SRSLTE_MAX_PRB) { return tbs_table[tbs_idx][n_prb - 1]; } else { return SRSLTE_ERROR; diff --git a/lib/src/phy/phch/tbs_tables.h b/lib/src/phy/phch/tbs_tables.h index a8a104157..e88277e85 100644 --- a/lib/src/phy/phch/tbs_tables.h +++ b/lib/src/phy/phch/tbs_tables.h @@ -32,7 +32,7 @@ static const int ul_mcs_tbs_idx_table[29] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26}; /* Transport Block Size from 3GPP TS 36.213 v12.13.0 table 7.1.7.2.1-1 */ -static const int tbs_table[34][110] = { +static const int tbs_table[SRSLTE_RA_NOF_TBS_IDX][110] = { /* The matrix below is automatically generated from ETSI TS 136 213 V12.13.0 (2019-03) */ {16, 32, 56, 88, 120, 152, 176, 208, 224, 256, 288, 328, 344, 376, 392, 424, 456, 488, 504, 536, 568, 600, 616, 648, 680, 712, 744, 776, 776, 808, 840, 872, 904, 936, 968, 1000, 1032, 1032, diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index e5b4bb2c8..d0cc852c9 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -200,7 +200,7 @@ void* srslte_vec_realloc(void* ptr, uint32_t old_size, uint32_t new_size) #endif } -void srslte_vec_fprint_c(FILE* stream, cf_t* x, const uint32_t len) +void srslte_vec_fprint_c(FILE* stream, const cf_t* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -210,7 +210,7 @@ void srslte_vec_fprint_c(FILE* stream, cf_t* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_f(FILE* stream, float* x, const uint32_t len) +void srslte_vec_fprint_f(FILE* stream, const float* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -220,7 +220,7 @@ void srslte_vec_fprint_f(FILE* stream, float* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_b(FILE* stream, uint8_t* x, const uint32_t len) +void srslte_vec_fprint_b(FILE* stream, const uint8_t* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -230,7 +230,7 @@ void srslte_vec_fprint_b(FILE* stream, uint8_t* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_bs(FILE* stream, int8_t* x, const uint32_t len) +void srslte_vec_fprint_bs(FILE* stream, const int8_t* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -240,7 +240,7 @@ void srslte_vec_fprint_bs(FILE* stream, int8_t* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_byte(FILE* stream, uint8_t* x, const uint32_t len) +void srslte_vec_fprint_byte(FILE* stream, const uint8_t* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -250,7 +250,7 @@ void srslte_vec_fprint_byte(FILE* stream, uint8_t* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_i(FILE* stream, int* x, const uint32_t len) +void srslte_vec_fprint_i(FILE* stream, const int* x, const uint32_t len) { int i; fprintf(stream, "["); @@ -260,7 +260,7 @@ void srslte_vec_fprint_i(FILE* stream, int* x, const uint32_t len) fprintf(stream, "];\n"); } -void srslte_vec_fprint_s(FILE* stream, short* x, const uint32_t len) +void srslte_vec_fprint_s(FILE* stream, const int16_t* x, const uint32_t len) { int i; fprintf(stream, "["); diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c index e220cc64a..69e7f5cb5 100644 --- a/lib/test/phy/phy_dl_test.c +++ b/lib/test/phy/phy_dl_test.c @@ -140,9 +140,6 @@ void parse_args(int argc, char** argv) } } -int prbset_num = 1, last_prbset_num = 1; -int prbset_orig = 0; - int work_enb(srslte_enb_dl_t* enb_dl, srslte_dl_sf_cfg_t* dl_sf, srslte_dci_cfg_t* dci_cfg, @@ -203,16 +200,16 @@ int work_ue(srslte_ue_dl_t* ue_dl, { if (srslte_ue_dl_decode_fft_estimate(ue_dl, sf_cfg_dl, ue_dl_cfg) < 0) { ERROR("Getting PDCCH FFT estimate sf_idx=%d\n", sf_idx); - return -1; + return SRSLTE_ERROR; } int nof_grants = srslte_ue_dl_find_dl_dci(ue_dl, sf_cfg_dl, ue_dl_cfg, rnti, dci_dl); if (nof_grants < 0) { ERROR("Looking for DL grants sf_idx=%d\n", sf_idx); - return -1; + return SRSLTE_ERROR; } else if (nof_grants == 0) { ERROR("Failed to find DCI in sf_idx=%d\n", sf_idx); - return -1; + return SRSLTE_ERROR; } // Enable power allocation @@ -221,15 +218,18 @@ int work_ue(srslte_ue_dl_t* ue_dl, ue_dl_cfg->cfg.pdsch.p_b = (transmission_mode > SRSLTE_TM1) ? 1 : 0; // 0 dB ue_dl_cfg->cfg.pdsch.rnti = dci_dl->rnti; ue_dl_cfg->cfg.pdsch.csi_enable = false; + ue_dl_cfg->cfg.pdsch.meas_evm_en = true; - char str[512]; - srslte_dci_dl_info(&dci_dl[0], str, 512); - INFO("UE PDCCH: rnti=0x%x, %s\n", rnti, str); + if (srslte_verbose >= SRSLTE_VERBOSE_INFO) { + char str[512]; + srslte_dci_dl_info(&dci_dl[0], str, 512); + INFO("UE PDCCH: rnti=0x%x, %s\n", rnti, str); + } if (srslte_ra_dl_dci_to_grant( &cell, sf_cfg_dl, transmission_mode, enable_256qam, &dci_dl[0], &ue_dl_cfg->cfg.pdsch.grant)) { ERROR("Computing DL grant sf_idx=%d\n", sf_idx); - return -1; + return SRSLTE_ERROR; } // Reset softbuffer @@ -241,34 +241,16 @@ int work_ue(srslte_ue_dl_t* ue_dl, if (srslte_ue_dl_decode_pdsch(ue_dl, sf_cfg_dl, &ue_dl_cfg->cfg.pdsch, pdsch_res)) { ERROR("ERROR: Decoding PDSCH sf_idx=%d\n", sf_idx); - return -1; + return SRSLTE_ERROR; } - srslte_pdsch_tx_info(&ue_dl_cfg->cfg.pdsch, str, 512); - INFO("UE PDSCH: rnti=0x%x, %s\n", rnti, str); - - return 0; -} - -unsigned int reverse(register unsigned int x) -{ - x = (((x & (uint32_t)0xaaaaaaaa) >> (uint32_t)1) | ((x & (uint32_t)0x55555555) << (uint32_t)1)); - x = (((x & (uint32_t)0xcccccccc) >> (uint32_t)2) | ((x & (uint32_t)0x33333333) << (uint32_t)2)); - x = (((x & (uint32_t)0xf0f0f0f0) >> (uint32_t)4) | ((x & (uint32_t)0x0f0f0f0f) << (uint32_t)4)); - x = (((x & (uint32_t)0xff00ff00) >> (uint32_t)8) | ((x & (uint32_t)0x00ff00ff) << (uint32_t)8)); - return ((x >> (uint32_t)16) | (x << (uint32_t)16)); -} - -uint32_t prbset_to_bitmask() -{ - uint32_t mask = 0; - uint32_t nb = (uint32_t)ceilf((float)cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); - for (uint32_t i = 0; i < nb; i++) { - if (i >= prbset_orig && i < prbset_orig + prbset_num) { - mask = mask | ((uint32_t)0x1 << i); - } + if (srslte_verbose >= SRSLTE_VERBOSE_INFO) { + char str[512]; + srslte_pdsch_rx_info(&ue_dl_cfg->cfg.pdsch, pdsch_res, str, 512); + INFO("eNb PDSCH: rnti=0x%x, %s\n", rnti, str); } - return reverse(mask) >> (uint32_t)(32 - nb); + + return SRSLTE_SUCCESS; } static int @@ -448,8 +430,8 @@ int main(int argc, char** argv) /* * DCI Configuration */ - srslte_dci_dl_t dci; - srslte_dci_cfg_t dci_cfg; + srslte_dci_dl_t dci = {}; + srslte_dci_cfg_t dci_cfg = {}; dci_cfg.srs_request_enabled = false; dci_cfg.ra_format_enabled = false; dci_cfg.multiple_csi_request_enabled = false; @@ -480,14 +462,19 @@ int main(int argc, char** argv) } // Set PRB Allocation type +#if 0 + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE2; + uint32_t n_prb = 1; ///< Number of PRB + uint32_t s_prb = 0; ///< Start + dci.type2_alloc.riv = srslte_ra_type2_to_riv(n_prb, s_prb, cell.nof_prb); +#else dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; - prbset_num = (int)ceilf((float)cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); - last_prbset_num = prbset_num; - dci.type0_alloc.rbg_bitmask = prbset_to_bitmask(); + dci.type0_alloc.rbg_bitmask = 0xffffffff; // All PRB +#endif // Set TB if (transmission_mode < SRSLTE_TM3) { - dci.format = SRSLTE_DCI_FORMAT1; + dci.format = (dci.alloc_type == SRSLTE_RA_ALLOC_TYPE2) ? SRSLTE_DCI_FORMAT1A : SRSLTE_DCI_FORMAT1; dci.tb[0].mcs_idx = mcs; dci.tb[0].rv = 0; dci.tb[0].ndi = 0; @@ -530,7 +517,7 @@ int main(int argc, char** argv) /* * Run eNodeB */ - srslte_dl_sf_cfg_t sf_cfg_dl; + srslte_dl_sf_cfg_t sf_cfg_dl = {}; sf_cfg_dl.tti = sf_idx % 10; sf_cfg_dl.cfi = cfi; sf_cfg_dl.sf_type = SRSLTE_SF_NORM;