Added more information in NR PHY SA cell search test

This commit is contained in:
Xavier Arteaga 2021-12-20 21:13:31 +01:00 committed by Xavier Arteaga
parent 5b744bb6c5
commit 4f86c2fac7
3 changed files with 163 additions and 63 deletions

View File

@ -64,6 +64,8 @@ public:
uint32_t ssb_periodicity_ms;
srsran_duplex_mode_t duplex_mode;
std::set<uint32_t> pci_list;
float channel_hst_fd_hz = 0.0f;
float channel_hst_period_s = 7.2f;
};
gnb_rf_emulator(const args_t& args)
@ -83,6 +85,11 @@ public:
gnb_args.ssb_periodicity_ms = args.ssb_periodicity_ms;
gnb_args.duplex_mode = args.duplex_mode;
gnb_args.channel.hst_enable = std::isnormal(args.channel_hst_fd_hz) and std::isnormal(args.channel_hst_period_s);
gnb_args.channel.hst_fd_hz = args.channel_hst_fd_hz;
gnb_args.channel.hst_period_s = args.channel_hst_period_s;
gnb_args.channel.enable = gnb_args.channel.hst_enable;
gnb_vector.emplace_back(std::make_shared<gnb_emulator>(gnb_args));
}

View File

@ -11,7 +11,6 @@
*/
#include "gnb_rf_emulator.h"
#include "srsran/asn1/rrc_nr.h"
#include "srsran/common/band_helper.h"
#include "srsran/common/crash_handler.h"
#include "srsran/common/string_helpers.h"
@ -46,8 +45,7 @@ public:
pending_tti_cvar.notify_all();
}
uint32_t count = 0;
void tick()
void tick()
{
// Wait for TTI to get processed
std::unique_lock<std::mutex> lock(pending_tti_mutex);
@ -79,7 +77,9 @@ struct args_t {
std::string stack_log_level = "warning";
// Simulation parameters
uint32_t sim_ssb_periodicity_ms = 10;
uint32_t sim_ssb_periodicity_ms = 10;
float sim_channel_hst_fd_hz = 0.0f;
float sim_channel_hst_period_s = 7.2f;
std::set<uint32_t> sim_cell_pci;
// RF parameters
@ -152,34 +152,36 @@ int parse_args(int argc, char** argv, args_t& args)
bpo::options_description simulation("Mode 2: Simulation options (enabled if simulation_cell_list is not empty)");
// clang-format off
over_the_air.add_options()
("rf.device_name", bpo::value<std::string>(&args.rf_device_name)->default_value(args.rf_device_name), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&args.rf_device_args)->default_value(args.rf_device_args), "RF Device arguments")
("rf.log_level", bpo::value<std::string>(&args.rf_log_level)->default_value(args.rf_log_level), "RF Log level (none, warning, info, debug)")
("rf.rx_gain", bpo::value<float>(&args.rf_rx_gain_dB)->default_value(args.rf_rx_gain_dB), "RF Receiver gain in dB")
("rf.freq_offset", bpo::value<float>(&args.rf_freq_offset_Hz)->default_value(args.rf_freq_offset_Hz), "RF Frequency offset")
;
over_the_air.add_options()
("rf.device_name", bpo::value<std::string>(&args.rf_device_name)->default_value(args.rf_device_name), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&args.rf_device_args)->default_value(args.rf_device_args), "RF Device arguments")
("rf.log_level", bpo::value<std::string>(&args.rf_log_level)->default_value(args.rf_log_level), "RF Log level (none, warning, info, debug)")
("rf.rx_gain", bpo::value<float>(&args.rf_rx_gain_dB)->default_value(args.rf_rx_gain_dB), "RF Receiver gain in dB")
("rf.freq_offset", bpo::value<float>(&args.rf_freq_offset_Hz)->default_value(args.rf_freq_offset_Hz), "RF Frequency offset")
;
simulation.add_options()
("sim.pci_list", bpo::value<std::string>(&simulation_cell_list)->default_value(simulation_cell_list), "Comma separated PCI cell list to simulate")
("sim.bw", bpo::value<uint32_t>(&args.base_carrier.nof_prb)->default_value(args.base_carrier.nof_prb), "Carrier bandwidth in RB")
("sim.ssb_period", bpo::value<uint32_t>(&args.sim_ssb_periodicity_ms)->default_value(args.sim_ssb_periodicity_ms), "SSB period in ms")
;
simulation.add_options()
("sim.pci_list", bpo::value<std::string>(&simulation_cell_list)->default_value(simulation_cell_list), "Comma separated PCI cell list to simulate")
("sim.bw", bpo::value<uint32_t>(&args.base_carrier.nof_prb)->default_value(args.base_carrier.nof_prb), "Carrier bandwidth in RB")
("sim.ssb_period", bpo::value<uint32_t>(&args.sim_ssb_periodicity_ms)->default_value(args.sim_ssb_periodicity_ms), "SSB period in ms")
("sim.channel.hst.fd", bpo::value<float>(&args.sim_channel_hst_fd_hz)->default_value(args.sim_channel_hst_fd_hz), "Channel emulator HST maximum frequency")
("sim.channel.hst.period", bpo::value<float>(&args.sim_channel_hst_period_s)->default_value(args.sim_channel_hst_period_s), "Channel emulator HST period")
;
phy.add_options()
("phy.srate", bpo::value<double>(&args.srate_hz)->default_value(args.srate_hz), "Sampling Rate in Hz")
("phy.log.level", bpo::value<std::string>(&args.phy_log_level)->default_value(args.phy_log_level), "Physical layer logging level")
;
phy.add_options()
("phy.srate", bpo::value<double>(&args.srate_hz)->default_value(args.srate_hz), "Sampling Rate in Hz")
("phy.log.level", bpo::value<std::string>(&args.phy_log_level)->default_value(args.phy_log_level), "Physical layer logging level")
;
stack.add_options()
("stack.log.level", bpo::value<std::string>(&args.stack_log_level)->default_value(args.stack_log_level), "Stack logging level")
;
stack.add_options()
("stack.log.level", bpo::value<std::string>(&args.stack_log_level)->default_value(args.stack_log_level), "Stack logging level")
;
options.add(over_the_air).add(simulation).add(phy).add(stack).add_options()
("help,h", "Show this message")
("duration", bpo::value<uint32_t>(&args.duration_ms)->default_value(args.duration_ms), "Duration of the test in milli-seconds")
("freq_dl", bpo::value<double>(&args.base_carrier.dl_center_frequency_hz)->default_value(args.base_carrier.dl_center_frequency_hz), "Carrier center frequency in Hz")
;
options.add(over_the_air).add(simulation).add(phy).add(stack).add_options()
("help,h", "Show this message")
("duration", bpo::value<uint32_t>(&args.duration_ms)->default_value(args.duration_ms), "Duration of the test in milli-seconds")
("freq_dl", bpo::value<double>(&args.base_carrier.dl_center_frequency_hz)->default_value(args.base_carrier.dl_center_frequency_hz), "Carrier center frequency in Hz")
;
// clang-format on
bpo::variables_map vm;
@ -223,6 +225,8 @@ public:
phy.wait_initialize();
}
bool cell_search_read_and_clear() { return stack.get_cell_search_finished(); }
bool start_cell_search(const srsue::phy_interface_stack_nr::cell_search_args_t& args)
{
return phy.start_cell_search(args);
@ -243,6 +247,8 @@ public:
// Stop PHY
phy.stop();
}
const ue_dummy_stack::metrics_t& get_metrics() const { return stack.get_metrics(); }
};
int main(int argc, char** argv)
@ -270,6 +276,8 @@ int main(int argc, char** argv)
gnb_args.ssb_scs = args.ssb_scs;
gnb_args.duplex_mode = args.duplex_mode;
gnb_args.pci_list = args.sim_cell_pci;
gnb_args.channel_hst_fd_hz = args.sim_channel_hst_fd_hz;
gnb_args.channel_hst_period_s = args.sim_channel_hst_period_s;
radio = std::make_shared<gnb_rf_emulator>(gnb_args);
} else {
@ -277,13 +285,13 @@ int main(int argc, char** argv)
srsran::rf_args_t rf_args = {};
rf_args.type = "multi";
rf_args.log_level = args.rf_log_level;
// rf_args.srate_hz = args.srate_hz;
rf_args.rx_gain = args.rf_rx_gain_dB;
rf_args.nof_carriers = 1;
rf_args.nof_antennas = 1;
rf_args.device_args = args.rf_device_args;
rf_args.device_name = args.rf_device_name;
rf_args.freq_offset = args.rf_freq_offset_Hz;
rf_args.srate_hz = args.srate_hz;
rf_args.rx_gain = args.rf_rx_gain_dB;
rf_args.nof_carriers = 1;
rf_args.nof_antennas = 1;
rf_args.device_args = args.rf_device_args;
rf_args.device_name = args.rf_device_name;
rf_args.freq_offset = args.rf_freq_offset_Hz;
// Instantiate
std::shared_ptr<srsran::radio> r = std::make_shared<srsran::radio>();
@ -362,7 +370,8 @@ int main(int argc, char** argv)
// Transition PHY to cell search
srsran_assert(ue.start_cell_search(cs_args_), "Failed cell search start");
for (uint32_t i = 0; i < args.duration_ms; i++) {
// Run slot until the PHY reported to the stack
while (not ue.cell_search_read_and_clear()) {
ue.run_tti();
}
}
@ -373,8 +382,41 @@ int main(int argc, char** argv)
// Stop Radio
radio->reset();
const ue_dummy_stack::metrics_t& metrics = ue.get_metrics();
printf("| %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s | %10s |\n",
"PCI",
"SSB",
"Count",
"RSRP min",
"RSRP avg",
"RSRP max",
"SNR min",
"SNR avg",
"SNR max",
"CFO min",
"CFO avg",
"CFO max");
for (auto& pci : metrics.cell_search) {
for (auto& ssb : pci.second) {
printf("| %10d | %10d | %10d | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | %+10.1f | "
"%+10.1f |\n",
pci.first,
ssb.first,
(uint32_t)ssb.second.count,
ssb.second.rsrp_db_min,
ssb.second.rsrp_db_avg,
ssb.second.rsrp_db_max,
ssb.second.snr_db_min,
ssb.second.snr_db_avg,
ssb.second.snr_db_max,
ssb.second.cfo_hz_min,
ssb.second.cfo_hz_avg,
ssb.second.cfo_hz_max);
}
}
// Erase radio
radio = nullptr;
return 0;
}
}

View File

@ -25,7 +25,24 @@ public:
uint32_t count;
};
struct cell_search_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 cfo_hz_avg = 0.0f;
float cfo_hz_min = +INFINITY;
float cfo_hz_max = -INFINITY;
uint32_t count = 0;
};
struct metrics_t {
std::map<uint32_t, std::map<uint32_t, cell_search_metrics_t> > cell_search;
std::map<uint32_t, prach_metrics_t> prach = {}; ///< PRACH metrics indexed with premable index
uint32_t sr_count = 0; ///< Counts number of transmitted SR
};
@ -48,6 +65,8 @@ private:
dummy_tx_harq_entity tx_harq_proc;
dummy_rx_harq_entity rx_harq_proc;
std::atomic<bool> cell_search_finished = {false};
public:
struct args_t {
uint16_t rnti = 0x1234; ///< C-RNTI for PUSCH and PDSCH transmissions
@ -134,39 +153,71 @@ public:
}
bool is_valid() const { return valid; }
metrics_t get_metrics() { return metrics; }
const metrics_t& get_metrics() const { return metrics; }
void set_phy_config_complete(bool status) override {}
bool get_cell_search_finished()
{
bool ret = cell_search_finished;
cell_search_finished = false;
return ret;
}
void cell_search_found_cell(const cell_search_result_t& result) override
{
if (result.cell_found) {
// Unpack MIB with ASN1
asn1::rrc_nr::mib_s mib_asn1;
asn1::cbit_ref cbit(result.pbch_msg.payload, SRSRAN_PBCH_MSG_NR_SZ);
mib_asn1.unpack(cbit);
// Flag as cell search is done
cell_search_finished = true;
// Convert MIB to JSON
asn1::json_writer json;
mib_asn1.to_json(json);
// Unpack MIB with C lib
srsran_mib_nr_t mib_c = {};
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
// Convert MIB from C lib to info
std::array<char, 512> mib_info = {};
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
// Convert CSI to string
std::array<char, 512> csi_info = {};
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
logger.info(
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
} else {
logger.info("Cell not found\n");
if (not result.cell_found) {
logger.info("Cell search finished without detecting any cell");
return;
}
// Pack PBCH message bits
std::array<uint8_t, SRSRAN_PBCH_MSG_NR_SZ> bit_pack_pbch_msg = {};
asn1::cbit_ref cbit(bit_pack_pbch_msg.data(), bit_pack_pbch_msg.size());
srsran_bit_pack_vector((uint8_t*)result.pbch_msg.payload, bit_pack_pbch_msg.data(), SRSRAN_PBCH_MSG_NR_SZ);
// Unpack MIB with ASN1
asn1::rrc_nr::bcch_bch_msg_s bcch;
bcch.unpack(cbit);
// Convert MIB to JSON
asn1::json_writer json;
bcch.to_json(json);
// Unpack MIB with C lib
srsran_mib_nr_t mib_c = {};
srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib_c);
// Convert MIB from C lib to info
std::array<char, 512> mib_info = {};
srsran_pbch_msg_nr_mib_info(&mib_c, mib_info.data(), (uint32_t)mib_info.size());
// Convert CSI to string
std::array<char, 512> csi_info = {};
srsran_csi_meas_info_short(&result.measurements, csi_info.data(), (uint32_t)csi_info.size());
logger.info(
"Cell found pci=%d %s %s ASN1: %s", result.pci, mib_info.data(), csi_info.data(), json.to_string().c_str());
cell_search_metrics_t& m = metrics.cell_search[result.pci][result.pbch_msg.ssb_idx];
m.epre_db_min = SRSRAN_MIN(m.epre_db_min, result.measurements.epre_dB);
m.epre_db_max = SRSRAN_MAX(m.epre_db_max, result.measurements.epre_dB);
m.epre_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.epre_dB, m.epre_db_avg, m.count);
m.rsrp_db_min = SRSRAN_MIN(m.rsrp_db_min, result.measurements.rsrp_dB);
m.rsrp_db_max = SRSRAN_MAX(m.rsrp_db_max, result.measurements.rsrp_dB);
m.rsrp_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.rsrp_dB, m.rsrp_db_avg, m.count);
m.snr_db_min = SRSRAN_MIN(m.snr_db_min, result.measurements.snr_dB);
m.snr_db_max = SRSRAN_MAX(m.snr_db_max, result.measurements.snr_dB);
m.snr_db_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.snr_dB, m.snr_db_avg, m.count);
m.cfo_hz_min = SRSRAN_MIN(m.cfo_hz_min, result.measurements.cfo_hz);
m.cfo_hz_max = SRSRAN_MAX(m.cfo_hz_max, result.measurements.cfo_hz);
m.cfo_hz_avg = SRSRAN_VEC_SAFE_CMA(result.measurements.cfo_hz, m.cfo_hz_avg, m.count);
m.count++;
}
};