add option to specify target ul sinr for UL power control to the enb rr.conf parser

This commit is contained in:
Francisco 2020-12-02 11:13:52 +00:00 committed by Andre Puschmann
parent 5865df39d1
commit 479602ed1d
8 changed files with 91 additions and 57 deletions

View File

@ -36,10 +36,13 @@ private:
template <typename T>
struct exp_average_fast_start {
exp_average_fast_start(T alpha_, uint32_t start_size = 100) : alpha(alpha_), nof_left(start_size) {}
exp_average_fast_start(T alpha_, uint32_t start_size = 100) : alpha(alpha_), start_count_size(start_size)
{
assert(start_size > 0);
}
void push(T sample)
{
if (nof_left-- > 0) {
if (count < start_count_size) {
avg_ += (sample - avg_) / (count + 1);
count++;
} else {
@ -51,7 +54,7 @@ struct exp_average_fast_start {
private:
T avg_ = 0;
uint32_t count = 0;
uint32_t nof_left;
uint32_t start_count_size;
T alpha;
};
@ -107,25 +110,25 @@ private:
template <typename T>
struct null_sliding_average {
null_sliding_average(uint32_t N, T null_val = std::numeric_limits<T>::max()) :
null_value_(null_val), window(N, null_val)
{}
static constexpr T null_value = std::numeric_limits<T>::max();
null_sliding_average(uint32_t N) : window(N, null_value) {}
void push(T sample) { window.push(sample); }
void push_hole() { window.push(null_value_); }
void push_hole() { window.push(null_value); }
T value() const
{
T ret = 0;
T ret = 0;
uint32_t count = 0;
for (size_t i = 0; i < window.size(); ++i) {
if (window[i] != null_value_) {
if (window[i] != null_value) {
ret += window[i];
count++;
}
}
return ret;
return (count == 0) ? null_value : ret / count;
}
T null_value() const { return null_value_; }
private:
T null_value_;
detail::sliding_window<T> window;
};

View File

@ -53,6 +53,7 @@ struct cell_cfg_t {
double dl_freq_hz;
uint32_t ul_earfcn;
double ul_freq_hz;
int target_ul_sinr_db;
uint32_t initial_dl_cqi;
std::vector<scell_cfg_t> scell_list;
rrc_meas_cfg_t meas_cfg;

View File

@ -22,34 +22,33 @@ namespace srsenb {
* Class to handle TPC Commands sent to the UE.
* The TPC value sent to the UE in each DCI is a result of:
* - the difference between the target SINR and the windowed average of past UE UL SNR estimates
* - subtracted by the sum of TPC values sent in the last TX_UL_DELAY milliseconds (i.e. 8ms), which the UE hasn't yet
* applied
* - subtracted by the sum of TPC values sent since the last PHR
*/
class tpc
{
static constexpr size_t SNR_WINDOW_SIZE_MS = 8;
static constexpr int PHR_NEG_NOF_PRB = 1;
public:
tpc(float target_snr_dB_ = -1.0) :
target_snr_dB(target_snr_dB_),
pusch_tpc_values(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS),
pucch_tpc_values(FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS),
snr_avg(SNR_WINDOW_SIZE_MS)
tpc(uint32_t cell_nof_prb, float target_snr_dB_ = -1.0) :
nof_prb(cell_nof_prb), target_snr_dB(target_snr_dB_), snr_avg(SNR_WINDOW_SIZE_MS)
{
pending_snr = snr_avg.null_value();
max_prbs_cached = nof_prb;
}
void set_cfg(float target_snr_dB_) { target_snr_dB = target_snr_dB_; }
void set_snr(float snr) { pending_snr = snr; }
void set_phr(int phr_)
{
last_phr = phr_;
last_phr = phr_;
sum_pusch_tpc_values = 0;
sum_pucch_tpc_values = 0;
// compute and cache the max nof UL PRBs that avoids overflowing PHR
max_prbs_cached = 1;
for (int nof_prbs = 100; nof_prbs >= 0; --nof_prbs) {
if (last_phr >= 10 * log10(nof_prbs)) {
max_prbs_cached = last_phr;
max_prbs_cached = PHR_NEG_NOF_PRB;
for (int n = nof_prb; n >= PHR_NEG_NOF_PRB - 1; --n) {
if (last_phr >= 10 * log10(n)) {
max_prbs_cached = n;
break;
}
}
@ -61,61 +60,88 @@ public:
return;
}
// Enqueue PUSCH/PUCCH TPC sent in last TTI (zero for both Delta_PUSCH/Delta_PUCCH=0 and TPC not sent)
pusch_tpc_values.push(pending_pusch_tpc);
sum_pusch_tpc_values += pending_pusch_tpc;
pending_pusch_tpc = 0;
pusch_tpc_values.push(pending_pucch_tpc);
sum_pucch_tpc_values += pending_pucch_tpc;
pending_pucch_tpc = 0;
// Enqueue pending SNR measurement
snr_avg.push(pending_snr);
pending_snr = snr_avg.null_value();
pending_snr = snr_avg.null_value;
}
/**
* Called during DCI format0 encoding to set TPC command
* @return accumulated TPC value {-3, -1, 0, 1, 3}
* Called during DCI format0 encoding to set PUSCH TPC command
* @remark See TS 36.213 Section 5.1.1
* @return accumulated TPC value {-1, 0, 1, 3}
*/
int8_t encode_pusch_tpc()
{
if (target_snr_dB < 0) {
return 0;
pending_pusch_tpc = 0;
if (target_snr_dB <= 0) {
// undefined target SINR case. Increase Tx power, while the number of allocable PRBs remains unchanged
pending_pusch_tpc = (max_prbs_cached == nof_prb) ? 1 : (last_phr < 0 ? -1 : 0);
} else if (snr_avg.value() != snr_avg.null_value) {
// target SINR is finite and there is power headroom
float diff = target_snr_dB - snr_avg.value();
diff -= sum_pusch_tpc_values;
pending_pusch_tpc = 0;
if (diff > 1) {
pending_pusch_tpc = diff > 3 ? 3 : 1;
} else if (diff <= -1) {
pending_pusch_tpc = -1;
}
if (last_phr <= 0) {
// In case there is no headroom, forbid power increases
pending_pusch_tpc = std::min(pending_pusch_tpc, 0);
}
}
float diff = target_snr_dB - snr_avg.value();
diff -= pusch_tpc_values.value();
int8_t ret = 0;
if (diff > 1) {
ret = diff > 3 ? 3 : 1;
} else if (diff <= -1) {
ret = -1;
}
pending_pusch_tpc = ret;
return ret;
return pending_pusch_tpc;
}
/**
* Called during DCI format1/2A/A encoding to set PUCCH TPC command
* Note: For now we use the same algorithm for PUCCH and PUSCH
* @remark See TS 36.213 Section 5.1.2
* @return accumulated TPC value {-1, 0, 1, 3}
*/
int8_t encode_pucch_tpc()
{
float diff = target_snr_dB - snr_avg.value();
diff -= pucch_tpc_values.value();
int8_t ret = 0;
if (diff > 1) {
ret = diff > 3 ? 3 : 1;
} else if (diff <= -1) {
ret = -1;
pending_pusch_tpc = 0;
if (target_snr_dB <= 0) {
// undefined target SINR case. Increase Tx power, while the number of allocable PRBs remains unchanged
pending_pucch_tpc = (max_prbs_cached == nof_prb) ? 1 : (last_phr < 0 ? -1 : 0);
} else if (snr_avg.value() != snr_avg.null_value) {
// target SINR is finite and there is power headroom
float diff = target_snr_dB - snr_avg.value();
diff -= sum_pucch_tpc_values;
pending_pucch_tpc = 0;
if (diff > 1) {
pending_pucch_tpc = diff > 3 ? 3 : 1;
} else if (diff <= -1) {
pending_pucch_tpc = -1;
}
if (last_phr <= 0) {
// In case there is no headroom, forbid power increases
pending_pucch_tpc = std::min(pending_pucch_tpc, 0);
}
}
pending_pucch_tpc = ret;
return ret;
return pending_pucch_tpc;
}
uint32_t max_ul_prbs() const { return max_prbs_cached; }
private:
float target_snr_dB;
uint32_t nof_prb;
float target_snr_dB;
srslte::null_sliding_average<float> snr_avg;
srslte::sliding_sum<int> pusch_tpc_values, pucch_tpc_values;
uint32_t max_prbs_cached = 100;
int last_phr = 0;
int sum_pusch_tpc_values = 0;
int sum_pucch_tpc_values = 0;
uint32_t max_prbs_cached = 100;
int last_phr = std::numeric_limits<int>::max();
int pending_pusch_tpc = 0, pending_pucch_tpc = 0;
float pending_snr = 0;
float pending_snr = srslte::null_sliding_average<float>::null_value;
};
} // namespace srsenb

View File

@ -734,6 +734,7 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root)
cell_cfg.root_seq_idx, cellroot, "root_seq_idx", rrc_cfg->sibs[1].sib2().rr_cfg_common.prach_cfg.root_seq_idx);
parse_default_field(cell_cfg.initial_dl_cqi, cellroot, "initial_dl_cqi", 5u);
parse_default_field(cell_cfg.meas_cfg.meas_gap_period, cellroot, "meas_gap_period", 0u);
HANDLEPARSERCODE(parse_default_field(cell_cfg.target_ul_sinr_db, cellroot, "target_ul_sinr", -1));
if (cellroot.exists("ho_active") and cellroot["ho_active"]) {
HANDLEPARSERCODE(parse_meas_cell_list(&cell_cfg.meas_cfg, cellroot["meas_cell_list"]));

View File

@ -1310,7 +1310,7 @@ cc_sched_ue::cc_sched_ue(const sched_interface::ue_cfg_t& cfg_,
ue_cc_idx(ue_cc_idx_),
last_tti(current_tti),
harq_ent(SCHED_MAX_HARQ_PROC, SCHED_MAX_HARQ_PROC),
tpc_fsm(cell_cfg_.cfg.target_ul_sinr)
tpc_fsm(cell_cfg_.nof_prb(), cell_cfg_.cfg.target_ul_sinr)
{
dl_cqi_rx = false;
dl_cqi = (ue_cc_idx == 0) ? cell_params->cfg.initial_dl_cqi : 0;

View File

@ -590,6 +590,7 @@ void rrc::config_mac()
item.maxharq_msg3tx = cfg.sibs[1].sib2().rr_cfg_common.rach_cfg_common.max_harq_msg3_tx;
item.enable_64qam = cfg.sibs[1].sib2().rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.enable64_qam;
item.initial_dl_cqi = cfg.cell_list[ccidx].initial_dl_cqi;
item.target_ul_sinr = cfg.cell_list[ccidx].target_ul_sinr_db;
item.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb);
rrc_log->info("Allocating %d PRBs for PUCCH\n", item.nrb_pucch);

View File

@ -352,6 +352,7 @@ sched_sim_events rand_sim_params(uint32_t nof_ttis)
sched_sim_event_generator generator;
sim_gen.sim_args.cell_cfg = {generate_default_cell_cfg(nof_prb)};
sim_gen.sim_args.cell_cfg[0].target_ul_sinr = pick_random_uniform({10, 15, 20, -1});
sim_gen.sim_args.default_ue_sim_cfg.ue_cfg = generate_default_ue_cfg();
sim_gen.sim_args.default_ue_sim_cfg.periodic_cqi = true;
sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.maxharq_tx = std::uniform_int_distribution<>{1, 5}(srsenb::get_rand_gen());

View File

@ -48,6 +48,7 @@ inline srsenb::sched_interface::cell_cfg_t generate_default_cell_cfg(uint32_t no
cell_cfg.prach_rar_window = 3;
cell_cfg.maxharq_msg3tx = 3;
cell_cfg.initial_dl_cqi = 5;
cell_cfg.target_ul_sinr = -1;
return cell_cfg;
}