mirror of https://github.com/pvnis/srsRAN_4G.git
created class that implements the scheduler transmit power control and PHR handling
parent
788ed5ce70
commit
5865df39d1
@ -0,0 +1,134 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_ACCUMULATORS_H
|
||||
#define SRSLTE_ACCUMULATORS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace srslte {
|
||||
|
||||
template <typename T>
|
||||
struct rolling_average {
|
||||
void push(T sample)
|
||||
{
|
||||
avg_ += (sample - avg_) / (count_ + 1);
|
||||
++count_;
|
||||
}
|
||||
T value() const { return count_ == 0 ? 0 : avg_; }
|
||||
uint32_t count() const { return count_; }
|
||||
|
||||
private:
|
||||
T avg_ = 0;
|
||||
uint32_t count_ = 0;
|
||||
};
|
||||
|
||||
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) {}
|
||||
void push(T sample)
|
||||
{
|
||||
if (nof_left-- > 0) {
|
||||
avg_ += (sample - avg_) / (count + 1);
|
||||
count++;
|
||||
} else {
|
||||
avg_ = (1 - alpha) * avg_ + alpha * sample;
|
||||
}
|
||||
}
|
||||
T value() const { return count == 0 ? 0 : avg_; }
|
||||
|
||||
private:
|
||||
T avg_ = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t nof_left;
|
||||
T alpha;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct sliding_window {
|
||||
sliding_window(uint32_t N, T val) : window(N, val) {}
|
||||
void push(T sample)
|
||||
{
|
||||
window[next_idx++] = sample;
|
||||
if (next_idx >= window.size()) {
|
||||
next_idx -= window.size();
|
||||
}
|
||||
}
|
||||
size_t size() const { return window.size(); }
|
||||
T& operator[](size_t i) { return window[i]; }
|
||||
const T& operator[](size_t i) const { return window[i]; }
|
||||
std::vector<T> window;
|
||||
size_t next_idx = 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
struct sliding_sum {
|
||||
sliding_sum(uint32_t N) : window(N, 0) {}
|
||||
|
||||
void push(T sample) { window.push(sample); }
|
||||
T value() const
|
||||
{
|
||||
T ret = 0;
|
||||
for (size_t i = 0; i < window.size(); ++i) {
|
||||
ret += window[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
size_t size() const { return window.size(); }
|
||||
|
||||
private:
|
||||
detail::sliding_window<T> window;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct sliding_average {
|
||||
sliding_average(uint32_t N) : window(N, 0) {}
|
||||
void push(T sample) { window.push(sample); }
|
||||
T value() const { return window.value() / window.size(); }
|
||||
|
||||
private:
|
||||
sliding_sum<T> window;
|
||||
};
|
||||
|
||||
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)
|
||||
{}
|
||||
void push(T sample) { window.push(sample); }
|
||||
void push_hole() { window.push(null_value_); }
|
||||
T value() const
|
||||
{
|
||||
T ret = 0;
|
||||
for (size_t i = 0; i < window.size(); ++i) {
|
||||
if (window[i] != null_value_) {
|
||||
ret += window[i];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
T null_value() const { return null_value_; }
|
||||
|
||||
private:
|
||||
T null_value_;
|
||||
detail::sliding_window<T> window;
|
||||
};
|
||||
|
||||
} // namespace srslte
|
||||
|
||||
#endif // SRSLTE_ACCUMULATORS_H
|
@ -0,0 +1,123 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2020 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_TPC_H
|
||||
#define SRSLTE_TPC_H
|
||||
|
||||
#include "srslte/adt/accumulators.h"
|
||||
#include "srslte/common/common.h"
|
||||
|
||||
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
|
||||
*/
|
||||
class tpc
|
||||
{
|
||||
static constexpr size_t SNR_WINDOW_SIZE_MS = 8;
|
||||
|
||||
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)
|
||||
{
|
||||
pending_snr = snr_avg.null_value();
|
||||
}
|
||||
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_;
|
||||
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void new_tti()
|
||||
{
|
||||
if (target_snr_dB < 0) {
|
||||
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);
|
||||
pending_pusch_tpc = 0;
|
||||
pusch_tpc_values.push(pending_pucch_tpc);
|
||||
pending_pucch_tpc = 0;
|
||||
|
||||
// Enqueue pending SNR measurement
|
||||
snr_avg.push(pending_snr);
|
||||
pending_snr = snr_avg.null_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during DCI format0 encoding to set TPC command
|
||||
* @return accumulated TPC value {-3, -1, 0, 1, 3}
|
||||
*/
|
||||
int8_t encode_pusch_tpc()
|
||||
{
|
||||
if (target_snr_dB < 0) {
|
||||
return 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;
|
||||
}
|
||||
|
||||
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_pucch_tpc = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t max_ul_prbs() const { return max_prbs_cached; }
|
||||
|
||||
private:
|
||||
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 pending_pusch_tpc = 0, pending_pucch_tpc = 0;
|
||||
float pending_snr = 0;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSLTE_TPC_H
|
Loading…
Reference in New Issue