mirror of https://github.com/PentHertz/srsLTE.git
add option to specify target ul sinr for UL power control to the enb rr.conf parser
This commit is contained in:
parent
5865df39d1
commit
479602ed1d
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue