mirror of https://github.com/PentHertz/srsLTE.git
Added NR PDCCH unit test plus fixes
This commit is contained in:
parent
53f6ac118e
commit
cd1aef7d76
|
@ -28,7 +28,7 @@ typedef enum SRSLTE_API {
|
||||||
typedef struct SRSLTE_API {
|
typedef struct SRSLTE_API {
|
||||||
srslte_dci_location_t location;
|
srslte_dci_location_t location;
|
||||||
srslte_search_space_type_t search_space;
|
srslte_search_space_type_t search_space;
|
||||||
uint8_t payload[32];
|
uint8_t payload[50];
|
||||||
srslte_rnti_type_t rnti_type;
|
srslte_rnti_type_t rnti_type;
|
||||||
uint32_t nof_bits;
|
uint32_t nof_bits;
|
||||||
srslte_dci_format_nr_t format;
|
srslte_dci_format_nr_t format;
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool disable_simd;
|
bool disable_simd;
|
||||||
bool measure_evm;
|
bool measure_evm;
|
||||||
|
bool measure_time;
|
||||||
} srslte_pdcch_nr_args_t;
|
} srslte_pdcch_nr_args_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,12 +52,18 @@ typedef struct SRSLTE_API {
|
||||||
srslte_carrier_nr_t carrier;
|
srslte_carrier_nr_t carrier;
|
||||||
srslte_coreset_t coreset;
|
srslte_coreset_t coreset;
|
||||||
srslte_crc_t crc24c;
|
srslte_crc_t crc24c;
|
||||||
uint8_t* c; // Message bits with attached CRC
|
uint8_t* c; // Message bits with attached CRC
|
||||||
uint8_t* d; // encoded bits
|
uint8_t* d; // encoded bits
|
||||||
uint8_t* f; // bits at the Rate matching output
|
uint8_t* f; // bits at the Rate matching output
|
||||||
|
uint8_t* allocated; // Allocated polar bit buffer, encoder input, decoder output
|
||||||
cf_t* symbols;
|
cf_t* symbols;
|
||||||
srslte_modem_table_t modem_table;
|
srslte_modem_table_t modem_table;
|
||||||
srslte_evm_buffer_t* evm_buffer;
|
srslte_evm_buffer_t* evm_buffer;
|
||||||
|
bool meas_time_en;
|
||||||
|
uint32_t meas_time_us;
|
||||||
|
uint32_t K;
|
||||||
|
uint32_t M;
|
||||||
|
uint32_t E;
|
||||||
} srslte_pdcch_nr_t;
|
} srslte_pdcch_nr_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,7 +99,7 @@ SRSLTE_API int srslte_pdcch_nr_init_tx(srslte_pdcch_nr_t* q, const srslte_pdcch_
|
||||||
|
|
||||||
SRSLTE_API int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args);
|
SRSLTE_API int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t* args);
|
||||||
|
|
||||||
SRSLTE_API void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q);
|
SRSLTE_API void srslte_pdcch_nr_free(srslte_pdcch_nr_t* q);
|
||||||
|
|
||||||
SRSLTE_API int
|
SRSLTE_API int
|
||||||
srslte_pdcch_nr_set_carrier(srslte_pdcch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset);
|
srslte_pdcch_nr_set_carrier(srslte_pdcch_nr_t* q, const srslte_carrier_nr_t* carrier, const srslte_coreset_t* coreset);
|
||||||
|
@ -116,4 +123,18 @@ SRSLTE_API int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
|
||||||
srslte_dci_msg_nr_t* dci_msg,
|
srslte_dci_msg_nr_t* dci_msg,
|
||||||
srslte_pdcch_nr_res_t* res);
|
srslte_pdcch_nr_res_t* res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stringifies NR PDCCH decoding information from the latest encoded/decoded transmission
|
||||||
|
*
|
||||||
|
* @param[in] q provides PDCCH encoder/decoder object
|
||||||
|
* @param[in] res Optional PDCCH decode result
|
||||||
|
* @param[out] str Destination string
|
||||||
|
* @param[out] str_len Maximum destination string length
|
||||||
|
* @return The number of characters written in the string
|
||||||
|
*/
|
||||||
|
SRSLTE_API uint32_t srslte_pdcch_nr_info(const srslte_pdcch_nr_t* q,
|
||||||
|
const srslte_pdcch_nr_res_t* res,
|
||||||
|
char* str,
|
||||||
|
uint32_t str_len);
|
||||||
|
|
||||||
#endif // SRSLTE_PDCCH_NR_H
|
#endif // SRSLTE_PDCCH_NR_H
|
||||||
|
|
|
@ -11,9 +11,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "srslte/phy/phch/pdcch_nr.h"
|
#include "srslte/phy/phch/pdcch_nr.h"
|
||||||
|
#include "srslte/phy/fec/polar/polar_chanalloc.h"
|
||||||
#include "srslte/phy/utils/debug.h"
|
#include "srslte/phy/utils/debug.h"
|
||||||
#include "srslte/phy/utils/vector.h"
|
#include "srslte/phy/utils/vector.h"
|
||||||
|
|
||||||
|
#define PDCCH_NR_POLAR_RM_IBIL 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Recursive Y_p_n function
|
* @brief Recursive Y_p_n function
|
||||||
*/
|
*/
|
||||||
|
@ -107,6 +110,8 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args
|
||||||
return SRSLTE_ERROR_INVALID_INPUTS;
|
return SRSLTE_ERROR_INVALID_INPUTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q->meas_time_en = args->measure_time;
|
||||||
|
|
||||||
q->c = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2);
|
q->c = srslte_vec_u8_malloc(SRSLTE_PDCCH_MAX_RE * 2);
|
||||||
if (q->c == NULL) {
|
if (q->c == NULL) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
|
@ -127,6 +132,11 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q->allocated = srslte_vec_u8_malloc(NMAX);
|
||||||
|
if (q->allocated == NULL) {
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (srslte_crc_init(&q->crc24c, SRSLTE_LTE_CRC24C, 24) < SRSLTE_SUCCESS) {
|
if (srslte_crc_init(&q->crc24c, SRSLTE_LTE_CRC24C, 24) < SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -136,6 +146,9 @@ static int pdcch_nr_init_common(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args
|
||||||
}
|
}
|
||||||
|
|
||||||
srslte_modem_table_lte(&q->modem_table, SRSLTE_MOD_QPSK);
|
srslte_modem_table_lte(&q->modem_table, SRSLTE_MOD_QPSK);
|
||||||
|
if (args->measure_evm) {
|
||||||
|
srslte_modem_table_bytes(&q->modem_table);
|
||||||
|
}
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +198,7 @@ int srslte_pdcch_nr_init_rx(srslte_pdcch_nr_t* q, const srslte_pdcch_nr_args_t*
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q)
|
void srslte_pdcch_nr_free(srslte_pdcch_nr_t* q)
|
||||||
{
|
{
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
return;
|
return;
|
||||||
|
@ -213,8 +226,20 @@ void srslte_pdcch_nr_init_free(srslte_pdcch_nr_t* q)
|
||||||
free(q->f);
|
free(q->f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (q->allocated) {
|
||||||
|
free(q->allocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q->symbols) {
|
||||||
|
free(q->symbols);
|
||||||
|
}
|
||||||
|
|
||||||
srslte_modem_table_free(&q->modem_table);
|
srslte_modem_table_free(&q->modem_table);
|
||||||
|
|
||||||
|
if (q->evm_buffer) {
|
||||||
|
srslte_evm_free(q->evm_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
SRSLTE_MEM_ZERO(q, srslte_pdcch_nr_t, 1);
|
SRSLTE_MEM_ZERO(q, srslte_pdcch_nr_t, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,15 +316,21 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timeval t[3];
|
||||||
|
if (q->meas_time_en) {
|
||||||
|
gettimeofday(&t[1], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate...
|
// Calculate...
|
||||||
uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
q->K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
||||||
uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
q->M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
||||||
uint32_t E = M * 2; // Number of Rate-Matched bits
|
q->E = q->M * 2; // Number of Rate-Matched bits
|
||||||
|
|
||||||
// Get polar code
|
// Get polar code
|
||||||
if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) {
|
if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
INFO("PDCCH NR TX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n);
|
||||||
|
|
||||||
// Copy DCI message
|
// Copy DCI message
|
||||||
srslte_vec_u8_copy(q->c, dci_msg->payload, dci_msg->nof_bits);
|
srslte_vec_u8_copy(q->c, dci_msg->payload, dci_msg->nof_bits);
|
||||||
|
@ -307,35 +338,64 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
|
||||||
// Append CRC
|
// Append CRC
|
||||||
srslte_crc_attach(&q->crc24c, q->c, dci_msg->nof_bits);
|
srslte_crc_attach(&q->crc24c, q->c, dci_msg->nof_bits);
|
||||||
|
|
||||||
|
INFO("PDCCH NR TX: Append CRC %06x\n", (uint32_t)srslte_crc_checksum_get(&q->crc24c));
|
||||||
|
|
||||||
// Unpack RNTI
|
// Unpack RNTI
|
||||||
uint8_t unpacked_rnti[16] = {};
|
uint8_t unpacked_rnti[16] = {};
|
||||||
uint8_t* ptr = unpacked_rnti;
|
uint8_t* ptr = unpacked_rnti;
|
||||||
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
||||||
|
|
||||||
// Scramble CRC with RNTI
|
// Scramble CRC with RNTI
|
||||||
srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16);
|
srslte_vec_xor_bbb(unpacked_rnti, &q->c[q->K - 16], &q->c[q->K - 16], 16);
|
||||||
|
|
||||||
|
// Print c
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
INFO("PDCCH NR TX: c=");
|
||||||
|
srslte_vec_fprint_hex(stdout, q->c, q->K);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate channel
|
||||||
|
srslte_polar_chanalloc_tx(q->c, q->allocated, q->code.N, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set);
|
||||||
|
|
||||||
// Encode bits
|
// Encode bits
|
||||||
if (srslte_polar_encoder_encode(&q->encoder, q->c, q->d, q->code.n) < SRSLTE_SUCCESS) {
|
if (srslte_polar_encoder_encode(&q->encoder, q->allocated, q->d, q->code.n) < SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print d
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
INFO("PDCCH NR TX: d=");
|
||||||
|
srslte_vec_fprint_byte(stdout, q->d, q->K);
|
||||||
|
}
|
||||||
|
|
||||||
// Rate matching
|
// Rate matching
|
||||||
srslte_polar_rm_tx(&q->rm, q->d, q->f, q->code.n, E, K, 0);
|
srslte_polar_rm_tx(&q->rm, q->d, q->f, q->code.n, q->E, q->K, PDCCH_NR_POLAR_RM_IBIL);
|
||||||
|
|
||||||
// Scrambling
|
// Scrambling
|
||||||
srslte_sequence_apply_bit(q->f, q->f, E, pdcch_nr_c_init(q, dci_msg));
|
srslte_sequence_apply_bit(q->f, q->f, q->E, pdcch_nr_c_init(q, dci_msg));
|
||||||
|
|
||||||
// Modulation
|
// Modulation
|
||||||
srslte_mod_modulate(&q->modem_table, q->f, q->symbols, E);
|
srslte_mod_modulate(&q->modem_table, q->f, q->symbols, q->E);
|
||||||
|
|
||||||
// Put symbols in grid
|
// Put symbols in grid
|
||||||
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true);
|
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, true);
|
||||||
if (M != m) {
|
if (q->M != m) {
|
||||||
ERROR("Unmatch number of RE (%d != %d)\n", m, M);
|
ERROR("Unmatch number of RE (%d != %d)\n", m, q->M);
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (q->meas_time_en) {
|
||||||
|
gettimeofday(&t[2], NULL);
|
||||||
|
get_time_interval(t);
|
||||||
|
q->meas_time_us = (uint32_t)t[0].tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
char str[128] = {};
|
||||||
|
srslte_pdcch_nr_info(q, NULL, str, sizeof(str));
|
||||||
|
INFO("PDCCH NR TX: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,73 +409,139 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timeval t[3];
|
||||||
|
if (q->meas_time_en) {
|
||||||
|
gettimeofday(&t[1], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate...
|
// Calculate...
|
||||||
uint32_t K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
q->K = dci_msg->nof_bits + 24U; // Payload size including CRC
|
||||||
uint32_t M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
q->M = (1U << dci_msg->location.L) * (SRSLTE_NRE - 3U) * 6U; // Number of RE
|
||||||
uint32_t E = M * 2; // Number of Rate-Matched bits
|
q->E = q->M * 2; // Number of Rate-Matched bits
|
||||||
|
|
||||||
// Check number of estimates is correct
|
// Check number of estimates is correct
|
||||||
if (ce->nof_re != M) {
|
if (ce->nof_re != q->M) {
|
||||||
ERROR("Invalid number of channel estimates (%d != %d)\n", M, ce->nof_re);
|
ERROR("Invalid number of channel estimates (%d != %d)\n", q->M, ce->nof_re);
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get polar code
|
// Get polar code
|
||||||
if (srslte_polar_code_get(&q->code, K, E, 9U) < SRSLTE_SUCCESS) {
|
if (srslte_polar_code_get(&q->code, q->K, q->E, 9U) < SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
INFO("PDCCH NR RX: K=%d; E=%d; M=%d; n=%d;\n", q->K, q->E, q->M, q->code.n);
|
||||||
|
|
||||||
// Get symbols from grid
|
// Get symbols from grid
|
||||||
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false);
|
uint32_t m = pdcch_nr_cp(q, &dci_msg->location, slot_symbols, q->symbols, false);
|
||||||
if (M != m) {
|
if (q->M != m) {
|
||||||
ERROR("Unmatch number of RE (%d != %d)\n", m, M);
|
ERROR("Unmatch number of RE (%d != %d)\n", m, q->M);
|
||||||
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equalise
|
// Equalise
|
||||||
srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, M, 1.0f, ce->noise_var);
|
srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, q->M, 1.0f, ce->noise_var);
|
||||||
|
|
||||||
// Demodulation
|
// Demodulation
|
||||||
int8_t* llr = (int8_t*)q->f;
|
int8_t* llr = (int8_t*)q->f;
|
||||||
srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, M);
|
srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, q->M);
|
||||||
|
|
||||||
// Measure EVM if configured
|
// Measure EVM if configured
|
||||||
if (q->evm_buffer != NULL) {
|
if (q->evm_buffer != NULL) {
|
||||||
res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_table, q->symbols, llr, E);
|
res->evm = srslte_evm_run_b(q->evm_buffer, &q->modem_table, q->symbols, llr, q->E);
|
||||||
} else {
|
} else {
|
||||||
res->evm = NAN;
|
res->evm = NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Negate all LLR
|
||||||
|
for (uint32_t i = 0; i < q->E; i++) {
|
||||||
|
llr[i] *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Descrambling
|
// Descrambling
|
||||||
srslte_sequence_apply_c(llr, llr, E, pdcch_nr_c_init(q, dci_msg));
|
srslte_sequence_apply_c(llr, llr, q->E, pdcch_nr_c_init(q, dci_msg));
|
||||||
|
|
||||||
// Un-rate matching
|
// Un-rate matching
|
||||||
int8_t* d = (int8_t*)q->d;
|
int8_t* d = (int8_t*)q->d;
|
||||||
if (srslte_polar_rm_rx_c(&q->rm, llr, d, E, q->code.n, K, 0) < SRSLTE_SUCCESS) {
|
if (srslte_polar_rm_rx_c(&q->rm, llr, d, q->E, q->code.n, q->K, PDCCH_NR_POLAR_RM_IBIL) < SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Print d
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
INFO("PDCCH NR RX: d=");
|
||||||
|
srslte_vec_fprint_bs(stdout, d, q->K);
|
||||||
|
}
|
||||||
|
|
||||||
// Decode
|
// Decode
|
||||||
if (srslte_polar_decoder_decode_c(&q->decoder, d, q->c, q->code.n, q->code.F_set, q->code.F_set_size) <
|
if (srslte_polar_decoder_decode_c(&q->decoder, d, q->allocated, q->code.n, q->code.F_set, q->code.F_set_size) <
|
||||||
SRSLTE_SUCCESS) {
|
SRSLTE_SUCCESS) {
|
||||||
return SRSLTE_ERROR;
|
return SRSLTE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// De-allocate channel
|
||||||
|
srslte_polar_chanalloc_rx(q->allocated, q->c, q->code.K, q->code.nPC, q->code.K_set, q->code.PC_set);
|
||||||
|
|
||||||
|
// Print c
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
INFO("PDCCH NR RX: c=");
|
||||||
|
srslte_vec_fprint_hex(stdout, q->c, q->K);
|
||||||
|
}
|
||||||
|
|
||||||
// Unpack RNTI
|
// Unpack RNTI
|
||||||
uint8_t unpacked_rnti[16] = {};
|
uint8_t unpacked_rnti[16] = {};
|
||||||
uint8_t* ptr = unpacked_rnti;
|
uint8_t* ptr = unpacked_rnti;
|
||||||
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
srslte_bit_unpack(dci_msg->rnti, &ptr, 16);
|
||||||
|
|
||||||
// De-Scramble CRC with RNTI
|
// De-Scramble CRC with RNTI
|
||||||
ptr = &q->c[K - 24];
|
ptr = &q->c[q->K - 24];
|
||||||
srslte_vec_xor_bbb(unpacked_rnti, &q->c[K - 16], &q->c[K - 16], 16);
|
srslte_vec_xor_bbb(unpacked_rnti, &q->c[q->K - 16], &q->c[q->K - 16], 16);
|
||||||
|
|
||||||
// Check CRC
|
// Check CRC
|
||||||
uint32_t checksum1 = srslte_crc_checksum(&q->crc24c, q->c, dci_msg->nof_bits);
|
uint32_t checksum1 = srslte_crc_checksum(&q->crc24c, q->c, dci_msg->nof_bits);
|
||||||
uint32_t checksum2 = srslte_bit_pack(&ptr, 24);
|
uint32_t checksum2 = srslte_bit_pack(&ptr, 24);
|
||||||
res->crc = checksum1 == checksum2;
|
res->crc = checksum1 == checksum2;
|
||||||
|
|
||||||
|
INFO("PDCCH NR RX: CRC={%06x, %06x}\n", checksum1, checksum2);
|
||||||
|
|
||||||
// Copy DCI message
|
// Copy DCI message
|
||||||
srslte_vec_u8_copy(dci_msg->payload, q->c, dci_msg->nof_bits);
|
srslte_vec_u8_copy(dci_msg->payload, q->c, dci_msg->nof_bits);
|
||||||
|
|
||||||
|
if (q->meas_time_en) {
|
||||||
|
gettimeofday(&t[2], NULL);
|
||||||
|
get_time_interval(t);
|
||||||
|
q->meas_time_us = (uint32_t)t[0].tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
|
||||||
|
char str[128] = {};
|
||||||
|
srslte_pdcch_nr_info(q, res, str, sizeof(str));
|
||||||
|
INFO("PDCCH NR RX: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t srslte_pdcch_nr_info(const srslte_pdcch_nr_t* q, const srslte_pdcch_nr_res_t* res, char* str, uint32_t str_len)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (q == NULL) {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = srslte_print_check(str, str_len, len, "K=%d,E=%d", q->K, q->E);
|
||||||
|
|
||||||
|
if (res != NULL) {
|
||||||
|
len = srslte_print_check(str, str_len, len, ",crc=%s", res->crc ? "OK" : "KO");
|
||||||
|
|
||||||
|
if (q->evm_buffer && res) {
|
||||||
|
len = srslte_print_check(str, str_len, len, ",evm=%.2f", res->evm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q->meas_time_en) {
|
||||||
|
len = srslte_print_check(str, str_len, len, ",t=%d us", q->meas_time_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
|
@ -621,3 +621,8 @@ add_test(dlsch_nr_test dlsch_nr_test -m 0 -p 1)
|
||||||
add_executable(pdsch_nr_test pdsch_nr_test.c)
|
add_executable(pdsch_nr_test pdsch_nr_test.c)
|
||||||
target_link_libraries(pdsch_nr_test srslte_phy)
|
target_link_libraries(pdsch_nr_test srslte_phy)
|
||||||
add_test(pdsch_nr_test pdsch_nr_test -p 6 -m 20)
|
add_test(pdsch_nr_test pdsch_nr_test -p 6 -m 20)
|
||||||
|
|
||||||
|
|
||||||
|
add_executable(pdcch_nr_test pdcch_nr_test.c)
|
||||||
|
target_link_libraries(pdcch_nr_test srslte_phy)
|
||||||
|
add_test(pdcch_nr_test pdcch_nr_test)
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013-2020 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/.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "srslte/common/test_common.h"
|
||||||
|
#include "srslte/phy/phch/pdcch_nr.h"
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
static srslte_carrier_nr_t carrier = {
|
||||||
|
0, // cell_id
|
||||||
|
0, // numerology
|
||||||
|
SRSLTE_MAX_PRB_NR, // nof_prb
|
||||||
|
0 // start
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t rnti = 0x1234;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t time_us;
|
||||||
|
uint64_t count;
|
||||||
|
} proc_time_t;
|
||||||
|
|
||||||
|
static proc_time_t enc_time[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR] = {};
|
||||||
|
static proc_time_t dec_time[SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR] = {};
|
||||||
|
|
||||||
|
static int test(srslte_pdcch_nr_t* tx,
|
||||||
|
srslte_pdcch_nr_t* rx,
|
||||||
|
cf_t* grid,
|
||||||
|
srslte_dmrs_pdcch_ce_t* ce,
|
||||||
|
srslte_dci_msg_nr_t* dci_msg_tx)
|
||||||
|
{
|
||||||
|
// Encode PDCCH
|
||||||
|
TESTASSERT(srslte_pdcch_nr_encode(tx, dci_msg_tx, grid) == SRSLTE_SUCCESS);
|
||||||
|
|
||||||
|
enc_time[dci_msg_tx->location.L].time_us += tx->meas_time_us;
|
||||||
|
enc_time[dci_msg_tx->location.L].count++;
|
||||||
|
|
||||||
|
// Init Rx MSG
|
||||||
|
srslte_pdcch_nr_res_t res = {};
|
||||||
|
srslte_dci_msg_nr_t dci_msg_rx = *dci_msg_tx;
|
||||||
|
srslte_vec_u8_zero(dci_msg_rx.payload, dci_msg_rx.nof_bits);
|
||||||
|
|
||||||
|
// Decode PDCCH
|
||||||
|
TESTASSERT(srslte_pdcch_nr_decode(rx, grid, ce, &dci_msg_rx, &res) == SRSLTE_SUCCESS);
|
||||||
|
|
||||||
|
dec_time[dci_msg_tx->location.L].time_us += rx->meas_time_us;
|
||||||
|
dec_time[dci_msg_tx->location.L].count++;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
TESTASSERT(res.evm < 0.01f);
|
||||||
|
TESTASSERT(res.crc);
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(char* prog)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [v] \n", prog);
|
||||||
|
printf("\t-p Number of carrier PRB [Default %d]\n", carrier.nof_prb);
|
||||||
|
// printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs);
|
||||||
|
// printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
|
||||||
|
// srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
|
||||||
|
// printf("\t-L Provide number of layers [Default %d]\n", pdsch_cfg.sch_cfg.max_mimo_layers);
|
||||||
|
printf("\t-v [set srslte_verbose to debug, default none]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_args(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "vp")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'p':
|
||||||
|
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
srslte_verbose++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int ret = SRSLTE_ERROR;
|
||||||
|
|
||||||
|
srslte_pdcch_nr_args_t args = {};
|
||||||
|
args.disable_simd = false;
|
||||||
|
args.measure_evm = true;
|
||||||
|
args.measure_time = true;
|
||||||
|
|
||||||
|
srslte_pdcch_nr_t pdcch_tx = {};
|
||||||
|
srslte_pdcch_nr_t pdcch_rx = {};
|
||||||
|
|
||||||
|
if (parse_args(argc, argv) < SRSLTE_SUCCESS) {
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t grid_sz = carrier.nof_prb * SRSLTE_NRE * SRSLTE_NSYMB_PER_SLOT_NR;
|
||||||
|
srslte_random_t rand_gen = srslte_random_init(1234);
|
||||||
|
srslte_dmrs_pdcch_ce_t* ce = SRSLTE_MEM_ALLOC(srslte_dmrs_pdcch_ce_t, 1);
|
||||||
|
cf_t* buffer = srslte_vec_cf_malloc(grid_sz);
|
||||||
|
if (rand_gen == NULL || ce == NULL || buffer == NULL) {
|
||||||
|
ERROR("Error malloc\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRSLTE_MEM_ZERO(ce, srslte_dmrs_pdcch_ce_t, 1);
|
||||||
|
|
||||||
|
if (srslte_pdcch_nr_init_tx(&pdcch_tx, &args) < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("Error init\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srslte_pdcch_nr_init_rx(&pdcch_rx, &args) < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("Error init\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
srslte_coreset_t coreset = {};
|
||||||
|
uint32_t nof_frequency_resource = SRSLTE_MIN(SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE, carrier.nof_prb / 6);
|
||||||
|
for (uint32_t frequency_resources = 1; frequency_resources < (1U << nof_frequency_resource); frequency_resources++) {
|
||||||
|
for (uint32_t i = 0; i < nof_frequency_resource; i++) {
|
||||||
|
uint32_t mask = ((frequency_resources >> i) & 1U);
|
||||||
|
coreset.freq_resources[i] = (mask == 1);
|
||||||
|
}
|
||||||
|
for (coreset.duration = SRSLTE_CORESET_DURATION_MIN; coreset.duration <= SRSLTE_CORESET_DURATION_MAX;
|
||||||
|
coreset.duration++) {
|
||||||
|
|
||||||
|
srslte_search_space_t search_space = {};
|
||||||
|
search_space.type = srslte_search_space_type_ue;
|
||||||
|
|
||||||
|
if (srslte_pdcch_nr_set_carrier(&pdcch_tx, &carrier, &coreset) < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("Error setting carrier\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srslte_pdcch_nr_set_carrier(&pdcch_rx, &carrier, &coreset) < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("Error setting carrier\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t coreset_bw = srslte_coreset_get_bw(&coreset);
|
||||||
|
uint32_t nof_cce = (coreset_bw * coreset.duration) / 6;
|
||||||
|
uint32_t max_aggregation_level = (uint32_t)floor(log2(nof_cce));
|
||||||
|
max_aggregation_level = SRSLTE_MIN(max_aggregation_level + 1, SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR);
|
||||||
|
|
||||||
|
// Fill search space maximum number of candidates
|
||||||
|
for (uint32_t aggregation_level = 0; aggregation_level < max_aggregation_level; aggregation_level++) {
|
||||||
|
uint32_t L = 1U << aggregation_level;
|
||||||
|
uint32_t nof_candidates = nof_cce / L;
|
||||||
|
nof_candidates = SRSLTE_MIN(nof_candidates, SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR);
|
||||||
|
search_space.nof_candidates[aggregation_level] = nof_candidates;
|
||||||
|
}
|
||||||
|
for (uint32_t aggregation_level = max_aggregation_level;
|
||||||
|
aggregation_level < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR;
|
||||||
|
aggregation_level++) {
|
||||||
|
search_space.nof_candidates[aggregation_level] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t aggregation_level = 0; aggregation_level < max_aggregation_level; aggregation_level++) {
|
||||||
|
uint32_t L = 1U << aggregation_level;
|
||||||
|
|
||||||
|
for (uint32_t slot_idx = 0; slot_idx < SRSLTE_NSLOTS_PER_FRAME_NR(carrier.numerology); slot_idx++) {
|
||||||
|
uint32_t dci_locations[SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR] = {};
|
||||||
|
|
||||||
|
// Calculate candidate locations
|
||||||
|
int n = srslte_pdcch_nr_locations_coreset(
|
||||||
|
&coreset, &search_space, rnti, aggregation_level, slot_idx, dci_locations);
|
||||||
|
if (n < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("Error calculating locations in CORESET\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
ERROR("Invalid number of locations (%d)\n", n);
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t ncce_idx = 0; ncce_idx < n; ncce_idx++) {
|
||||||
|
|
||||||
|
// Init MSG
|
||||||
|
srslte_dci_msg_nr_t dci_msg = {};
|
||||||
|
dci_msg.rnti_type = srslte_rnti_type_c;
|
||||||
|
dci_msg.location.L = aggregation_level;
|
||||||
|
dci_msg.location.ncce = dci_locations[n];
|
||||||
|
dci_msg.nof_bits = srslte_dci_nr_format_1_0_sizeof(&carrier, &coreset, dci_msg.rnti_type);
|
||||||
|
|
||||||
|
// Generate random payload
|
||||||
|
for (uint32_t i = 0; i < dci_msg.nof_bits; i++) {
|
||||||
|
dci_msg.payload[i] = srslte_random_uniform_int_dist(rand_gen, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set channel estimate number of elements and set out-of-range values to zero
|
||||||
|
ce->nof_re = (SRSLTE_NRE - 3) * 6 * L;
|
||||||
|
for (uint32_t i = 0; i < SRSLTE_PDCCH_MAX_RE; i++) {
|
||||||
|
ce->ce[i] = (i < ce->nof_re) ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
|
ce->noise_var = 0.0f;
|
||||||
|
|
||||||
|
if (test(&pdcch_tx, &pdcch_rx, buffer, ce, &dci_msg) < SRSLTE_SUCCESS) {
|
||||||
|
ERROR("test failed\n");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%6s %6s %6s\n", " ", " Time ", " Time ");
|
||||||
|
printf("%6s %6s %6s\n", "L", "Encode", "Decode");
|
||||||
|
printf("%6s %6s %6s\n", " ", " (us) ", " (us) ");
|
||||||
|
for (uint32_t i = 0; i < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; i++) {
|
||||||
|
if (enc_time[i].count > 0 && dec_time[i].count) {
|
||||||
|
printf("%6d %6.1f %6.1f\n",
|
||||||
|
i,
|
||||||
|
(double)enc_time[i].time_us / (double)enc_time[i].count,
|
||||||
|
(double)dec_time[i].time_us / (double)dec_time[i].count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SRSLTE_SUCCESS;
|
||||||
|
clean_exit:
|
||||||
|
srslte_random_free(rand_gen);
|
||||||
|
|
||||||
|
if (ce) {
|
||||||
|
free(ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
srslte_pdcch_nr_free(&pdcch_tx);
|
||||||
|
srslte_pdcch_nr_free(&pdcch_rx);
|
||||||
|
|
||||||
|
if (ret == SRSLTE_SUCCESS) {
|
||||||
|
printf("Passed!\n");
|
||||||
|
} else {
|
||||||
|
printf("Failed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in New Issue