mirror of https://github.com/PentHertz/srsLTE.git
Integrated SR decoder in gNb
This commit is contained in:
parent
6a9baef11d
commit
bb4f469794
|
@ -206,9 +206,11 @@ public:
|
|||
class mac_interface_phy_nr
|
||||
{
|
||||
public:
|
||||
const static int MAX_SSB = 4;
|
||||
const static int MAX_GRANTS = 64;
|
||||
const static int MAX_NZP_CSI_RS = 4;
|
||||
const static int MAX_SSB = 4;
|
||||
const static int MAX_GRANTS = 64;
|
||||
const static int MAX_PUCCH_MSG = 64;
|
||||
const static int MAX_PUCCH_CANDIDATES = 2;
|
||||
const static int MAX_NZP_CSI_RS = 4;
|
||||
|
||||
struct pdcch_dl_t {
|
||||
srsran_dci_cfg_nr_t dci_cfg = {};
|
||||
|
@ -255,8 +257,8 @@ public:
|
|||
};
|
||||
|
||||
struct pucch_t {
|
||||
srsran_pucch_nr_common_cfg_t pucch_cfg; ///< UE dedicated PUCCH configuration
|
||||
srsran::bounded_vector<pucch_candidate_t, MAX_GRANTS> candidates; ///< PUCCH candidates to decode
|
||||
srsran_pucch_nr_common_cfg_t pucch_cfg; ///< UE dedicated PUCCH configuration
|
||||
srsran::bounded_vector<pucch_candidate_t, MAX_PUCCH_CANDIDATES> candidates; ///< PUCCH candidates to decode
|
||||
};
|
||||
|
||||
struct ul_sched_t {
|
||||
|
@ -265,8 +267,8 @@ public:
|
|||
};
|
||||
|
||||
struct pucch_info_t {
|
||||
srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti
|
||||
// ... add signal measurements here
|
||||
srsran_uci_data_nr_t uci_data; ///< RNTI is available under cfg->pucch->rnti
|
||||
srsran_csi_trs_measurements_t csi; ///< DMRS based signal Channel State Information (CSI)
|
||||
};
|
||||
|
||||
struct pusch_info_t {
|
||||
|
|
|
@ -57,7 +57,8 @@ SRSRAN_API int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
|
|||
const srsran_pucch_nr_common_cfg_t* cfg,
|
||||
const srsran_pucch_nr_resource_t* resource,
|
||||
const srsran_uci_cfg_nr_t* uci_cfg,
|
||||
srsran_uci_value_nr_t* uci_value);
|
||||
srsran_uci_value_nr_t* uci_value,
|
||||
srsran_csi_trs_measurements_t* meas);
|
||||
|
||||
SRSRAN_API uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
|
||||
const srsran_pucch_nr_resource_t* resource,
|
||||
|
|
|
@ -290,7 +290,18 @@ bool phy_cfg_nr_t::get_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
|
|||
}
|
||||
|
||||
// Generate configuration for SR
|
||||
// ...
|
||||
uint32_t sr_resource_id[SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES] = {};
|
||||
int n = srsran_ue_ul_nr_sr_send_slot(pucch.sr_resources, slot_cfg.idx, sr_resource_id);
|
||||
if (n < SRSRAN_SUCCESS) {
|
||||
ERROR("Calculating SR opportunities");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
uci_cfg.pucch.sr_resource_id = sr_resource_id[0];
|
||||
uci_cfg.o_sr = srsran_ra_ul_nr_nof_sr_bits((uint32_t)n);
|
||||
uci_cfg.sr_positive_present = true;
|
||||
}
|
||||
|
||||
// Generate configuration for CSI reports
|
||||
// ...
|
||||
|
@ -324,4 +335,4 @@ bool phy_cfg_nr_t::get_pusch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
|
|||
return true;
|
||||
}
|
||||
|
||||
} // namespace srsran
|
||||
} // namespace srsran
|
||||
|
|
|
@ -210,6 +210,11 @@ static int gnb_ul_decode_pucch_format1(srsran_gnb_ul_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// As format 1 with positive SR is not encoded with any payload, set SR to 1
|
||||
if (uci_cfg->sr_positive_present) {
|
||||
uci_value->sr = 1;
|
||||
}
|
||||
|
||||
// Take valid decision
|
||||
uci_value->valid = (norm_corr > 0.5f);
|
||||
|
||||
|
@ -248,7 +253,8 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
|
|||
const srsran_pucch_nr_common_cfg_t* cfg,
|
||||
const srsran_pucch_nr_resource_t* resource,
|
||||
const srsran_uci_cfg_nr_t* uci_cfg,
|
||||
srsran_uci_value_nr_t* uci_value)
|
||||
srsran_uci_value_nr_t* uci_value,
|
||||
srsran_csi_trs_measurements_t* meas)
|
||||
{
|
||||
if (q == NULL || slot_cfg == NULL || cfg == NULL || resource == NULL || uci_cfg == NULL || uci_value == NULL) {
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
|
@ -257,17 +263,39 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
|
|||
// Estimate channel
|
||||
switch (resource->format) {
|
||||
case SRSRAN_PUCCH_NR_FORMAT_1:
|
||||
return gnb_ul_decode_pucch_format1(q, slot_cfg, cfg, resource, uci_cfg, uci_value);
|
||||
if (gnb_ul_decode_pucch_format1(q, slot_cfg, cfg, resource, uci_cfg, uci_value) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
break;
|
||||
case SRSRAN_PUCCH_NR_FORMAT_2:
|
||||
return gnb_ul_decode_pucch_format2(q, slot_cfg, cfg, resource, uci_cfg, uci_value);
|
||||
if (gnb_ul_decode_pucch_format2(q, slot_cfg, cfg, resource, uci_cfg, uci_value) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
break;
|
||||
case SRSRAN_PUCCH_NR_FORMAT_0:
|
||||
case SRSRAN_PUCCH_NR_FORMAT_3:
|
||||
case SRSRAN_PUCCH_NR_FORMAT_4:
|
||||
case SRSRAN_PUCCH_NR_FORMAT_ERROR:
|
||||
ERROR("Invalid or not implemented PUCCH-NR format %d", (int)resource->format);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
return SRSRAN_ERROR;
|
||||
// Copy DMRS measurements
|
||||
if (meas != NULL) {
|
||||
meas->rsrp = q->chest_pucch.rsrp;
|
||||
meas->rsrp_dB = q->chest_pucch.rsrp_dBfs;
|
||||
meas->epre = q->chest_pucch.epre;
|
||||
meas->epre_dB = q->chest_pucch.epre_dBfs;
|
||||
meas->n0 = q->chest_pucch.noise_estimate;
|
||||
meas->n0_dB = q->chest_pucch.noise_estimate_dbm;
|
||||
meas->snr_dB = q->chest_pucch.snr_db;
|
||||
meas->cfo_hz = q->chest_pucch.cfo_hz;
|
||||
meas->cfo_hz_max = NAN; // Unavailable
|
||||
meas->delay_us = q->chest_pucch.ta_us;
|
||||
meas->nof_re = 0; // Unavailable
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t srsran_gnb_ul_pucch_info(srsran_gnb_ul_t* q,
|
||||
|
|
|
@ -478,17 +478,21 @@ static int ra_ul_nr_pucch_resource_default(uint32_t r_pucch, srsran_pucch_nr_res
|
|||
}
|
||||
|
||||
static int ra_ul_nr_pucch_resource_hl(const srsran_pucch_nr_hl_cfg_t* cfg,
|
||||
uint32_t O_uci,
|
||||
const srsran_uci_cfg_nr_t* uci_cfg,
|
||||
uint32_t pucch_resource_id,
|
||||
srsran_pucch_nr_resource_t* resource)
|
||||
{
|
||||
uint32_t N2 = cfg->sets[1].max_payload_size > 0 ? cfg->sets[1].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS;
|
||||
uint32_t N3 = cfg->sets[2].max_payload_size > 0 ? cfg->sets[2].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS;
|
||||
uint32_t O_uci = srsran_uci_nr_total_bits(uci_cfg);
|
||||
uint32_t N2 = cfg->sets[1].max_payload_size > 0 ? cfg->sets[1].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS;
|
||||
uint32_t N3 = cfg->sets[2].max_payload_size > 0 ? cfg->sets[2].max_payload_size : SRSRAN_UCI_NR_MAX_NOF_BITS;
|
||||
|
||||
// If the UE transmits O UCI UCI information bits, that include HARQ-ACK information bits, the UE determines a PUCCH
|
||||
// resource set to be...
|
||||
uint32_t resource_set_id = 3;
|
||||
if (O_uci <= 2 && cfg->sets[0].nof_resources > 0) {
|
||||
if (uci_cfg->nof_csi == 0 && uci_cfg->ack.count <= 2) {
|
||||
// a first set of PUCCH resources with pucch-ResourceSetId = 0 if O_UCI ≤ 2 including 1 or 2 HARQ-ACK
|
||||
// information bits and a positive or negative SR on one SR transmission occasion if transmission of HARQ-ACK
|
||||
// information and SR occurs simultaneously, or
|
||||
resource_set_id = 0;
|
||||
} else if (O_uci <= N2 && cfg->sets[1].nof_resources > 0) {
|
||||
resource_set_id = 1;
|
||||
|
@ -524,8 +528,6 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
uint32_t O_uci = srsran_uci_nr_total_bits(uci_cfg);
|
||||
|
||||
// Use SR PUCCH resource
|
||||
// - At least one positive SR
|
||||
// - No HARQ-ACK
|
||||
|
@ -553,7 +555,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
// - At least one positive SR
|
||||
// - up to 2 HARQ-ACK
|
||||
// - No CSI report
|
||||
if (uci_cfg->sr_positive_present > 0 && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
|
||||
if (uci_cfg->sr_positive_present && uci_cfg->ack.count <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS &&
|
||||
uci_cfg->nof_csi == 0) {
|
||||
uint32_t sr_resource_id = uci_cfg->pucch.sr_resource_id;
|
||||
if (sr_resource_id >= SRSRAN_PUCCH_MAX_NOF_SR_RESOURCES) {
|
||||
|
@ -571,7 +573,8 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
|
||||
// Select PUCCH resource for HARQ-ACK
|
||||
srsran_pucch_nr_resource_t resource_harq = {};
|
||||
if (ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, &resource_harq) < SRSRAN_SUCCESS) {
|
||||
if (ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, &resource_harq) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error selecting HARQ-ACK resource");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
|
@ -595,6 +598,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
}
|
||||
|
||||
// The impossible happened...
|
||||
ERROR("The impossible happened...");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
|
@ -603,7 +607,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
// - More than 2 HARQ-ACK
|
||||
// - No CSI report
|
||||
if (uci_cfg->o_sr > 0 && uci_cfg->ack.count > SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) {
|
||||
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource);
|
||||
return ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, resource);
|
||||
}
|
||||
|
||||
// Use format 2, 3 or 4 CSI report resource from higher layers
|
||||
|
@ -622,7 +626,7 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
uint32_t r_pucch = (2 * uci_cfg->pucch.n_cce_0) + 2 * uci_cfg->pucch.resource_id;
|
||||
return ra_ul_nr_pucch_resource_default(r_pucch, resource);
|
||||
}
|
||||
return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch.resource_id, resource);
|
||||
return ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, resource);
|
||||
}
|
||||
|
||||
uint32_t srsran_ra_ul_nr_nof_sr_bits(uint32_t K)
|
||||
|
|
|
@ -148,22 +148,37 @@ bool slot_worker::work_ul()
|
|||
|
||||
// For each PUCCH...
|
||||
for (stack_interface_phy_nr::pucch_t& pucch : ul_sched.pucch) {
|
||||
stack_interface_phy_nr::pucch_info_t pucch_info = {};
|
||||
pucch_info.uci_data.cfg = pucch.candidates[0].uci_cfg;
|
||||
srsran::bounded_vector<stack_interface_phy_nr::pucch_info_t, stack_interface_phy_nr::MAX_PUCCH_CANDIDATES>
|
||||
pucch_info(pucch.candidates.size());
|
||||
|
||||
// Decode PUCCH
|
||||
if (srsran_gnb_ul_get_pucch(&gnb_ul,
|
||||
&ul_slot_cfg,
|
||||
&pucch.pucch_cfg,
|
||||
&pucch.candidates[0].resource,
|
||||
&pucch_info.uci_data.cfg,
|
||||
&pucch_info.uci_data.value) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error getting PUCCH");
|
||||
return false;
|
||||
// For each candidate decode PUCCH
|
||||
for (uint32_t i = 0; i < (uint32_t)pucch.candidates.size(); i++) {
|
||||
pucch_info[i].uci_data.cfg = pucch.candidates[i].uci_cfg;
|
||||
|
||||
// Decode PUCCH
|
||||
if (srsran_gnb_ul_get_pucch(&gnb_ul,
|
||||
&ul_slot_cfg,
|
||||
&pucch.pucch_cfg,
|
||||
&pucch.candidates[i].resource,
|
||||
&pucch_info[i].uci_data.cfg,
|
||||
&pucch_info[i].uci_data.value,
|
||||
&pucch_info[i].csi) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error getting PUCCH");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find most suitable PUCCH candidate
|
||||
uint32_t best_candidate = 0;
|
||||
for (uint32_t i = 1; i < (uint32_t)pucch_info.size(); i++) {
|
||||
// Select candidate if exceeds the previous best candidate SNR
|
||||
if (pucch_info[i].csi.snr_dB > pucch_info[best_candidate].csi.snr_dB) {
|
||||
best_candidate = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform stack
|
||||
if (stack.pucch_info(ul_slot_cfg, pucch_info) < SRSRAN_SUCCESS) {
|
||||
if (stack.pucch_info(ul_slot_cfg, pucch_info[best_candidate]) < SRSRAN_SUCCESS) {
|
||||
logger.error("Error pushing PUCCH information to stack");
|
||||
return false;
|
||||
}
|
||||
|
@ -171,8 +186,11 @@ bool slot_worker::work_ul()
|
|||
// Log PUCCH decoding
|
||||
if (logger.info.enabled()) {
|
||||
std::array<char, 512> str;
|
||||
srsran_gnb_ul_pucch_info(
|
||||
&gnb_ul, &pucch.candidates[0].resource, &pucch_info.uci_data, str.data(), (uint32_t)str.size());
|
||||
srsran_gnb_ul_pucch_info(&gnb_ul,
|
||||
&pucch.candidates[0].resource,
|
||||
&pucch_info[best_candidate].uci_data,
|
||||
str.data(),
|
||||
(uint32_t)str.size());
|
||||
|
||||
logger.info("PUCCH: %s", str.data());
|
||||
}
|
||||
|
|
|
@ -322,9 +322,28 @@ bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, d
|
|||
// Put UCI configuration in PUCCH config
|
||||
ul_res.pucch.emplace_back();
|
||||
pucch_t& pucch = ul_res.pucch.back();
|
||||
pucch.uci_cfg = uci_cfg;
|
||||
bool ret = phy_cfg->get_pucch_uci_cfg(slot_cfg, pucch.uci_cfg, pucch.pucch_cfg, pucch.resource);
|
||||
srsran_assert(ret, "Error getting PUCCH UCI cfg");
|
||||
pucch.candidates.emplace_back();
|
||||
pucch.candidates.back().uci_cfg = uci_cfg;
|
||||
srsran_assert(phy_cfg->get_pucch_uci_cfg(
|
||||
slot_cfg, pucch.candidates.back().uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource),
|
||||
"Error getting PUCCH UCI cfg");
|
||||
|
||||
// If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR.
|
||||
if (uci_cfg.sr_positive_present and uci_cfg.ack.count > 0 and
|
||||
pucch.candidates.back().resource.format == SRSRAN_PUCCH_NR_FORMAT_1) {
|
||||
// Set SR negative
|
||||
if (uci_cfg.o_sr > 0) {
|
||||
uci_cfg.sr_positive_present = false;
|
||||
}
|
||||
|
||||
// Append new resource
|
||||
pucch.candidates.emplace_back();
|
||||
pucch.candidates.back().uci_cfg = uci_cfg;
|
||||
srsran_assert(
|
||||
phy_cfg->get_pucch_uci_cfg(
|
||||
slot_cfg, pucch.candidates.back().uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource),
|
||||
"Error getting PUCCH UCI cfg");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,4 +355,4 @@ bool sched_worker_manager::save_sched_result(tti_point pdcch_tti, uint32_t cc, d
|
|||
}
|
||||
|
||||
} // namespace sched_nr_impl
|
||||
} // namespace srsenb
|
||||
} // namespace srsenb
|
||||
|
|
|
@ -110,7 +110,7 @@ void sf_worker::work_imp()
|
|||
|
||||
// Perform UL processing
|
||||
for (auto& w : cc_workers) {
|
||||
w->work_ul();
|
||||
w.get()->work_ul();
|
||||
}
|
||||
|
||||
// Set Tx buffers
|
||||
|
|
|
@ -27,14 +27,17 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB)
|
|||
add_nr_test(nr_phy_test_10MHz_dl_only nr_phy_test
|
||||
--duration=100
|
||||
--gnb.stack.pdsch.slots=\"0,1,2,3,4,5\"
|
||||
--gnb.stack.pusch.slots=\"\"
|
||||
--gnb.stack.pdsch.start=0 # Start at RB 0
|
||||
--gnb.stack.pdsch.length=52 # Full 10 MHz BW
|
||||
--gnb.stack.pdsch.mcs=28 # Maximum MCS
|
||||
--gnb.stack.pusch.slots=none
|
||||
--gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS}
|
||||
--ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS}
|
||||
)
|
||||
|
||||
add_nr_test(nr_phy_test_10MHz_ul_only nr_phy_test
|
||||
--duration=100 # 100 slots
|
||||
--gnb.stack.pdsch.slots=6 # No PDSCH
|
||||
--gnb.stack.pdsch.slots=none
|
||||
--gnb.stack.pusch.slots=6,7,8,9 # All possible UL slots
|
||||
--gnb.stack.pusch.start=0 # Start at RB 0
|
||||
--gnb.stack.pusch.length=52 # Full 10 MHz BW
|
||||
|
@ -59,11 +62,32 @@ if (RF_FOUND AND ENABLE_SRSUE AND ENABLE_SRSENB)
|
|||
|
||||
add_nr_test(nr_phy_test_10MHz_prach nr_phy_test
|
||||
--duration=1000 # 100 slots
|
||||
--gnb.stack.pdsch.slots=6 # No PDSCH
|
||||
--gnb.stack.pusch.slots=0 # No PUSCH
|
||||
--gnb.stack.pdsch.slots=none # No PDSCH
|
||||
--gnb.stack.pusch.slots=none # No PUSCH
|
||||
--gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS}
|
||||
--ue.stack.prach.period=30 # Transmit PRACH every 30 radio frames
|
||||
--ue.stack.prach.preamble=10 # Use preamble 10
|
||||
--ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS}
|
||||
)
|
||||
|
||||
add_nr_test(nr_phy_test_10MHz_sr nr_phy_test
|
||||
--duration=1000 # 100 slots
|
||||
--gnb.stack.pdsch.slots=none # No PDSCH
|
||||
--gnb.stack.pusch.slots=none # No PUSCH
|
||||
--gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS}
|
||||
--ue.stack.sr.period=1 # Transmit SR every candidate
|
||||
--ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS}
|
||||
)
|
||||
|
||||
add_nr_test(nr_phy_test_10MHz_dl_sr nr_phy_test
|
||||
--duration=100
|
||||
--gnb.stack.pdsch.slots=\"0,1,2,3,4,5\"
|
||||
--gnb.stack.pdsch.start=0 # Start at RB 0
|
||||
--gnb.stack.pdsch.length=2 # Full 10 MHz BW
|
||||
--gnb.stack.pdsch.mcs=1 # Minimum MCS
|
||||
--gnb.stack.pusch.slots=none
|
||||
--gnb.phy.nof_threads=${NR_PHY_TEST_GNB_NOF_THREADS}
|
||||
--ue.stack.sr.period=1 # Transmit SR every candidate
|
||||
--ue.phy.nof_threads=${NR_PHY_TEST_UE_NOF_THREADS}
|
||||
)
|
||||
endif ()
|
||||
|
|
|
@ -33,10 +33,27 @@ public:
|
|||
uint32_t count;
|
||||
float avg_ta;
|
||||
};
|
||||
struct pucch_metrics_t {
|
||||
float epre_db_avg = 0.0f;
|
||||
float epre_db_min = +INFINITY;
|
||||
float epre_db_max = -INFINITY;
|
||||
float rsrp_db_avg = 0.0f;
|
||||
float rsrp_db_min = +INFINITY;
|
||||
float rsrp_db_max = -INFINITY;
|
||||
float snr_db_avg = 0.0f;
|
||||
float snr_db_min = +INFINITY;
|
||||
float snr_db_max = -INFINITY;
|
||||
float ta_us_avg = 0.0f;
|
||||
float ta_us_min = +INFINITY;
|
||||
float ta_us_max = -INFINITY;
|
||||
uint32_t count = 0;
|
||||
};
|
||||
|
||||
struct metrics_t {
|
||||
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
||||
srsenb::mac_ue_metrics_t mac = {}; ///< MAC metrics
|
||||
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
||||
srsenb::mac_ue_metrics_t mac = {}; ///< MAC metrics
|
||||
uint32_t sr_count = 0; ///< SR counter
|
||||
pucch_metrics_t pucch = {};
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -44,10 +61,10 @@ private:
|
|||
bool use_dummy_sched = true;
|
||||
const uint16_t rnti = 0x1234;
|
||||
struct {
|
||||
srsran::circular_array<srsran_dci_location_t, SRSRAN_NOF_SF_X_FRAME> dci_location;
|
||||
uint32_t mcs;
|
||||
uint32_t freq_res = 0;
|
||||
std::set<uint32_t> slots;
|
||||
srsran::circular_array<srsran_dci_location_t, SRSRAN_NOF_SF_X_FRAME> dci_location = {};
|
||||
uint32_t mcs = 0;
|
||||
uint32_t freq_res = 0;
|
||||
std::set<uint32_t> slots = {};
|
||||
} dl, ul;
|
||||
srsran::circular_array<uint32_t, SRSRAN_NOF_SF_X_FRAME> dl_data_to_ul_ack;
|
||||
uint32_t ss_id = 0;
|
||||
|
@ -259,6 +276,7 @@ private:
|
|||
{
|
||||
std::unique_lock<std::mutex> lock(metrics_mutex);
|
||||
|
||||
// Process HARQ-ACK
|
||||
for (uint32_t i = 0; i < cfg.ack.count; i++) {
|
||||
const srsran_harq_ack_bit_t* ack_bit = &cfg.ack.bits[i];
|
||||
bool is_ok = (value.ack[i] == 1) and value.valid;
|
||||
|
@ -271,6 +289,11 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// Process SR
|
||||
if (value.valid and value.sr > 0) {
|
||||
metrics.sr_count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -314,8 +337,12 @@ public:
|
|||
dl.mcs = args.pdsch.mcs;
|
||||
ul.mcs = args.pusch.mcs;
|
||||
|
||||
srsran::string_parse_list(args.pdsch.slots, ',', dl.slots);
|
||||
srsran::string_parse_list(args.pusch.slots, ',', ul.slots);
|
||||
if (args.pdsch.slots != "none" and not args.pdsch.slots.empty()) {
|
||||
srsran::string_parse_list(args.pdsch.slots, ',', dl.slots);
|
||||
}
|
||||
if (args.pusch.slots != "none" and not args.pusch.slots.empty()) {
|
||||
srsran::string_parse_list(args.pusch.slots, ',', ul.slots);
|
||||
}
|
||||
|
||||
// Select DCI locations
|
||||
for (uint32_t slot = 0; slot < SRSRAN_NOF_SF_X_FRAME; slot++) {
|
||||
|
@ -474,14 +501,35 @@ public:
|
|||
|
||||
// If any UCI information is triggered, schedule PUCCH
|
||||
if (uci_cfg.ack.count > 0 || uci_cfg.nof_csi > 0 || uci_cfg.o_sr > 0) {
|
||||
mac_interface_phy_nr::pucch_t pucch = {};
|
||||
pucch.candidates[0].uci_cfg = uci_cfg;
|
||||
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates[0].resource)) {
|
||||
ul_sched.pucch.emplace_back();
|
||||
|
||||
uci_cfg.pucch.rnti = rnti;
|
||||
|
||||
mac_interface_phy_nr::pucch_t& pucch = ul_sched.pucch.back();
|
||||
pucch.candidates.emplace_back();
|
||||
pucch.candidates.back().uci_cfg = uci_cfg;
|
||||
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) {
|
||||
logger.error("Error getting UCI CFG");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
ul_sched.pucch.push_back(pucch);
|
||||
// If this slot has a SR opportunity and the selected PUCCH format is 1, consider positive SR.
|
||||
if (uci_cfg.o_sr > 0 and uci_cfg.ack.count > 0 and
|
||||
pucch.candidates.back().resource.format == SRSRAN_PUCCH_NR_FORMAT_1) {
|
||||
// Set SR negative
|
||||
if (uci_cfg.o_sr > 0) {
|
||||
uci_cfg.sr_positive_present = false;
|
||||
}
|
||||
|
||||
// Append new resource
|
||||
pucch.candidates.emplace_back();
|
||||
pucch.candidates.back().uci_cfg = uci_cfg;
|
||||
if (not phy_cfg.get_pucch_uci_cfg(slot_cfg, uci_cfg, pucch.pucch_cfg, pucch.candidates.back().resource)) {
|
||||
logger.error("Error getting UCI CFG");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -498,7 +546,19 @@ public:
|
|||
}
|
||||
|
||||
// Handle PHY metrics
|
||||
// ...
|
||||
metrics.pucch.epre_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.epre_dB, metrics.pucch.epre_db_avg, metrics.pucch.count);
|
||||
metrics.pucch.epre_db_min = SRSRAN_MIN(metrics.pucch.epre_db_min, pucch_info.csi.epre_dB);
|
||||
metrics.pucch.epre_db_max = SRSRAN_MAX(metrics.pucch.epre_db_max, pucch_info.csi.epre_dB);
|
||||
metrics.pucch.rsrp_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.rsrp_dB, metrics.pucch.rsrp_db_avg, metrics.pucch.count);
|
||||
metrics.pucch.rsrp_db_min = SRSRAN_MIN(metrics.pucch.rsrp_db_min, pucch_info.csi.rsrp_dB);
|
||||
metrics.pucch.rsrp_db_max = SRSRAN_MAX(metrics.pucch.rsrp_db_max, pucch_info.csi.rsrp_dB);
|
||||
metrics.pucch.snr_db_avg = SRSRAN_VEC_CMA(pucch_info.csi.snr_dB, metrics.pucch.snr_db_avg, metrics.pucch.count);
|
||||
metrics.pucch.snr_db_min = SRSRAN_MIN(metrics.pucch.snr_db_min, pucch_info.csi.snr_dB);
|
||||
metrics.pucch.snr_db_max = SRSRAN_MAX(metrics.pucch.snr_db_max, pucch_info.csi.snr_dB);
|
||||
metrics.pucch.ta_us_avg = SRSRAN_VEC_CMA(pucch_info.csi.delay_us, metrics.pucch.ta_us_avg, metrics.pucch.count);
|
||||
metrics.pucch.ta_us_min = SRSRAN_MIN(metrics.pucch.ta_us_min, pucch_info.csi.delay_us);
|
||||
metrics.pucch.ta_us_max = SRSRAN_MAX(metrics.pucch.ta_us_max, pucch_info.csi.delay_us);
|
||||
metrics.pucch.count++;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ public:
|
|||
};
|
||||
|
||||
struct metrics_t {
|
||||
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
||||
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
|
||||
uint32_t sr_count = 0; ///< Counts number of transmitted SR
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -95,11 +96,14 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ret = (sr_count % sr_period == 0);
|
||||
if (sr_count >= (sr_period - 1) and not ul_sch_tx) {
|
||||
metrics.sr_count++;
|
||||
sr_count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
sr_count++;
|
||||
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
bool is_valid() const { return valid; }
|
||||
|
||||
|
|
|
@ -225,14 +225,54 @@ int main(int argc, char** argv)
|
|||
TESTASSERT(metrics.ue_stack.prach.count(p.first) > 0);
|
||||
}
|
||||
srsran::console(" +------------+------------+------------+\n\n");
|
||||
}
|
||||
|
||||
// Print PUCCH
|
||||
if (metrics.gnb_stack.pucch.count > 0) {
|
||||
srsran::console("PUCCH DMRS Receiver metrics:\n");
|
||||
srsran::console(" +------------+------------+------------+------------+\n");
|
||||
srsran::console(" | %10s | %10s | %10s | %10s |\n", "Measure", "Average", "Min", "Max");
|
||||
srsran::console(" +------------+------------+------------+------------+\n");
|
||||
srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n",
|
||||
"EPRE (dB)",
|
||||
metrics.gnb_stack.pucch.epre_db_avg,
|
||||
metrics.gnb_stack.pucch.epre_db_min,
|
||||
metrics.gnb_stack.pucch.epre_db_min);
|
||||
srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n",
|
||||
"RSRP (dB)",
|
||||
metrics.gnb_stack.pucch.rsrp_db_avg,
|
||||
metrics.gnb_stack.pucch.rsrp_db_min,
|
||||
metrics.gnb_stack.pucch.rsrp_db_max);
|
||||
srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n",
|
||||
"SINR (dB)",
|
||||
metrics.gnb_stack.pucch.snr_db_avg,
|
||||
metrics.gnb_stack.pucch.snr_db_min,
|
||||
metrics.gnb_stack.pucch.snr_db_max);
|
||||
srsran::console(" | %10s | %+10.2f | %+10.2f | %+10.2f |\n",
|
||||
"TA (us)",
|
||||
metrics.gnb_stack.pucch.ta_us_avg,
|
||||
metrics.gnb_stack.pucch.ta_us_min,
|
||||
metrics.gnb_stack.pucch.ta_us_max);
|
||||
srsran::console(" +------------+------------+------------+------------+\n");
|
||||
} else {
|
||||
// In this case no PRACH should
|
||||
// In this case the gNb should not have detected any
|
||||
TESTASSERT(metrics.gnb_stack.prach.empty());
|
||||
}
|
||||
|
||||
// Print SR
|
||||
if (metrics.ue_stack.sr_count > 0) {
|
||||
srsran::console("SR:\n");
|
||||
srsran::console(" +------------+------------+\n");
|
||||
srsran::console(" | %10s | %10s |\n", "Transmit'd", "Received");
|
||||
srsran::console(" +------------+------------+\n");
|
||||
srsran::console(" | %10d | %10d |\n", metrics.ue_stack.sr_count, metrics.gnb_stack.sr_count);
|
||||
srsran::console(" +------------+------------+\n");
|
||||
}
|
||||
|
||||
// Assert metrics
|
||||
TESTASSERT(metrics.gnb_stack.mac.tx_errors == 0);
|
||||
TESTASSERT(metrics.gnb_stack.mac.rx_errors == 0);
|
||||
TESTASSERT(metrics.ue_stack.sr_count == metrics.gnb_stack.sr_count);
|
||||
|
||||
// If reached here, the test is successful
|
||||
return SRSRAN_SUCCESS;
|
||||
|
|
Loading…
Reference in New Issue