Improved NR blind search and DL test

master
Xavier Arteaga 4 years ago committed by Andre Puschmann
parent 90aa4fbea7
commit e07cf513d0

@ -71,6 +71,10 @@ typedef struct SRSLTE_API {
/// Channel estimates, size coreset_sz /// Channel estimates, size coreset_sz
cf_t* ce; cf_t* ce;
/// Frequency domain smoothing filter
float* filter;
uint32_t filter_len;
} srslte_dmrs_pdcch_estimator_t; } srslte_dmrs_pdcch_estimator_t;
/** /**
@ -121,9 +125,14 @@ SRSLTE_API int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q,
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
/// Linear reference signal received power (RSRP). Measure correlation /// Linear reference signal received power (RSRP). Measure correlation
float rsrp; float rsrp;
float rsrp_dBfs;
/// Energy per resource element (EPRE) /// Energy per resource element (EPRE)
float epre; float epre;
float epre_dBfs;
/// Normalized Correlation (RSRP / EPRE)
float norm_corr;
/// CFO Measure in Hz (only available for CORESET durations 2 and 3) /// CFO Measure in Hz (only available for CORESET durations 2 and 3)
float cfo_hz; float cfo_hz;

@ -54,6 +54,11 @@ extern "C" {
*/ */
#define SRSLTE_NSLOTS_PER_FRAME_NR(NUM) (SRSLTE_NSLOTS_PER_SF_NR(NUM) * SRSLTE_NOF_SF_X_FRAME) #define SRSLTE_NSLOTS_PER_FRAME_NR(NUM) (SRSLTE_NSLOTS_PER_SF_NR(NUM) * SRSLTE_NOF_SF_X_FRAME)
/**
* @brief Bounds slot index into the frame
*/
#define SRSLTE_SLOT_NR_MOD(NUM, N) ((N) % SRSLTE_NSLOTS_PER_FRAME_NR(NUM))
/** /**
* @brief Maximum Carrier identification value. Defined by TS 38.331 v15.10.0 as PhysCellId from 0 to 1007. * @brief Maximum Carrier identification value. Defined by TS 38.331 v15.10.0 as PhysCellId from 0 to 1007.
*/ */

@ -53,6 +53,8 @@ SRSLTE_API int srslte_enb_dl_nr_set_coreset(srslte_enb_dl_nr_t* q, const srslte_
SRSLTE_API void srslte_enb_dl_nr_free(srslte_enb_dl_nr_t* q); SRSLTE_API void srslte_enb_dl_nr_free(srslte_enb_dl_nr_t* q);
SRSLTE_API int srslte_enb_dl_nr_base_zero(srslte_enb_dl_nr_t* q);
SRSLTE_API void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q); SRSLTE_API void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q);
SRSLTE_API int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q, SRSLTE_API int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q,

