mirror of https://github.com/PentHertz/srsLTE.git
Implemented PDCCH DCI message correlation and updated test
This commit is contained in:
parent
bcd2e59635
commit
7c78fd2050
|
@ -95,6 +95,14 @@ SRSRAN_API int srsran_pdcch_extract_llr(srsran_pdcch_t* q,
|
|||
SRSRAN_API int
|
||||
srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dci_cfg_t* dci_cfg, srsran_dci_msg_t* msg);
|
||||
|
||||
/**
|
||||
* @brief Computes decoded DCI correlation. It encodes the given DCI message and compares it with the received LLRs
|
||||
* @param q PDCCH object
|
||||
* @param msg Previously decoded DCI message
|
||||
* @return The normalized correlation between the restored symbols and the received LLRs
|
||||
*/
|
||||
SRSRAN_API float srsran_pdcch_msg_corr(srsran_pdcch_t* q, srsran_dci_msg_t* msg);
|
||||
|
||||
SRSRAN_API int
|
||||
srsran_pdcch_dci_decode(srsran_pdcch_t* q, float* e, uint8_t* data, uint32_t E, uint32_t nof_bits, uint16_t* crc);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -412,6 +413,27 @@ int srsran_pdcch_decode_msg(srsran_pdcch_t* q, srsran_dl_sf_cfg_t* sf, srsran_dc
|
|||
return ret;
|
||||
}
|
||||
|
||||
float srsran_pdcch_msg_corr(srsran_pdcch_t* q, srsran_dci_msg_t* msg)
|
||||
{
|
||||
if (q == NULL || msg == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
uint32_t E = PDCCH_FORMAT_NOF_BITS(msg->location.L);
|
||||
uint32_t nof_llr = E / 2;
|
||||
|
||||
// Encode same decoded message and compute correlation
|
||||
srsran_pdcch_dci_encode(q, msg->payload, q->e, msg->nof_bits, E, msg->rnti);
|
||||
|
||||
// Modulate
|
||||
srsran_mod_modulate(&q->mod, q->e, q->d, E);
|
||||
|
||||
// Correlate
|
||||
cf_t corr = srsran_vec_dot_prod_conj_ccc((cf_t*)&q->llr[msg->location.ncce * 72], q->d, nof_llr);
|
||||
|
||||
return cabsf(corr / nof_llr) * (float)M_SQRT1_2;
|
||||
}
|
||||
|
||||
/** Performs PDCCH receiver processing to extract LLR for all control region. LLR bits are stored in srsran_pdcch_t
|
||||
* object. DCI can be decoded from given locations in successive calls to srsran_pdcch_decode_msg()
|
||||
*/
|
||||
|
|
|
@ -198,19 +198,20 @@ add_lte_test(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
|
|||
add_executable(pdcch_test pdcch_test.c)
|
||||
target_link_libraries(pdcch_test srsran_phy)
|
||||
|
||||
add_lte_test(pdcch_test_6 pdcch_test -n 6)
|
||||
add_lte_test(pdcch_test_15 pdcch_test -n 15)
|
||||
add_lte_test(pdcch_test_25 pdcch_test -n 25)
|
||||
add_lte_test(pdcch_test_50 pdcch_test -n 50)
|
||||
add_lte_test(pdcch_test_75 pdcch_test -n 75)
|
||||
add_lte_test(pdcch_test_100 pdcch_test -n 100)
|
||||
add_lte_test(pdcch_test_6_mimo pdcch_test -n 6 -p 2)
|
||||
add_lte_test(pdcch_test_15_mimo pdcch_test -n 15 -p 2)
|
||||
add_lte_test(pdcch_test_25_mimo pdcch_test -n 25 -p 2)
|
||||
add_lte_test(pdcch_test_50_mimo pdcch_test -n 50 -p 2)
|
||||
add_lte_test(pdcch_test_75_mimo pdcch_test -n 75 -p 2)
|
||||
add_lte_test(pdcch_test_100_mimo pdcch_test -n 100 -p 2)
|
||||
#add_lte_test(pdcch_test_crosscarrier pdcch_test -x)
|
||||
foreach (nof_prb 6 15 25 50 75 100)
|
||||
foreach (nof_ports 1 2)
|
||||
foreach (cfi 1 2 3)
|
||||
foreach (snr auto 15 300)
|
||||
set(pdcch_test_args "")
|
||||
set(pdcch_test_args -n ${nof_prb} -p ${nof_ports} -f ${cfi} -S ${snr} -R 1 -F)
|
||||
|
||||
string(REGEX REPLACE "\ " "" test_name_args ${pdcch_test_args})
|
||||
|
||||
add_lte_test(pdcch_test${test_name_args} pdcch_test ${pdcch_test_args})
|
||||
endforeach ()
|
||||
endforeach ()
|
||||
endforeach ()
|
||||
endforeach ()
|
||||
|
||||
########################################################################
|
||||
# PDSCH TEST
|
||||
|
|
|
@ -19,25 +19,25 @@
|
|||
#include "srsran/srsran.h"
|
||||
|
||||
// Test parameters
|
||||
static uint32_t pci = 1;
|
||||
static uint16_t rnti = 0x46;
|
||||
static uint32_t cfi = 1;
|
||||
static uint32_t nof_ports = 1;
|
||||
static uint32_t pci = 1;
|
||||
static uint16_t rnti = 0x46;
|
||||
static uint32_t cfi = 2;
|
||||
static uint32_t nof_ports = 1;
|
||||
static srsran_dci_cfg_t dci_cfg = {};
|
||||
static uint32_t nof_prb = 100;
|
||||
static float snr_dB = 20.0f;
|
||||
static float snr_dB = NAN;
|
||||
static uint32_t repetitions = 1;
|
||||
static bool false_check = false;
|
||||
|
||||
// Test objects
|
||||
static srsran_random_t random_gen = NULL;
|
||||
static srsran_pdcch_t pdcch_tx = {};
|
||||
static srsran_pdcch_t pdcch_rx = {};
|
||||
static srsran_chest_dl_res_t chest_dl_res = {};
|
||||
static srsran_channel_awgn_t awgn = {};
|
||||
static cf_t* slot_symbols[SRSRAN_MAX_PORTS];
|
||||
static srsran_random_t random_gen = NULL;
|
||||
static srsran_pdcch_t pdcch_tx = {};
|
||||
static srsran_pdcch_t pdcch_rx = {};
|
||||
static srsran_chest_dl_res_t chest_dl_res = {};
|
||||
static srsran_channel_awgn_t awgn = {};
|
||||
static cf_t* slot_symbols[SRSRAN_MAX_PORTS] = {};
|
||||
|
||||
void usage(char* prog)
|
||||
static void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s [pfncxv]\n", prog);
|
||||
printf("\t-c cell id [Default %d]\n", pci);
|
||||
|
@ -45,13 +45,16 @@ void usage(char* prog)
|
|||
printf("\t-p cell.nof_ports [Default %d]\n", nof_ports);
|
||||
printf("\t-n cell.nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-x Enable/Disable Cross-scheduling [Default %s]\n", dci_cfg.cif_enabled ? "enabled" : "disabled");
|
||||
printf("\t-F False detection check [Default %s]\n", false_check ? "enabled" : "disabled");
|
||||
printf("\t-R Repetitions [Default %d]\n", repetitions);
|
||||
printf("\t-S SNR in dB [Default %+.1f]\n", snr_dB);
|
||||
printf("\t-v [set srsran_verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char** argv)
|
||||
static void parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "pfncxv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "pfncxvFRS")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
nof_ports = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
|
@ -66,7 +69,16 @@ void parse_args(int argc, char** argv)
|
|||
pci = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'x':
|
||||
dci_cfg.cif_enabled ^= true;
|
||||
dci_cfg.cif_enabled = !dci_cfg.cif_enabled;
|
||||
break;
|
||||
case 'F':
|
||||
false_check = !false_check;
|
||||
break;
|
||||
case 'R':
|
||||
repetitions = (uint32_t)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'S':
|
||||
snr_dB = (float)strtof(argv[optind], NULL);
|
||||
break;
|
||||
case 'v':
|
||||
srsran_verbose++;
|
||||
|
@ -76,6 +88,17 @@ void parse_args(int argc, char** argv)
|
|||
exit(-1);
|
||||
}
|
||||
}
|
||||
printf("params - pci=%d; rnti=0x%04x; cfi=%d; nof_ports=%d; cif_enabled=%d; nof_prb=%d; snr_db=%+.1f; "
|
||||
"repetitions=%d; false_check=%d;\n",
|
||||
pci,
|
||||
rnti,
|
||||
cfi,
|
||||
nof_ports,
|
||||
dci_cfg.cif_enabled,
|
||||
nof_prb,
|
||||
snr_dB,
|
||||
repetitions,
|
||||
false_check);
|
||||
}
|
||||
|
||||
static void print_dci_msg(const char* desc, const srsran_dci_msg_t* dci_msg)
|
||||
|
@ -142,19 +165,32 @@ static const srsran_dci_format_t formats[] = {SRSRAN_DCI_FORMAT0,
|
|||
SRSRAN_DCI_FORMAT2,
|
||||
SRSRAN_DCI_NOF_FORMATS};
|
||||
|
||||
static float get_snr_dB(uint32_t L)
|
||||
{
|
||||
static const float snr_table_dB[4] = {15.0f, 6.0f, 5.0f, 0.0f};
|
||||
|
||||
if (isnormal(snr_dB) && L < 4) {
|
||||
return snr_dB;
|
||||
}
|
||||
|
||||
return snr_table_dB[L];
|
||||
}
|
||||
|
||||
static int test_case1()
|
||||
{
|
||||
uint32_t nof_re = SRSRAN_NOF_RE(pdcch_tx.cell);
|
||||
struct timeval t[3] = {};
|
||||
uint64_t t_encode_us = 0;
|
||||
uint64_t t_encode_count = 0;
|
||||
uint64_t t_llr_us = 0;
|
||||
uint64_t t_decode_us = 0;
|
||||
uint64_t t_decode_count = 0;
|
||||
uint32_t nof_re = SRSRAN_NOF_RE(pdcch_tx.cell);
|
||||
|
||||
// Iterate all possible subframes
|
||||
for (uint32_t f_idx = 0; formats[f_idx] != SRSRAN_DCI_NOF_FORMATS; f_idx++) {
|
||||
srsran_dci_format_t format = formats[f_idx];
|
||||
srsran_dci_format_t format = formats[f_idx];
|
||||
struct timeval t[3] = {};
|
||||
uint64_t t_encode_us = 0;
|
||||
uint64_t t_encode_count = 0;
|
||||
uint64_t t_llr_us = 0;
|
||||
uint64_t t_decode_us = 0;
|
||||
uint64_t t_decode_count = 0;
|
||||
uint32_t false_alarm_corr_count = 0;
|
||||
float min_corr = INFINITY;
|
||||
|
||||
for (uint32_t sf_idx = 0; sf_idx < repetitions * SRSRAN_NOF_SF_X_FRAME; sf_idx++) {
|
||||
srsran_dl_sf_cfg_t dl_sf_cfg = {};
|
||||
|
@ -196,6 +232,11 @@ static int test_case1()
|
|||
t_encode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
|
||||
t_encode_count++;
|
||||
|
||||
// Set noise level according to aggregation level
|
||||
float n0_dB = -get_snr_dB(locations[loc].L);
|
||||
TESTASSERT(srsran_channel_awgn_set_n0(&awgn, n0_dB) == SRSRAN_SUCCESS);
|
||||
chest_dl_res.noise_estimate = srsran_convert_dB_to_power(n0_dB);
|
||||
|
||||
// Apply AWGN
|
||||
for (uint32_t p = 0; p < nof_ports; p++) {
|
||||
srsran_channel_awgn_run_c(&awgn, slot_symbols[p], slot_symbols[p], nof_re);
|
||||
|
@ -210,7 +251,10 @@ static int test_case1()
|
|||
|
||||
// Try decoding the PDCCH in all possible locations
|
||||
for (uint32_t loc_rx = 0; loc_rx < locations_count; loc_rx++) {
|
||||
if (!false_check && loc_rx != loc) {
|
||||
// Skip location if:
|
||||
// - False check is disabled and Tx/Rx dont match
|
||||
// - Tx aggregation level is bigger than Rx aggregation level
|
||||
if ((!false_check && loc_rx != loc) || locations[loc_rx].L < locations[loc].L) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -227,16 +271,42 @@ static int test_case1()
|
|||
t_decode_us += (size_t)(t[0].tv_sec * 1e6 + t[0].tv_usec);
|
||||
t_decode_count++;
|
||||
|
||||
// Compute LLR correlation
|
||||
float corr = srsran_pdcch_msg_corr(&pdcch_rx, &dci_rx);
|
||||
|
||||
bool rnti_match = (dci_tx.rnti == dci_rx.rnti);
|
||||
bool location_match = (loc == loc_rx);
|
||||
bool payload_match = (memcmp(dci_tx.payload, dci_rx.payload, dci_tx.nof_bits) == 0);
|
||||
bool corr_thr = corr > 0.5f;
|
||||
|
||||
// Skip location if the decoding is not successful in a different location than transmitted
|
||||
if (!location_match && !rnti_match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip location if the correlation does not surpass the threshold
|
||||
if (!location_match && !corr_thr) {
|
||||
false_alarm_corr_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assert correlation only if location matches
|
||||
if (location_match) {
|
||||
TESTASSERT(corr_thr);
|
||||
if (location_match && corr < min_corr) {
|
||||
min_corr = corr;
|
||||
}
|
||||
}
|
||||
|
||||
if (srsran_verbose >= SRSRAN_VERBOSE_INFO || !payload_match) {
|
||||
// If payload is not match and there is no logging, set logging to info and run the decoder again
|
||||
if (srsran_verbose < SRSRAN_VERBOSE_INFO) {
|
||||
printf("-- Detected payload was not matched, repeating decode with INFO logs (n0: %+.1f dB, corr: %f)\n",
|
||||
n0_dB,
|
||||
corr);
|
||||
srsran_verbose = SRSRAN_VERBOSE_INFO;
|
||||
srsran_pdcch_decode_msg(&pdcch_rx, &dl_sf_cfg, &dci_cfg, &dci_rx);
|
||||
}
|
||||
print_dci_msg("Tx: ", &dci_tx);
|
||||
print_dci_msg("Rx: ", &dci_rx);
|
||||
}
|
||||
|
@ -246,12 +316,16 @@ static int test_case1()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("test_case_1 - %.1f usec/encode; %.1f usec/llr; %.1f usec/decode;\n",
|
||||
(double)t_encode_us / (double)(t_encode_count),
|
||||
(double)t_llr_us / (double)(t_encode_count),
|
||||
(double)t_decode_us / (double)(t_decode_count));
|
||||
printf("test_case_1 - format %s - passed - %.1f usec/encode; %.1f usec/llr; %.1f usec/decode; min_corr=%f; "
|
||||
"false_alarm_prob=%f;\n",
|
||||
srsran_dci_format_string(format),
|
||||
(double)t_encode_us / (double)(t_encode_count),
|
||||
(double)t_llr_us / (double)(t_encode_count),
|
||||
(double)t_decode_us / (double)(t_decode_count),
|
||||
min_corr,
|
||||
(double)false_alarm_corr_count / (double)t_decode_count);
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
@ -319,11 +393,6 @@ int main(int argc, char** argv)
|
|||
goto quit;
|
||||
}
|
||||
|
||||
if (srsran_channel_awgn_set_n0(&awgn, -snr_dB) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error setting n0");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
// Execute actual test cases
|
||||
if (test_case1() < SRSRAN_SUCCESS) {
|
||||
ERROR("Test case 1 failed");
|
||||
|
|
Loading…
Reference in New Issue