Add CFR to srsue LTE UL (#3865)

lte,phy: Add CFR to srsue LTE UL

This commit adds the configuration steps needed to enable
and configure the CFR module for the srsue's uplink signal.
Parsing of the CFR manual threshold has been streamlined.
master
Joaquim Broquetas 3 years ago committed by GitHub
parent 7410182c64
commit 520128162e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -77,10 +77,6 @@ static bool enable_256qam = false;
static float output_file_snr = +INFINITY;
static bool use_standard_lte_rate = false;
// CFR type test args
static char cfr_manual_str[] = "manual";
static char cfr_auto_cma_str[] = "auto_cma";
static char cfr_auto_ema_str[] = "auto_ema";
// CFR runtime control flags
static bool cfr_thr_inc = false;
@ -96,7 +92,7 @@ typedef struct {
} cfr_args_t;
static cfr_args_t cfr_args = {.enable = 0,
.mode = cfr_manual_str,
.mode = "manual",
.manual_thres = 1.0f,
.strength = 1.0f,
.auto_target_papr = 8.0f,
@ -292,14 +288,9 @@ static int parse_cfr_args()
cfr_config.alpha = cfr_args.strength;
cfr_config.ema_alpha = cfr_args.ema_alpha;
if (!strcmp(cfr_args.mode, cfr_manual_str)) {
cfr_config.cfr_mode = SRSRAN_CFR_THR_MANUAL;
} else if (!strcmp(cfr_args.mode, cfr_auto_cma_str)) {
cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_CMA;
} else if (!strcmp(cfr_args.mode, cfr_auto_ema_str)) {
cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_EMA;
} else {
ERROR("CFR mode is not recognised");
cfr_config.cfr_mode = srsran_cfr_str2mode(cfr_args.mode);
if (cfr_config.cfr_mode == SRSRAN_CFR_THR_INVALID) {
ERROR("CFR mode not recognised");
return SRSRAN_ERROR;
}

@ -26,6 +26,15 @@
namespace srsue {
struct cfr_args_t {
bool enable = false;
srsran_cfr_mode_t mode = SRSRAN_CFR_THR_MANUAL;
float manual_thres = 2.0f;
float strength = 1.0f;
float auto_target_papr = 7.0f;
float ema_alpha = 1.0f / (float)SRSRAN_CP_NORM_NSYMB;
};
struct phy_args_t {
std::string type = "lte";
srsran::phy_log_args_t log;
@ -96,6 +105,8 @@ struct phy_args_t {
srsran::channel::args_t dl_channel_args;
srsran::channel::args_t ul_channel_args;
cfr_args_t cfr_args; ///< Stores user-defined CFR configuration
};
/* RAT agnostic Interface MAC -> PHY */

@ -20,12 +20,14 @@
#define CFR_EMA_INIT_AVG_PWR 0.1
/**
* @brief CFR manual threshold or PAPR limiting with Moving Average or EMA power averaging
* @brief CFR manual threshold or PAPR limiting with CMA or EMA power averaging
*/
typedef enum SRSRAN_API {
SRSRAN_CFR_THR_MANUAL = 1,
SRSRAN_CFR_THR_AUTO_CMA = 2,
SRSRAN_CFR_THR_AUTO_EMA = 3
SRSRAN_CFR_THR_INVALID,
SRSRAN_CFR_THR_MANUAL,
SRSRAN_CFR_THR_AUTO_CMA,
SRSRAN_CFR_THR_AUTO_EMA,
SRSRAN_CFR_NOF_MODES
} srsran_cfr_mode_t;
/**
@ -115,4 +117,14 @@ SRSRAN_API int srsran_cfr_set_threshold(srsran_cfr_t* q, float thres);
*/
SRSRAN_API int srsran_cfr_set_papr(srsran_cfr_t* q, float papr);
/**
* @brief Converts a string representing a CFR mode from the config files into srsran_cfr_mode_t type
*
* @param[in] mode_str the cfr.mode string coming from the config file
* @return SRSRAN_CFR_THR_INVALID if mode_str is empty,
* SRSRAN_CFR_THR_INVALID if mode_str is not recognised,
* otherwise it returns the corresponding srsran_cfr_mode_t value.
*/
SRSRAN_API srsran_cfr_mode_t srsran_cfr_str2mode(const char* mode_str);
#endif // SRSRAN_CFR_H

@ -99,6 +99,8 @@ typedef struct SRSRAN_API {
srsran_ra_ul_pusch_hopping_t hopping;
srsran_cfr_cfg_t cfr_config;
cf_t* out_buffer;
cf_t* refsignal;
cf_t* srs_signal;
@ -112,6 +114,8 @@ SRSRAN_API void srsran_ue_ul_free(srsran_ue_ul_t* q);
SRSRAN_API int srsran_ue_ul_set_cell(srsran_ue_ul_t* q, srsran_cell_t cell);
SRSRAN_API int srsran_ue_ul_set_cfr(srsran_ue_ul_t* q, const srsran_cfr_cfg_t* cfr);
SRSRAN_API int srsran_ue_ul_pregen_signals(srsran_ue_ul_t* q, srsran_ue_ul_cfg_t* cfg);
SRSRAN_API int srsran_ue_ul_dci_to_pusch_grant(srsran_ue_ul_t* q,

@ -153,6 +153,10 @@ int srsran_cfr_init(srsran_cfr_t* q, srsran_cfr_cfg_t* cfg)
ERROR("Error, invalid configuration");
goto clean_exit;
}
if (cfg->cfr_mode == SRSRAN_CFR_THR_INVALID) {
ERROR("Error, invalid CFR mode");
goto clean_exit;
}
if (cfg->cfr_mode == SRSRAN_CFR_THR_MANUAL && cfg->manual_thr <= 0) {
ERROR("Error, invalid configuration for manual threshold");
goto clean_exit;
@ -321,6 +325,9 @@ bool srsran_cfr_params_valid(srsran_cfr_cfg_t* cfr_conf)
if (cfr_conf == NULL) {
return false;
}
if (cfr_conf->cfr_mode == SRSRAN_CFR_THR_INVALID) {
return false;
}
if (cfr_conf->alpha < 0 || cfr_conf->alpha > 1) {
return false;
}
@ -365,3 +372,22 @@ int srsran_cfr_set_papr(srsran_cfr_t* q, float papr)
q->max_papr_lin = srsran_convert_dB_to_power(q->cfg.max_papr_db);
return SRSRAN_SUCCESS;
}
srsran_cfr_mode_t srsran_cfr_str2mode(const char* mode_str)
{
srsran_cfr_mode_t ret;
if (strcmp(mode_str, "")) {
if (!strcmp(mode_str, "manual")) {
ret = SRSRAN_CFR_THR_MANUAL;
} else if (!strcmp(mode_str, "auto_cma")) {
ret = SRSRAN_CFR_THR_AUTO_CMA;
} else if (!strcmp(mode_str, "auto_ema")) {
ret = SRSRAN_CFR_THR_AUTO_EMA;
} else {
ret = SRSRAN_CFR_THR_INVALID; // mode_str is not recognised
}
} else {
ret = SRSRAN_CFR_THR_INVALID; // mode_str is empty
}
return ret;
}

@ -21,13 +21,9 @@
#define MAX_ACPR_DB -100
// CFR type test args
static char cfr_manual_str[] = "manual";
static char cfr_auto_cma_str[] = "auto_cma";
static char cfr_auto_ema_str[] = "auto_ema";
// Default CFR type
static char* cfr_type_arg = cfr_manual_str;
static char* cfr_mode_str = "manual";
static int nof_prb = -1;
static srsran_cp_t cp = SRSRAN_CP_NORM;
@ -60,7 +56,7 @@ static void usage(char* prog)
printf("\t-e extended cyclic prefix [Default Normal]\n");
printf("\t-f Number of frames [Default %d]\n", nof_frames);
printf("\t-r Number of repetitions [Default %d]\n", nof_repetitions);
printf("\t-m CFR mode: %s, %s, %s [Default %s]\n", cfr_manual_str, cfr_auto_cma_str, cfr_auto_ema_str, cfr_type_arg);
printf("\t-m CFR mode: manual, auto_cma, auto_ema [Default %s]\n", cfr_mode_str);
printf("\t-d Use DC subcarrier: [Default DC empty]\n");
printf("\t-a CFR alpha: [Default %.2f]\n", alpha);
printf("\t-t CFR manual threshold: [Default %.2f]\n", thr_manual);
@ -89,7 +85,7 @@ static int parse_args(int argc, char** argv)
nof_frames = (int)strtol(argv[optind], NULL, 10);
break;
case 'm':
cfr_type_arg = argv[optind];
cfr_mode_str = argv[optind];
break;
case 'a':
alpha = strtof(argv[optind], NULL);
@ -140,13 +136,8 @@ int main(int argc, char** argv)
goto clean_exit;
}
if (!strcmp(cfr_type_arg, cfr_manual_str)) {
cfr_mode = SRSRAN_CFR_THR_MANUAL;
} else if (!strcmp(cfr_type_arg, cfr_auto_cma_str)) {
cfr_mode = SRSRAN_CFR_THR_AUTO_CMA;
} else if (!strcmp(cfr_type_arg, cfr_auto_ema_str)) {
cfr_mode = SRSRAN_CFR_THR_AUTO_EMA;
} else {
cfr_mode = srsran_cfr_str2mode(cfr_mode_str);
if (cfr_mode == SRSRAN_CFR_THR_INVALID) {
ERROR("CFR mode is not recognised");
goto clean_exit;
}
@ -193,6 +184,11 @@ int main(int argc, char** argv)
cfr_tx_cfg.ema_alpha = ema_alpha;
cfr_tx_cfg.dc_sc = dc_empty;
if (!srsran_cfr_params_valid(&cfr_tx_cfg)) {
ERROR("Invalid CFR configuration");
goto clean_exit;
}
if (srsran_cfr_init(&cfr, &cfr_tx_cfg)) {
ERROR("Error initializing CFR");
goto clean_exit;

@ -702,7 +702,8 @@ int srsran_ofdm_set_cfr(srsran_ofdm_t* q, srsran_cfr_cfg_t* cfr)
q->cfg.cfr_tx_cfg.symbol_sz = q->cfg.symbol_sz;
q->cfg.cfr_tx_cfg.symbol_bw = q->nof_re;
// in the DL, the DC carrier is empty but still counts when designing the filter BW
// in the LTE DL, the DC carrier is empty but still counts when designing the filter BW
// in the LTE UL, the DC carrier is used
q->cfg.cfr_tx_cfg.dc_sc = (!q->cfg.keep_dc) && (!isnormal(q->cfg.freq_shift_f));
if (q->cfg.cfr_tx_cfg.cfr_enable) {
if (srsran_cfr_init(&q->tx_cfr, &q->cfg.cfr_tx_cfg) < SRSRAN_SUCCESS) {

@ -165,6 +165,25 @@ int srsran_ue_ul_set_cell(srsran_ue_ul_t* q, srsran_cell_t cell)
return ret;
}
int srsran_ue_ul_set_cfr(srsran_ue_ul_t* q, const srsran_cfr_cfg_t* cfr)
{
if (q == NULL || cfr == NULL) {
ERROR("Error, invalid inputs");
return SRSRAN_ERROR_INVALID_INPUTS;
}
// Copy the cfr config into the UE
q->cfr_config = *cfr;
// Set the cfr for the fft's
if (srsran_ofdm_set_cfr(&q->fft, &q->cfr_config) < SRSRAN_SUCCESS) {
ERROR("Error setting the CFR for the fft");
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int srsran_ue_ul_pregen_signals(srsran_ue_ul_t* q, srsran_ue_ul_cfg_t* cfg)
{
if (q->signals_pregenerated) {

@ -378,18 +378,11 @@ void parse_args(all_args_t* args, int argc, char* argv[])
exit(1);
}
// convert CFR mode
if (!cfr_mode.empty()) {
if (cfr_mode == "manual") {
args->phy.cfr_args.mode = SRSRAN_CFR_THR_MANUAL;
} else if (cfr_mode == "auto_cma") {
args->phy.cfr_args.mode = SRSRAN_CFR_THR_AUTO_CMA;
} else if (cfr_mode == "auto_ema") {
args->phy.cfr_args.mode = SRSRAN_CFR_THR_AUTO_EMA;
} else {
cout << "Error, invalid CFR mode: " << cfr_mode << endl;
exit(1);
}
// parse the CFR mode string
args->phy.cfr_args.mode = srsran_cfr_str2mode(cfr_mode.c_str());
if (args->phy.cfr_args.mode == SRSRAN_CFR_THR_INVALID) {
cout << "Error, invalid CFR mode: " << cfr_mode << endl;
exit(1);
}
// Apply all_level to any unset layers

@ -306,6 +306,8 @@ public:
}
}
srsran_cfr_cfg_t get_cfr_config() { return cfr_config; }
private:
std::mutex meas_mutex;
@ -323,6 +325,8 @@ private:
std::array<float, SRSRAN_MAX_CARRIERS> avg_noise = {};
std::array<float, SRSRAN_MAX_CARRIERS> avg_rsrp_neigh = {};
srsran_cfr_cfg_t cfr_config = {};
static constexpr uint32_t pcell_report_period = 20;
static constexpr uint32_t update_rxgain_period = 10;

@ -59,8 +59,9 @@ string config_file;
static int parse_args(all_args_t* args, int argc, char* argv[])
{
bool use_standard_lte_rates = false;
bool use_standard_lte_rates = false;
std::string scs_khz, ssb_scs_khz; // temporary value to store integer
std::string cfr_mode;
// Command line only options
bpo::options_description general("General options");
@ -239,6 +240,14 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
("channel.ul.hst.fd_hz", bpo::value<float>(&args->phy.ul_channel_args.hst_fd_hz)->default_value(+750.0f), "Doppler frequency in Hz")
("channel.ul.hst.init_time_s", bpo::value<float>(&args->phy.ul_channel_args.hst_init_time_s)->default_value(0), "Initial time in seconds")
/* CFR section */
("cfr.enable", bpo::value<bool>(&args->phy.cfr_args.enable)->default_value(args->phy.cfr_args.enable), "CFR enable")
("cfr.mode", bpo::value<string>(&cfr_mode)->default_value("manual"), "CFR mode")
("cfr.manual_thres", bpo::value<float>(&args->phy.cfr_args.manual_thres)->default_value(args->phy.cfr_args.manual_thres), "Fixed manual clipping threshold for CFR manual mode")
("cfr.strength", bpo::value<float>(&args->phy.cfr_args.strength)->default_value(args->phy.cfr_args.strength), "CFR ratio between amplitude-limited vs original signal (0 to 1)")
("cfr.auto_target_papr", bpo::value<float>(&args->phy.cfr_args.auto_target_papr)->default_value(args->phy.cfr_args.auto_target_papr), "Signal PAPR target (in dB) in CFR auto modes")
("cfr.ema_alpha", bpo::value<float>(&args->phy.cfr_args.ema_alpha)->default_value(args->phy.cfr_args.ema_alpha), "Alpha coefficient for the power average in auto_ema mode (0 to 1)")
/* PHY section */
("phy.worker_cpu_mask",
bpo::value<int>(&args->phy.worker_cpu_mask)->default_value(-1),
@ -548,6 +557,13 @@ static int parse_args(all_args_t* args, int argc, char* argv[])
args->stack.usim.using_op = vm.count("usim.op");
}
// parse the CFR mode string
args->phy.cfr_args.mode = srsran_cfr_str2mode(cfr_mode.c_str());
if (args->phy.cfr_args.mode == SRSRAN_CFR_THR_INVALID) {
cout << "Error, invalid CFR mode: " << cfr_mode << endl;
exit(1);
}
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if (!vm.count("log.rf_level")) {

@ -47,6 +47,8 @@ cc_worker::cc_worker(uint32_t cc_idx_, uint32_t max_prb, srsue::phy_common* phy_
cc_idx = cc_idx_;
phy = phy_;
srsran_cfr_cfg_t cfr_config = phy->get_cfr_config();
signal_buffer_max_samples = 3 * SRSRAN_SF_LEN_PRB(max_prb);
for (uint32_t i = 0; i < phy->args->nof_rx_ant; i++) {
@ -72,6 +74,11 @@ cc_worker::cc_worker(uint32_t cc_idx_, uint32_t max_prb, srsue::phy_common* phy_
return;
}
if (srsran_ue_ul_set_cfr(&ue_ul, &cfr_config) < SRSRAN_SUCCESS) {
Error("Setting the CFR");
return;
}
phy->set_ue_dl_cfg(&ue_dl_cfg);
phy->set_ue_ul_cfg(&ue_ul_cfg);
phy->set_pdsch_cfg(&ue_dl_cfg.cfg.pdsch);

@ -56,6 +56,14 @@ void phy_common::init(phy_args_t* _args,
ul_channel = srsran::channel_ptr(
new srsran::channel(args->ul_channel_args, args->nof_lte_carriers * args->nof_rx_ant, logger));
}
// Init the CFR config struct with the CFR args
cfr_config.cfr_enable = args->cfr_args.enable;
cfr_config.cfr_mode = args->cfr_args.mode;
cfr_config.alpha = args->cfr_args.strength;
cfr_config.manual_thr = args->cfr_args.manual_thres;
cfr_config.max_papr_db = args->cfr_args.auto_target_papr;
cfr_config.ema_alpha = args->cfr_args.ema_alpha;
}
void phy_common::set_ue_dl_cfg(srsran_ue_dl_cfg_t* ue_dl_cfg)

@ -284,6 +284,33 @@ int ue::parse_args(const all_args_t& args_)
args.stack.nas_5g.pdu_session_cfgs.push_back({args.stack.nas.apn_name});
}
// Validate the CFR args
srsran_cfr_cfg_t cfr_test_cfg = {};
cfr_test_cfg.cfr_enable = args.phy.cfr_args.enable;
cfr_test_cfg.cfr_mode = args.phy.cfr_args.mode;
cfr_test_cfg.alpha = args.phy.cfr_args.strength;
cfr_test_cfg.manual_thr = args.phy.cfr_args.manual_thres;
cfr_test_cfg.max_papr_db = args.phy.cfr_args.auto_target_papr;
cfr_test_cfg.ema_alpha = args.phy.cfr_args.ema_alpha;
if (!srsran_cfr_params_valid(&cfr_test_cfg)) {
srsran::console("Invalid CFR parameters: cfr_mode=%d, alpha=%.2f, manual_thr=%.2f, \n "
"max_papr_db=%.2f, ema_alpha=%.2f\n",
cfr_test_cfg.cfr_mode,
cfr_test_cfg.alpha,
cfr_test_cfg.manual_thr,
cfr_test_cfg.max_papr_db,
cfr_test_cfg.ema_alpha);
logger.error("Invalid CFR parameters: cfr_mode=%d, alpha=%.2f, manual_thr=%.2f, max_papr_db=%.2f, ema_alpha=%.2f\n",
cfr_test_cfg.cfr_mode,
cfr_test_cfg.alpha,
cfr_test_cfg.manual_thr,
cfr_test_cfg.max_papr_db,
cfr_test_cfg.ema_alpha);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}

@ -389,6 +389,33 @@ enable = false
[phy.nr]
#store_pdsch_ko = false
#####################################################################
# CFR configuration options
#
# The CFR module provides crest factor reduction for the transmitted signal.
#
# enable: Enable or disable the CFR. Default: disabled
#
# mode: manual: CFR threshold is set by cfr_manual_thres (default).
# auto_ema: CFR threshold is adaptive based on the signal PAPR. Power avg. with Exponential Moving Average.
# The time constant of the averaging can be tweaked with the ema_alpha parameter.
# auto_cma: CFR threshold is adaptive based on the signal PAPR. Power avg. with Cumulative Moving Average.
# Use with care, as CMA's increasingly slow response may be unsuitable for most use cases.
#
# strength: Ratio between amplitude-limited vs unprocessed signal (0 to 1). Default: 1
# manual_thres: Fixed manual clipping threshold for CFR manual mode. Default: 2
# auto_target_papr: Signal PAPR target (in dB) in CFR auto modes. output PAPR can be higher due to peak smoothing. Default: 7
# ema_alpha: Alpha coefficient for the power average in auto_ema mode. Default: 1/7
#
#####################################################################
[cfr]
#enable = false
#mode = manual
#manual_thres = 2.0
#strength = 1.0
#auto_target_papr = 7.0
#ema_alpha = 0.0143
#####################################################################
# Simulation configuration options
#

Loading…
Cancel
Save