@ -36,6 +36,7 @@ typedef struct SRSLTE_API {
uint32_t max_prb; uint32_t max_prb;
uint32_t nof_rx_antennas; uint32_t nof_rx_antennas;
float pdcch_dmrs_corr_thr; float pdcch_dmrs_corr_thr;
float pdcch_dmrs_epre_thr;
srslte_carrier_nr_t carrier; srslte_carrier_nr_t carrier;
srslte_coreset_t coreset; srslte_coreset_t coreset;

@ -16,6 +16,12 @@
/// per frequency resource. /// per frequency resource.
#define NOF_PILOTS_X_FREQ_RES 18 #define NOF_PILOTS_X_FREQ_RES 18
#define DMRS_PDCCH_INFO_TX(...) INFO("PDCCH DMRS Tx: " __VA_ARGS__)
#define DMRS_PDCCH_INFO_RX(...) INFO("PDCCH DMRS Rx: " __VA_ARGS__)
/// @brief Enables interpolation at CCE frequency bandwidth to avoid interference with adjacent PDCCH DMRS
#define DMRS_PDCCH_INTERPOLATE_GROUP 1
static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uint32_t n_id) static uint32_t dmrs_pdcch_get_cinit(uint32_t slot_idx, uint32_t symbol_idx, uint32_t n_id)
{ {
return (uint32_t)((((SRSLTE_NSYMB_PER_SLOT_NR * slot_idx + symbol_idx + 1UL) << 17UL) * (2 * n_id + 1) + 2 * n_id) & return (uint32_t)((((SRSLTE_NSYMB_PER_SLOT_NR * slot_idx + symbol_idx + 1UL) << 17UL) * (2 * n_id + 1) + 2 * n_id) &
@ -130,9 +136,14 @@ int srslte_dmrs_pdcch_put(const srslte_carrier_nr_t* carrier,
n_id = coreset->dmrs_scrambling_id; n_id = coreset->dmrs_scrambling_id;
} }
// Bound slot index
uint32_t slot_idx = SRSLTE_SLOT_NR_MOD(carrier->numerology, slot_cfg->idx);
for (uint32_t l = 0; l < coreset->duration; l++) { for (uint32_t l = 0; l < coreset->duration; l++) {
// Get Cin // Get Cin
uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id); uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id);
DMRS_PDCCH_INFO_TX("n=%d; l=%d; cinit=%08x\n", slot_idx, l, cinit);
// Put data // Put data
dmrs_pdcch_put_symbol_noninterleaved( dmrs_pdcch_put_symbol_noninterleaved(
@ -178,7 +189,11 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q,
uint32_t coreset_bw = srslte_coreset_get_bw(coreset); uint32_t coreset_bw = srslte_coreset_get_bw(coreset);
uint32_t coreset_sz = srslte_coreset_get_sz(coreset); uint32_t coreset_sz = srslte_coreset_get_sz(coreset);
#if DMRS_PDCCH_INTERPOLATE_GROUP
if (srslte_interp_linear_init(&q->interpolator, NOF_PILOTS_X_FREQ_RES / q->coreset.duration, 4)) {
#else
if (srslte_interp_linear_init(&q->interpolator, coreset_bw * 3, 4)) { if (srslte_interp_linear_init(&q->interpolator, coreset_bw * 3, 4)) {
#endif
ERROR("Initiating interpolator\n"); ERROR("Initiating interpolator\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -206,6 +221,17 @@ int srslte_dmrs_pdcch_estimator_init(srslte_dmrs_pdcch_estimator_t* q,
q->ce = srslte_vec_cf_malloc(coreset_sz); q->ce = srslte_vec_cf_malloc(coreset_sz);
} }
if (q->filter == NULL) {
q->filter_len = 5U;
q->filter = srslte_vec_f_malloc(q->filter_len);
if (q->filter == NULL) {
return SRSLTE_ERROR;
}
srslte_chest_set_smooth_filter_gauss(q->filter, q->filter_len - 1, 2);
}
// Save new calculated values // Save new calculated values
q->coreset_bw = coreset_bw; q->coreset_bw = coreset_bw;
q->coreset_sz = coreset_sz; q->coreset_sz = coreset_sz;
@ -229,9 +255,13 @@ void srslte_dmrs_pdcch_estimator_free(srslte_dmrs_pdcch_estimator_t* q)
} }
} }
if (q->filter) {
free(q->filter);
}
srslte_interp_linear_free(&q->interpolator); srslte_interp_linear_free(&q->interpolator);
memset(q, 0, sizeof(srslte_dmrs_pdcch_estimator_t)); SRSLTE_MEM_ZERO(q, srslte_dmrs_pdcch_estimator_t, 1);
} }
static void static void
@ -246,8 +276,10 @@ srslte_dmrs_pdcch_extract(srslte_dmrs_pdcch_estimator_t* q, uint32_t cinit, cons
// Counts enabled frequency domain resources // Counts enabled frequency domain resources
uint32_t rb_coreset_idx = 0; uint32_t rb_coreset_idx = 0;
// Iterate over all possible frequency resources // Iterate over all possible frequency resources
for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { uint32_t freq_domain_res_size = SRSLTE_MIN(q->carrier.nof_prb / 6, SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE);
for (uint32_t i = 0; i < freq_domain_res_size; i++) {
// Skip disabled frequency resources // Skip disabled frequency resources
if (!q->coreset.freq_resources[i]) { if (!q->coreset.freq_resources[i]) {
sequence_skip += NOF_PILOTS_X_FREQ_RES; sequence_skip += NOF_PILOTS_X_FREQ_RES;
@ -300,10 +332,15 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q,
n_id = q->coreset.dmrs_scrambling_id; n_id = q->coreset.dmrs_scrambling_id;
} }
// Bound slot index
uint32_t slot_idx = SRSLTE_SLOT_NR_MOD(q->carrier.numerology, slot_cfg->idx);
// Extract pilots // Extract pilots
for (uint32_t l = 0; l < q->coreset.duration; l++) { for (uint32_t l = 0; l < q->coreset.duration; l++) {
// Calculate PRN sequence initial state // Calculate PRN sequence initial state
uint32_t cinit = dmrs_pdcch_get_cinit(slot_cfg->idx, l, n_id); uint32_t cinit = dmrs_pdcch_get_cinit(slot_idx, l, n_id);
DMRS_PDCCH_INFO_RX("n=%d; l=%d; cinit=%08x\n", slot_idx, l, cinit);
// Extract pilots least square estimates // Extract pilots least square estimates
srslte_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], q->lse[l]); srslte_dmrs_pdcch_extract(q, cinit, &sf_symbols[l * q->carrier.nof_prb * SRSLTE_NRE], q->lse[l]);
@ -312,10 +349,26 @@ int srslte_dmrs_pdcch_estimate(srslte_dmrs_pdcch_estimator_t* q,
// Time averaging and smoothing should be implemented here // Time averaging and smoothing should be implemented here
// ... // ...
// Interpolation, it assumes all frequency domain resources are contiguous // Interpolation in groups
#if DMRS_PDCCH_INTERPOLATE_GROUP
uint32_t group_count = (q->coreset.duration * q->coreset_bw * 3) / NOF_PILOTS_X_FREQ_RES;
uint32_t group_size = NOF_PILOTS_X_FREQ_RES / q->coreset.duration;
for (uint32_t l = 0; l < q->coreset.duration; l++) {
for (uint32_t j = 0; j < group_count; j++) {
cf_t tmp[NOF_PILOTS_X_FREQ_RES];
// Smoothing filter group
srslte_conv_same_cf(&q->lse[l][j * group_size], q->filter, tmp, group_size, q->filter_len);
srslte_interp_linear_offset(
&q->interpolator, tmp, &q->ce[SRSLTE_NRE * q->coreset_bw * l + j * group_size * 4], 1, 3);
}
}
#else
for (uint32_t l = 0; l < q->coreset.duration; l++) { for (uint32_t l = 0; l < q->coreset.duration; l++) {
srslte_interp_linear_offset(&q->interpolator, q->lse[l], &q->ce[SRSLTE_NRE * q->coreset_bw * l], 1, 3); srslte_interp_linear_offset(&q->interpolator, q->lse[l], &q->ce[SRSLTE_NRE * q->coreset_bw * l], 1, 3);
} }
#endif
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -350,11 +403,16 @@ int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q,
float sync_err = 0.0f; float sync_err = 0.0f;
cf_t corr[SRSLTE_CORESET_DURATION_MAX] = {}; cf_t corr[SRSLTE_CORESET_DURATION_MAX] = {};
for (uint32_t l = 0; l < q->coreset.duration; l++) { for (uint32_t l = 0; l < q->coreset.duration; l++) {
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
DMRS_PDCCH_INFO_RX("Measuring PDCCH l=%d; lse=", l);
srslte_vec_fprint_c(stdout, &q->lse[l][pilot_idx], nof_pilots);
}
// Correlate DMRS // Correlate DMRS
corr[l] = srslte_vec_acc_cc(&q->lse[l][pilot_idx], nof_pilots) / (float)nof_pilots; corr[l] = srslte_vec_acc_cc(&q->lse[l][pilot_idx], nof_pilots) / (float)nof_pilots;
// Measure symbol RSRP // Measure symbol RSRP
rsrp += cabsf(corr[l]); rsrp += __real__ corr[l] * __real__ corr[l] + __imag__ corr[l] * __imag__ corr[l];
// Measure symbol EPRE // Measure symbol EPRE
epre += srslte_vec_avg_power_cf(&q->lse[l][pilot_idx], nof_pilots); epre += srslte_vec_avg_power_cf(&q->lse[l][pilot_idx], nof_pilots);
@ -381,6 +439,22 @@ int srslte_dmrs_pdcch_get_measure(const srslte_dmrs_pdcch_estimator_t* q,
measure->sync_error_us = measure->sync_error_us =
(float)SRSLTE_SUBC_SPACING_NR(q->carrier.numerology) * sync_err / (4.0e-6f * (float)q->coreset.duration); (float)SRSLTE_SUBC_SPACING_NR(q->carrier.numerology) * sync_err / (4.0e-6f * (float)q->coreset.duration);
measure->rsrp_dBfs = srslte_convert_power_to_dB(measure->rsrp);
measure->epre_dBfs = srslte_convert_power_to_dB(measure->epre);
if (isnormal(measure->rsrp) && isnormal(measure->epre)) {
measure->norm_corr = measure->rsrp / measure->epre;
} else {
measure->norm_corr = 0.0f;
}
DMRS_PDCCH_INFO_RX("Measure L=%d; ncce=%d; RSRP=%+.1f dBfs; EPRE=%+.1f dBfs; Corr=%.3f\n",
dci_location->L,
dci_location->ncce,
measure->rsrp_dBfs,
measure->epre_dBfs,
measure->norm_corr);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
@ -424,5 +498,8 @@ int srslte_dmrs_pdcch_get_ce(const srslte_dmrs_pdcch_estimator_t* q,
ERROR("Incorrect number of extracted resources (%d != %d)\n", count, ce->nof_re); ERROR("Incorrect number of extracted resources (%d != %d)\n", count, ce->nof_re);
} }
// At the moment Noise is not calculated
ce->noise_var = 0.0f;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -154,6 +154,19 @@ void srslte_enb_dl_nr_gen_signal(srslte_enb_dl_nr_t* q)
} }
} }
int srslte_enb_dl_nr_base_zero(srslte_enb_dl_nr_t* q)
{
if (q == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
for (uint32_t i = 0; i < q->nof_tx_antennas; i++) {
srslte_vec_cf_zero(q->sf_symbols[i], SRSLTE_SLOT_LEN_RE_NR(q->carrier.nof_prb));
}
return SRSLTE_SUCCESS;
}
int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q, int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q,
const srslte_dl_slot_cfg_t* slot_cfg, const srslte_dl_slot_cfg_t* slot_cfg,
const srslte_search_space_t* search_space, const srslte_search_space_t* search_space,
@ -195,6 +208,8 @@ int srslte_enb_dl_nr_pdcch_put(srslte_enb_dl_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
INFO("DCI DL NR: L=%d; ncce=%d;\n", dci_location->L, dci_location->ncce);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -17,6 +17,9 @@
#define PDCCH_NR_POLAR_RM_IBIL 0 #define PDCCH_NR_POLAR_RM_IBIL 0
#define PDCCH_INFO_TX(...) INFO("PDCCH Tx: " __VA_ARGS__)
#define PDCCH_INFO_RX(...) INFO("PDCCH Rx: " __VA_ARGS__)
/** /**
* @brief Recursive Y_p_n function * @brief Recursive Y_p_n function
*/ */
@ -345,7 +348,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
if (srslte_polar_code_get(&q->code, q->K, q->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); PDCCH_INFO_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);
@ -353,7 +356,7 @@ 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)); PDCCH_INFO_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] = {};
@ -365,7 +368,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
// Print c // Print c
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
INFO("PDCCH NR TX: c="); PDCCH_INFO_TX("c=");
srslte_vec_fprint_hex(stdout, q->c, q->K); srslte_vec_fprint_hex(stdout, q->c, q->K);
} }
@ -379,7 +382,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
// Print d // Print d
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
INFO("PDCCH NR TX: d="); PDCCH_INFO_TX("d=");
srslte_vec_fprint_byte(stdout, q->d, q->K); srslte_vec_fprint_byte(stdout, q->d, q->K);
} }
@ -408,7 +411,7 @@ int srslte_pdcch_nr_encode(srslte_pdcch_nr_t* q, const srslte_dci_msg_nr_t* dci_
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
char str[128] = {}; char str[128] = {};
srslte_pdcch_nr_info(q, NULL, str, sizeof(str)); srslte_pdcch_nr_info(q, NULL, str, sizeof(str));
INFO("PDCCH NR TX: %s\n", str); PDCCH_INFO_TX("%s\n", str);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -444,7 +447,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
if (srslte_polar_code_get(&q->code, q->K, q->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); PDCCH_INFO_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);
@ -453,9 +456,21 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Print channel estimates if enabled
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
PDCCH_INFO_RX("ce=");
srslte_vec_fprint_c(stdout, ce->ce, q->M);
}
// Equalise // Equalise
srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, q->M, 1.0f, ce->noise_var); srslte_predecoding_single(q->symbols, ce->ce, q->symbols, NULL, q->M, 1.0f, ce->noise_var);
// Print symbols if enabled
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
PDCCH_INFO_RX("symbols=");
srslte_vec_fprint_c(stdout, q->symbols, q->M);
}
// 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, q->M); srslte_demod_soft_demodulate_b(SRSLTE_MOD_QPSK, q->symbols, llr, q->M);
@ -483,7 +498,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
// Print d // Print d
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
INFO("PDCCH NR RX: d="); PDCCH_INFO_RX("d=");
srslte_vec_fprint_bs(stdout, d, q->K); srslte_vec_fprint_bs(stdout, d, q->K);
} }
@ -498,7 +513,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
// Print c // Print c
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
INFO("PDCCH NR RX: c="); PDCCH_INFO_RX("c=");
srslte_vec_fprint_hex(stdout, q->c, q->K); srslte_vec_fprint_hex(stdout, q->c, q->K);
} }
@ -516,7 +531,10 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
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); if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
PDCCH_INFO_RX("CRC={%06x, %06x}; msg=", checksum1, checksum2);
srslte_vec_fprint_hex(stdout, q->c, dci_msg->nof_bits);
}
// 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);
@ -530,7 +548,7 @@ int srslte_pdcch_nr_decode(srslte_pdcch_nr_t* q,
if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) {
char str[128] = {}; char str[128] = {};
srslte_pdcch_nr_info(q, res, str, sizeof(str)); srslte_pdcch_nr_info(q, res, str, sizeof(str));
INFO("PDCCH NR RX: %s\n", str); PDCCH_INFO_RX("%s\n", str);
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;

@ -13,6 +13,7 @@
#include "srslte/phy/ue/ue_dl_nr.h" #include "srslte/phy/ue/ue_dl_nr.h"
#define UE_DL_NR_PDCCH_CORR_DEFAULT_THR 0.5f #define UE_DL_NR_PDCCH_CORR_DEFAULT_THR 0.5f
#define UE_DL_NR_PDCCH_EPRE_DEFAULT_THR -10.0f
static int ue_dl_nr_alloc_prb(srslte_ue_dl_nr_t* q, uint32_t new_nof_prb) static int ue_dl_nr_alloc_prb(srslte_ue_dl_nr_t* q, uint32_t new_nof_prb)
{ {
@ -189,19 +190,43 @@ static int ue_dl_nr_find_dci_ncce(srslte_ue_dl_nr_t* q, srslte_dci_msg_nr_t* dci
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// If measured RSRP and EPRE is invalid, early return // If measured correlation is invalid, early return
if (!isnormal(m.rsrp) || !isnormal(m.epre)) { if (!isnormal(m.norm_corr)) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; Invalid measurement;\n", dci_msg->location.L, dci_msg->location.ncce);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
// Compare EPRE with threshold
{
float thr = q->pdcch_dmrs_epre_thr;
if (!isnormal(thr)) {
thr = UE_DL_NR_PDCCH_EPRE_DEFAULT_THR; //< Load default threshold if not provided
}
if (m.epre_dBfs < thr) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; EPRE is too weak (%.1f<%.1f);\n",
dci_msg->location.L,
dci_msg->location.ncce,
m.epre_dBfs,
thr);
return SRSLTE_SUCCESS;
}
}
// Compare DMRS correlation with threshold // Compare DMRS correlation with threshold
{
float thr = q->pdcch_dmrs_corr_thr; float thr = q->pdcch_dmrs_corr_thr;
if (!isnormal(thr)) { if (!isnormal(thr)) {
thr = UE_DL_NR_PDCCH_CORR_DEFAULT_THR; //< Load default threshold if not provided thr = UE_DL_NR_PDCCH_CORR_DEFAULT_THR; //< Load default threshold if not provided
} }
if (m.rsrp / m.epre < thr) { if (m.norm_corr < thr) {
INFO("Discarded PDCCH candidate L=%d;ncce=%d; Correlation is too low (%.1f<%.1f);\n",
dci_msg->location.L,
dci_msg->location.ncce,
m.norm_corr,
thr);
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
}
// Extract PDCCH channel estimates // Extract PDCCH channel estimates
if (srslte_dmrs_pdcch_get_ce(&q->dmrs_pdcch, &dci_msg->location, q->pdcch_ce) < SRSLTE_SUCCESS) { if (srslte_dmrs_pdcch_get_ce(&q->dmrs_pdcch, &dci_msg->location, q->pdcch_ce) < SRSLTE_SUCCESS) {

@ -35,11 +35,14 @@ static uint32_t mcs = 30; // Set to 30 for steering
static srslte_pdsch_cfg_nr_t pdsch_cfg = {}; static srslte_pdsch_cfg_nr_t pdsch_cfg = {};
static srslte_pdsch_grant_nr_t pdsch_grant = {}; static srslte_pdsch_grant_nr_t pdsch_grant = {};
static uint16_t rnti = 0x1234; static uint16_t rnti = 0x1234;
static uint32_t nof_slots = 10;
void usage(char* prog) void usage(char* prog)
{ {
printf("Usage: %s [pTL] \n", prog); printf("Usage: %s [pTL] \n", prog);
printf("\t-P Number of BWP (Carrier) PRB [Default %d]\n", carrier.nof_prb);
printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb); printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb);
printf("\t-n Number of slots to simulate [Default %d]\n", nof_slots);
printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); 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", printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n",
srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table)); srslte_mcs_table_to_str(pdsch_cfg.sch_cfg.mcs_table));
@ -50,11 +53,17 @@ void usage(char* prog)
int parse_args(int argc, char** argv) int parse_args(int argc, char** argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "pmTLv")) != -1) { while ((opt = getopt(argc, argv, "PpmnTLv")) != -1) {
switch (opt) { switch (opt) {
case 'P':
carrier.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'p': case 'p':
n_prb = (uint32_t)strtol(argv[optind], NULL, 10); n_prb = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
case 'n':
nof_slots = (uint32_t)strtol(argv[optind], NULL, 10);
break;
case 'm': case 'm':
mcs = (uint32_t)strtol(argv[optind], NULL, 10); mcs = (uint32_t)strtol(argv[optind], NULL, 10);
break; break;
@ -76,6 +85,62 @@ int parse_args(int argc, char** argv)
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int work_gnb_dl(srslte_enb_dl_nr_t* enb_dl,
srslte_dl_slot_cfg_t* slot,
srslte_search_space_t* search_space,
srslte_dci_dl_nr_t* dci_dl,
srslte_dci_location_t* dci_location,
uint8_t** data_tx)
{
if (srslte_enb_dl_nr_base_zero(enb_dl) < SRSLTE_SUCCESS) {
ERROR("Error setting base to zero\n");
return SRSLTE_ERROR;
}
// Put actual DCI
if (srslte_enb_dl_nr_pdcch_put(enb_dl, slot, search_space, dci_dl, dci_location, rnti) < SRSLTE_SUCCESS) {
ERROR("Error putting PDCCH\n");
return SRSLTE_ERROR;
}
// Put PDSCH transmission
if (srslte_enb_dl_nr_pdsch_put(enb_dl, slot, &pdsch_cfg, &pdsch_grant, data_tx) < SRSLTE_SUCCESS) {
ERROR("Error putting PDSCH\n");
return SRSLTE_ERROR;
}
srslte_enb_dl_nr_gen_signal(enb_dl);
return SRSLTE_SUCCESS;
}
int work_ue_dl(srslte_ue_dl_nr_t* ue_dl,
srslte_dl_slot_cfg_t* slot,
srslte_search_space_t* search_space,
srslte_pdsch_res_nr_t* pdsch_res)
{
srslte_ue_dl_nr_estimate_fft(ue_dl, slot);
srslte_dci_dl_nr_t dci_dl_rx = {};
int nof_found_dci = srslte_ue_dl_nr_find_dl_dci(ue_dl, search_space, slot, rnti, &dci_dl_rx, 1);
if (nof_found_dci < SRSLTE_SUCCESS) {
ERROR("Error decoding\n");
return SRSLTE_ERROR;
}
if (nof_found_dci < 1) {
ERROR("Error DCI not found\n");
return SRSLTE_ERROR;
}
if (srslte_ue_dl_nr_pdsch_get(ue_dl, slot, &pdsch_cfg, &pdsch_grant, pdsch_res) < SRSLTE_SUCCESS) {
ERROR("Error decoding\n");
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
@ -84,6 +149,10 @@ int main(int argc, char** argv)
srslte_pdsch_res_nr_t pdsch_res[SRSLTE_MAX_TB] = {}; srslte_pdsch_res_nr_t pdsch_res[SRSLTE_MAX_TB] = {};
srslte_random_t rand_gen = srslte_random_init(1234); srslte_random_t rand_gen = srslte_random_init(1234);
srslte_dl_slot_cfg_t slot = {}; srslte_dl_slot_cfg_t slot = {};
struct timeval t[3] = {};
uint64_t pdsch_encode_us = 0;
uint64_t pdsch_decode_us = 0;
uint64_t nof_bits = 0;
uint8_t* data_tx[SRSLTE_MAX_TB] = {}; uint8_t* data_tx[SRSLTE_MAX_TB] = {};
uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {}; uint8_t* data_rx[SRSLTE_MAX_CODEWORDS] = {};
@ -97,15 +166,16 @@ int main(int argc, char** argv)
srslte_ue_dl_nr_args_t ue_dl_args = {}; srslte_ue_dl_nr_args_t ue_dl_args = {};
ue_dl_args.nof_rx_antennas = 1; ue_dl_args.nof_rx_antennas = 1;
ue_dl_args.nof_max_prb = MAX_PRB; ue_dl_args.pdsch.sch.disable_simd = false;
ue_dl_args.pdsch.sch.disable_simd = true; ue_dl_args.pdsch.sch.decoder_use_flooded = false;
ue_dl_args.pdsch.measure_evm = true; ue_dl_args.pdsch.measure_evm = true;
ue_dl_args.pdsch.measure_time = true; ue_dl_args.pdcch.disable_simd = false;
ue_dl_args.pdcch.measure_evm = true;
srslte_enb_dl_nr_args_t enb_dl_args = {}; srslte_enb_dl_nr_args_t enb_dl_args = {};
enb_dl_args.nof_tx_antennas = 1; enb_dl_args.nof_tx_antennas = 1;
enb_dl_args.nof_max_prb = MAX_PRB; enb_dl_args.pdsch.sch.disable_simd = false;
enb_dl_args.pdsch.sch.disable_simd = true; enb_dl_args.pdcch.disable_simd = false;
// Set default PDSCH configuration // Set default PDSCH configuration
pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam; pdsch_cfg.sch_cfg.mcs_table = srslte_mcs_table_64qam;
@ -113,21 +183,17 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
srslte_pdsch_nr_args_t pdsch_args = {};
pdsch_args.sch.disable_simd = true;
pdsch_args.measure_evm = true;
// Configure CORESET // Configure CORESET
srslte_coreset_t coreset = {}; srslte_coreset_t coreset = {};
coreset.duration = 2; coreset.duration = 2;
for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { for (uint32_t i = 0; i < SRSLTE_CORESET_FREQ_DOMAIN_RES_SIZE; i++) {
coreset.freq_resources[i] = i < carrier.nof_prb; coreset.freq_resources[i] = i < carrier.nof_prb / 6;
} }
// Configure Search Space // Configure Search Space
srslte_search_space_t search_space = {}; srslte_search_space_t search_space = {};
search_space.type = srslte_search_space_type_ue; search_space.type = srslte_search_space_type_ue;
for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR; L++) { for (uint32_t L = 0; L < SRSLTE_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) {
search_space.nof_candidates[L] = srslte_pdcch_nr_max_candidates_coreset(&coreset, L); search_space.nof_candidates[L] = srslte_pdcch_nr_max_candidates_coreset(&coreset, L);
} }
@ -210,8 +276,10 @@ int main(int argc, char** argv)
mcs_end = SRSLTE_MIN(mcs + 1, mcs_end); mcs_end = SRSLTE_MIN(mcs + 1, mcs_end);
} }
uint64_t slot_count = 0;
for (slot.idx = 0; slot.idx < nof_slots; slot.idx++) {
for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) { for (n_prb = n_prb_start; n_prb < n_prb_end; n_prb++) {
for (mcs = mcs_start; mcs < mcs_end; mcs++) { for (mcs = mcs_start; mcs < mcs_end; mcs++, slot_count++) {
for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) { for (uint32_t n = 0; n < SRSLTE_MAX_PRB_NR; n++) {
pdsch_grant.prb_idx[n] = (n < n_prb); pdsch_grant.prb_idx[n] = (n < n_prb);
@ -252,43 +320,28 @@ int main(int argc, char** argv)
// Setup DCI // Setup DCI
srslte_dci_dl_nr_t dci_dl = {}; srslte_dci_dl_nr_t dci_dl = {};
// Put actual DCI gettimeofday(&t[1], NULL);
if (srslte_enb_dl_nr_pdcch_put(&enb_dl, &slot, &search_space, &dci_dl, &dci_location, rnti) < SRSLTE_SUCCESS) { if (work_gnb_dl(&enb_dl, &slot, &search_space, &dci_dl, &dci_location, data_tx) < SRSLTE_ERROR) {
ERROR("Error putting PDCCH\n"); ERROR("Error running eNb DL\n");
goto clean_exit;
}
// Put PDSCH transmission
if (srslte_enb_dl_nr_pdsch_put(&enb_dl, &slot, &pdsch_cfg, &pdsch_grant, data_tx) < SRSLTE_SUCCESS) {
ERROR("Error putting PDSCH\n");
goto clean_exit; goto clean_exit;
} }
gettimeofday(&t[2], NULL);
srslte_enb_dl_nr_gen_signal(&enb_dl); get_time_interval(t);
pdsch_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx; pdsch_grant.tb[tb].softbuffer.rx = &softbuffer_rx;
srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx); srslte_softbuffer_rx_reset(pdsch_grant.tb[tb].softbuffer.rx);
} }
srslte_ue_dl_nr_estimate_fft(&ue_dl, &slot); gettimeofday(&t[1], NULL);
if (work_ue_dl(&ue_dl, &slot, &search_space, pdsch_res) < SRSLTE_SUCCESS) {
srslte_dci_dl_nr_t dci_dl_rx = {}; ERROR("Error running UE DL\n");
int nof_found_dci = srslte_ue_dl_nr_find_dl_dci(&ue_dl, &search_space, &slot, rnti, &dci_dl_rx, 1);
if (nof_found_dci < SRSLTE_SUCCESS) {
ERROR("Error decoding\n");
goto clean_exit;
}
if (nof_found_dci < 1) {
ERROR("Error DCI not found\n");
goto clean_exit;
}
if (srslte_ue_dl_nr_pdsch_get(&ue_dl, &slot, &pdsch_cfg, &pdsch_grant, pdsch_res) < SRSLTE_SUCCESS) {
ERROR("Error decoding\n");
goto clean_exit; goto clean_exit;
} }
gettimeofday(&t[2], NULL);
get_time_interval(t);
pdsch_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
if (pdsch_res->evm > 0.001f) { if (pdsch_res->evm > 0.001f) {
ERROR("Error PDSCH EVM is too high %f\n", pdsch_res->evm); ERROR("Error PDSCH EVM is too high %f\n", pdsch_res->evm);
@ -309,9 +362,21 @@ int main(int argc, char** argv)
goto clean_exit; goto clean_exit;
} }
printf("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm); INFO("n_prb=%d; mcs=%d; TBS=%d; EVM=%f; PASSED!\n", n_prb, mcs, pdsch_grant.tb[0].tbs, pdsch_res[0].evm);
// Count the Tx/Rx'd number of bits
nof_bits += pdsch_grant.tb[0].tbs;
} }
} }
}
printf("[Rates in Mbps] Granted Processed\n");
printf(" eNb: %5.1f %5.1f\n",
(double)nof_bits / (double)slot_count / 1000.0f,
(double)nof_bits / pdsch_encode_us);
printf(" UE: %5.1f %5.1f\n",
(double)nof_bits / (double)slot_count / 1000.0f,
(double)nof_bits / pdsch_decode_us);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;

Loading…
Cancel
Save