From 610795c7d80a7622f9016d319ca54c4076a8f33b Mon Sep 17 00:00:00 2001 From: Gabriele Gemmi Date: Tue, 10 Mar 2026 01:44:37 +0000 Subject: [PATCH] Read DBT from libconfig --- openair2/GNB_APP/gnb_config.c | 74 +++++++++++++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/config.c | 8 ++-- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 42ee49ca5a..720044c213 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1455,6 +1455,75 @@ static double complex **read_dbt_from_csv(const char *filename, return table; } +#define DBT_PARAMS_DESC { \ + {"", "beam", 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ +} + +static double complex **read_dbt_from_config(const char *prefix, + int *num_beams, + int *num_weights_per_beam, + uint16_t **beam_ids) +{ + paramdef_t dbt_params[] = DBT_PARAMS_DESC; + paramlist_def_t dbt_list = {"dbt", NULL, 0}; + int ret = config_getlist(config_get_if(), &dbt_list, dbt_params, sizeofArray(dbt_params), prefix); + if (ret <= 0) { + *num_beams = 0; + *num_weights_per_beam = 0; + *beam_ids = NULL; + return NULL; + } + + const int beams = ret; + int weights = 0; + double complex **table = calloc_or_fail(beams, sizeof(*table)); + uint16_t *ids = calloc_or_fail(beams, sizeof(*ids)); + + for (int b = 0; b < beams; ++b) { + paramdef_t *row = &dbt_list.paramarray[b][0]; + AssertFatal(row->strlistptr != NULL, "Invalid dbt row %d in section '%s': missing string list\n", b, prefix); + AssertFatal(row->numelt >= 2, + "Invalid dbt row %d in section '%s': expected beam_id + >=1 weights, got %d elements\n", + b, + prefix, + row->numelt); + + const int row_weights = row->numelt - 1; + if (weights == 0) + weights = row_weights; + AssertFatal(weights == row_weights, + "Inconsistent dbt row width in section '%s': row %d has %d weights, expected %d\n", + prefix, + b, + row_weights, + weights); + + errno = 0; + char *endptr = NULL; + long beam_id = strtol(row->strlistptr[0], &endptr, 10); + AssertFatal(endptr != row->strlistptr[0] && errno != ERANGE && *endptr == '\0' && beam_id >= 0 && beam_id <= UINT16_MAX, + "Invalid dbt beam id '%s' in section '%s', row %d\n", + row->strlistptr[0], + prefix, + b); + ids[b] = (uint16_t)beam_id; + + table[b] = calloc_or_fail(weights, sizeof(*table[b])); + for (int w = 0; w < weights; ++w) + AssertFatal(parse_complex_token(row->strlistptr[w + 1], &table[b][w]), + "Invalid dbt complex weight '%s' in section '%s', row %d col %d\n", + row->strlistptr[w + 1], + prefix, + b, + w + 1); + } + + *num_beams = beams; + *num_weights_per_beam = weights; + *beam_ids = ids; + return table; +} + void RCconfig_nr_macrlc(configmodule_interface_t *cfg) { int j = 0; @@ -1723,6 +1792,11 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(GNB_APP, "loading DBT table from file %s\n", *fptr); config.bt.beam_weights = read_dbt_from_csv(*fptr, &config.bt.num_beams, &config.bt.num_weights_per_beam, &config.bt.beam_ids); + } else { + char prefix[MAX_OPTNAME_SIZE * 2 + 8]; + snprintf(prefix, sizeof(prefix), CONFIG_STRING_MACRLC_LIST ".[%d]", j); + config.bt.beam_weights = + read_dbt_from_config(prefix, &config.bt.num_beams, &config.bt.num_weights_per_beam, &config.bt.beam_ids); } // triggers also PHY initialization in case we have L1 via FAPI nr_mac_config_scc(RC.nrmac[j], scc, &config); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index dc26361712..643b607d25 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -82,7 +82,7 @@ static void log_dbt_table(const nr_beam_table_t *bt) if (!bt || bt->num_beams <= 0 || bt->num_weights_per_beam <= 0 || !bt->beam_weights) return; - LOG_I(NR_MAC, "DBT dump: num_beams=%d num_weights_per_beam=%d\n", bt->num_beams, bt->num_weights_per_beam); + LOG_I(NR_MAC, "DBT: num_beams=%d num_weights_per_beam=%d\n", bt->num_beams, bt->num_weights_per_beam); for (int b = 0; b < bt->num_beams; ++b) { uint16_t beam_id = bt->beam_ids ? bt->beam_ids[b] : b; @@ -96,7 +96,7 @@ static void log_dbt_table(const nr_beam_table_t *bt) w, creal(bt->beam_weights[b][w]), cimag(bt->beam_weights[b][w])); - LOG_I(NR_MAC, "%s\n", line); + LOG_D(NR_MAC, "%s\n", line); } } @@ -456,8 +456,8 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR for (uint16_t w = 0; w < cfg->dbt_config.num_txrus; ++w) { float re = crealf(config->bt.beam_weights[b][w]); float im = cimagf(config->bt.beam_weights[b][w]); - AssertFatal(re > -1.0f && re < 1.0f, "DBT real weight out of range [-1,1]: %f\n", re); - AssertFatal(im > -1.0f && im < 1.0f, "DBT imag weight out of range [-1,1]: %f\n", im); + AssertFatal(re >= -1.0f && re <= 1.0f, "DBT real weight out of range [-1,1]: %f\n", re); + AssertFatal(im >= -1.0f && im <= 1.0f, "DBT imag weight out of range [-1,1]: %f\n", im); c16_t q15 = convert_precoder_weight(config->bt.beam_weights[b][w]); beam->txru_list[w].dig_beam_weight_Re = (uint16_t)q15.r; beam->txru_list[w].dig_beam_weight_Im = (uint16_t)q15.i;