Commit d448e99e authored by Gabriele Gemmi's avatar Gabriele Gemmi

read DBT from csv

parent 3f3576bb
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
#define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration" #define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration"
#define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period" #define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period"
#define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights" #define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights"
#define CONFIG_STRING_MACRLC_DBT_FILE "dbt_file"
#define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue" #define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue"
...@@ -97,6 +98,7 @@ ...@@ -97,6 +98,7 @@
#define HLP_MACRLC_AB "Flag to enable analog beamforming" #define HLP_MACRLC_AB "Flag to enable analog beamforming"
#define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams" #define HLP_MACRLC_BEAM_DURATION "number of consecutive slots for a given set of beams"
#define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period" #define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period"
#define HLP_MACRLC_DBT_FILE "File path to CSV file to read digital beamforming table"
#define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS" #define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)" #define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)"
...@@ -147,6 +149,7 @@ ...@@ -147,6 +149,7 @@
{CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \
{CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ {CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \
{CONFIG_STRING_MACRLC_DBT_FILE, HLP_MACRLC_DBT_FILE, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \
{CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \ {CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ {CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \
...@@ -195,9 +198,10 @@ ...@@ -195,9 +198,10 @@
#define MACRLC_ANALOG_BEAM_DURATION_IDX 37 #define MACRLC_ANALOG_BEAM_DURATION_IDX 37
#define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38 #define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38
#define MACRLC_BEAMWEIGHTS_IDX 39 #define MACRLC_BEAMWEIGHTS_IDX 39
#define MACRLC_PUSCH_RSSI_THRES_IDX 40 #define MACRLC_DBT_FILE_IDX 40
#define MACRLC_PUCCH_RSSI_THRES_IDX 41 #define MACRLC_PUSCH_RSSI_THRES_IDX 41
#define MACRLC_STATS_MAX_UE_IDX 42 #define MACRLC_PUCCH_RSSI_THRES_IDX 42
#define MACRLC_STATS_MAX_UE_IDX 43
#define MACRLCPARAMS_CHECK { \ #define MACRLCPARAMS_CHECK { \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
...@@ -243,6 +247,7 @@ ...@@ -243,6 +247,7 @@
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
*/ */
#include "gnb_config.h" #include "gnb_config.h"
#include <ctype.h>
#include <complex.h>
#include <errno.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -1361,6 +1364,97 @@ static void get_bwp_config(nr_mac_config_t *configuration, const NR_ServingCellC ...@@ -1361,6 +1364,97 @@ static void get_bwp_config(nr_mac_config_t *configuration, const NR_ServingCellC
} }
} }
static bool parse_complex_token(const char *tok, double complex *out)
{
double re = 0.0;
double im = 0.0;
if (sscanf(tok, "%lf%lfi", &re, &im) == 2 || sscanf(tok, "%lf%lfj", &re, &im) == 2) {
*out = re + I * im;
return true;
}
if (sscanf(tok, "%lfi", &im) == 1 || sscanf(tok, "%lfj", &im) == 1) {
*out = I * im;
return true;
}
if (sscanf(tok, "%lf", &re) == 1) {
*out = re;
return true;
}
return false;
}
static double complex **read_dbt_from_csv(const char *filename,
int *num_beams,
int *num_weights_per_beam,
uint16_t **beam_ids)
{
FILE *fp = fopen(filename, "r");
AssertFatal(fp != NULL, "Failed to open DBT CSV file '%s'\n", filename);
char line[16384];
AssertFatal(fgets(line, sizeof(line), fp) != NULL, "Failed to read DBT CSV header from '%s'\n", filename);
int weights = 1;
for (char *p = line; *p; ++p)
if (*p == ',')
weights++;
weights -= 1; // first column is beam ID
AssertFatal(weights > 0, "DBT CSV '%s' has no weight columns\n", filename);
int beams = 0;
while (fgets(line, sizeof(line), fp))
beams++;
AssertFatal(beams > 0, "No DBT beam rows found in CSV file '%s'\n", filename);
rewind(fp);
AssertFatal(fgets(line, sizeof(line), fp) != NULL, "Failed to reread DBT CSV header from '%s'\n", filename);
double complex **table = calloc_or_fail(beams, sizeof(*table));
uint16_t *ids = calloc_or_fail(beams, sizeof(*ids));
int b = 0;
while (fgets(line, sizeof(line), fp)) {
line[strcspn(line, "\r\n")] = '\0';
char *saveptr = NULL;
char *tok = strtok_r(line, ",", &saveptr);
AssertFatal(tok != NULL, "Malformed DBT row %d in '%s'\n", b + 1, filename);
errno = 0;
char *endptr = NULL;
long beam_id = strtol(tok, &endptr, 10);
AssertFatal(endptr != tok && errno != ERANGE && *endptr == '\0' && beam_id >= 0 && beam_id <= UINT16_MAX,
"Invalid DBT beam id '%s' in file '%s', beam row %d\n",
tok,
filename,
b + 1);
ids[b] = (uint16_t)beam_id;
table[b] = calloc_or_fail(weights, sizeof(*table[b]));
for (int w = 0; w < weights; ++w) {
tok = strtok_r(NULL, ",", &saveptr);
AssertFatal(tok != NULL, "Missing DBT weight in file '%s', beam row %d column %d\n", filename, b + 1, w + 1);
AssertFatal(parse_complex_token(tok, &table[b][w]),
"Invalid DBT complex weight '%s' in file '%s', beam row %d column %d\n",
tok,
filename,
b + 1,
w + 1);
}
AssertFatal(strtok_r(NULL, ",", &saveptr) == NULL,
"Too many DBT columns in file '%s', beam row %d\n",
filename,
b + 1);
b++;
}
AssertFatal(b == beams, "Parsed %d DBT rows but counted %d in file '%s'\n", b, beams, filename);
fclose(fp);
*num_beams = beams;
*num_weights_per_beam = weights;
*beam_ids = ids;
return table;
}
void RCconfig_nr_macrlc(configmodule_interface_t *cfg) void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
{ {
int j = 0; int j = 0;
...@@ -1620,6 +1714,16 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) ...@@ -1620,6 +1714,16 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
for (int b = 0; b < n; b++) for (int b = 0; b < n; b++)
config.bw_list[b] = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].iptr[b]; config.bw_list[b] = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].iptr[b];
} }
config.bt.num_beams = 0;
config.bt.num_weights_per_beam = 0;
config.bt.beam_ids = NULL;
config.bt.beam_weights = NULL;
char **fptr = MacRLC_ParamList.paramarray[j][MACRLC_DBT_FILE_IDX].strptr;
if (fptr && *fptr && **fptr != '\0') {
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);
}
// triggers also PHY initialization in case we have L1 via FAPI // triggers also PHY initialization in case we have L1 via FAPI
nr_mac_config_scc(RC.nrmac[j], scc, &config); nr_mac_config_scc(RC.nrmac[j], scc, &config);
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++) } // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
*/ */
#include <complex.h> #include <complex.h>
#include <limits.h>
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
...@@ -64,6 +65,41 @@ c16_t convert_precoder_weight(double complex c_in) ...@@ -64,6 +65,41 @@ c16_t convert_precoder_weight(double complex c_in)
return (c16_t) {.r = round(SHRT_MAX*creal(c_in)), .i = round(SHRT_MAX*cimag(c_in))}; return (c16_t) {.r = round(SHRT_MAX*creal(c_in)), .i = round(SHRT_MAX*cimag(c_in))};
} }
static void free_dbt_config(nfapi_nr_dbt_pdu_t *dbt)
{
if (!dbt || !dbt->dig_beam_list)
return;
for (int i = 0; i < dbt->num_dig_beams; ++i)
free(dbt->dig_beam_list[i].txru_list);
free(dbt->dig_beam_list);
dbt->dig_beam_list = NULL;
dbt->num_dig_beams = 0;
dbt->num_txrus = 0;
}
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);
for (int b = 0; b < bt->num_beams; ++b) {
uint16_t beam_id = bt->beam_ids ? bt->beam_ids[b] : b;
const int max_line = 2048;
char line[max_line];
int off = snprintf(line, sizeof(line), "DBT beam[%d] id=%u:", b, beam_id);
for (int w = 0; w < bt->num_weights_per_beam && off > -1 && off < max_line - 1; ++w)
off += snprintf(line + off,
sizeof(line) - off,
" w[%d]=(%0.6f,%0.6f)",
w,
creal(bt->beam_weights[b][w]),
cimag(bt->beam_weights[b][w]));
LOG_I(NR_MAC, "%s\n", line);
}
}
void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers) void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers)
{ {
// num of allowed k1 and k2 according to 5.2.2.2.1-3 and -4 in 38.214 // num of allowed k1 and k2 according to 5.2.2.2.1-3 and -4 in 38.214
...@@ -395,6 +431,45 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR ...@@ -395,6 +431,45 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR
{ {
nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0]; nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
nrmac->common_channels[0].ServingCellConfigCommon = scc; nrmac->common_channels[0].ServingCellConfigCommon = scc;
free_dbt_config(&cfg->dbt_config);
if (config->bt.num_beams > 0) {
AssertFatal(config->bt.beam_weights != NULL,
"DBT config invalid: num_beams=%d but beam_weights is NULL\n",
config->bt.num_beams);
AssertFatal(config->bt.num_weights_per_beam > 0,
"DBT config invalid: num_weights_per_beam=%d\n",
config->bt.num_weights_per_beam);
AssertFatal(config->bt.num_weights_per_beam <= UINT16_MAX,
"DBT num_weights_per_beam %d exceeds uint16 max\n",
config->bt.num_weights_per_beam);
AssertFatal(config->bt.num_beams <= UINT16_MAX,
"DBT num_beams %d exceeds uint16 max\n",
config->bt.num_beams);
cfg->dbt_config.num_dig_beams = (uint16_t)config->bt.num_beams;
cfg->dbt_config.num_txrus = (uint16_t)config->bt.num_weights_per_beam;
cfg->dbt_config.dig_beam_list = calloc_or_fail(cfg->dbt_config.num_dig_beams, sizeof(*cfg->dbt_config.dig_beam_list));
for (uint16_t b = 0; b < cfg->dbt_config.num_dig_beams; ++b) {
nfapi_nr_dig_beam_t *beam = &cfg->dbt_config.dig_beam_list[b];
beam->beam_idx = config->bt.beam_ids ? config->bt.beam_ids[b] : b;
beam->txru_list = calloc_or_fail(cfg->dbt_config.num_txrus, sizeof(*beam->txru_list));
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);
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;
}
}
LOG_I(NR_MAC,
"Loaded DBT: num_beams=%d num_weights_per_beam=%d\n",
config->bt.num_beams,
config->bt.num_weights_per_beam);
log_dbt_table(&config->bt);
}
// Carrier configuration // Carrier configuration
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <complex.h>
#include <pthread.h> #include <pthread.h>
#include "common/utils/ds/seq_arr.h" #include "common/utils/ds/seq_arr.h"
#include "common/utils/nr/nr_common.h" #include "common/utils/nr/nr_common.h"
...@@ -184,6 +185,13 @@ typedef enum { ...@@ -184,6 +185,13 @@ typedef enum {
SSB_SINR, SSB_SINR,
} nr_config_report_type_t; } nr_config_report_type_t;
typedef struct nr_beam_table {
int num_weights_per_beam;
int num_beams;
uint16_t *beam_ids;
double complex **beam_weights;
} nr_beam_table_t;
typedef struct nr_mac_config_s { typedef struct nr_mac_config_s {
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts; nr_pdsch_AntennaPorts_t pdsch_AntennaPorts;
int pusch_AntennaPorts; int pusch_AntennaPorts;
...@@ -213,6 +221,7 @@ typedef struct nr_mac_config_s { ...@@ -213,6 +221,7 @@ typedef struct nr_mac_config_s {
nr_redcap_config_t *redcap; nr_redcap_config_t *redcap;
nr_ptrs_config_t *ptrs; nr_ptrs_config_t *ptrs;
nr_config_report_type_t report_type; nr_config_report_type_t report_type;
nr_beam_table_t bt;
} nr_mac_config_t; } nr_mac_config_t;
typedef struct NR_preamble_ue { typedef struct NR_preamble_ue {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment