Improvements in NR cell search

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 5b31654ae2
commit 0b3f4e5de0

@ -966,7 +966,8 @@ uint32_t srsran_csi_rs_measure_info(const srsran_csi_trs_measurements_t* measure
measure->rsrp_dB, measure->rsrp_dB,
measure->epre_dB, measure->epre_dB,
measure->n0_dB, measure->n0_dB,
measure->snr_dB); measure->snr_dB,
measure->delay_us);
// Append measured CFO and the maximum CFO that can be measured // Append measured CFO and the maximum CFO that can be measured
if (isnormal(measure->cfo_hz_max)) { if (isnormal(measure->cfo_hz_max)) {

@ -212,7 +212,7 @@ void channel::run(cf_t* in[SRSRAN_MAX_CHANNELS],
// Logging // Logging
std::stringstream str; std::stringstream str;
str << "t=" << t.full_secs + t.frac_secs << "s; "; str << "Channel: t=" << t.full_secs + t.frac_secs << "s; ";
if (delay[0]) { if (delay[0]) {
str << "delay=" << delay[0]->delay_us << "us; "; str << "delay=" << delay[0]->delay_us << "us; ";
} }

@ -30,7 +30,7 @@
/** /**
* Correlation size in number of FFTs. It is desired to be power of 2 * Correlation size in number of FFTs. It is desired to be power of 2
*/ */
#define SSB_CORR_SZ 4 #define SSB_CORR_SZ 2
static int ssb_init_corr(srsran_ssb_t* q) static int ssb_init_corr(srsran_ssb_t* q)
{ {
@ -707,13 +707,23 @@ ssb_pss_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t*
srsran_dft_run_guru_c(&q->ifft_corr); srsran_dft_run_guru_c(&q->ifft_corr);
// Find maximum // Find maximum
uint32_t this_max_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window); uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
float corr = SRSRAN_CSQABS(q->tmp_time[this_max_idx]);
// Average power, skip window if value is invalid (0.0, nan or inf)
float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz);
if (!isnormal(avg_pwr_corr)) {
continue;
}
float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr;
if (corr < sqrtf(SRSRAN_PSS_NR_LEN)) {
continue;
}
// Update if the correlation is better than the current best // Update if the correlation is better than the current best
if (best_corr < corr) { if (best_corr < corr) {
best_corr = corr; best_corr = corr;
best_delay = this_max_idx + t_offset; best_delay = peak_idx + t_offset;
best_N_id_2 = N_id_2; best_N_id_2 = N_id_2;
} }
} }

@ -13,7 +13,7 @@
#define Log(level, fmt, ...) \ #define Log(level, fmt, ...) \
do { \ do { \
logger.level("INTRA-%s: " fmt, to_string(get_rat()).c_str(), ##__VA_ARGS__); \ logger.level("INTRA-%s-%d: " fmt, to_string(get_rat()).c_str(), get_earfcn(), ##__VA_ARGS__); \
} while (false) } while (false)
namespace srsue { namespace srsue {
@ -117,6 +117,8 @@ void intra_measure_base::write(uint32_t tti, cf_t* data, uint32_t nsamples)
last_measure_tti = tti; last_measure_tti = tti;
srsran_ringbuffer_reset(&ring_buffer); srsran_ringbuffer_reset(&ring_buffer);
Log(debug, "Start writing");
// Force receive state // Force receive state
write(tti, data, nsamples); write(tti, data, nsamples);
} }
@ -134,6 +136,7 @@ void intra_measure_base::write(uint32_t tti, cf_t* data, uint32_t nsamples)
} else { } else {
// As soon as there are enough samples in the buffer, transition to measure // As soon as there are enough samples in the buffer, transition to measure
if (srsran_ringbuffer_status(&ring_buffer) >= required_nbytes) { if (srsran_ringbuffer_status(&ring_buffer) >= required_nbytes) {
Log(debug, "Starting search and measurements");
state.set_state(internal_state::measure); state.set_state(internal_state::measure);
} }
} }
@ -146,8 +149,12 @@ void intra_measure_base::measure_proc()
std::set<uint32_t> cells_to_measure = {}; std::set<uint32_t> cells_to_measure = {};
// Read data from buffer and find cells in it // Read data from buffer and find cells in it
srsran_ringbuffer_read( int ret = srsran_ringbuffer_read_timed(
&ring_buffer, search_buffer.data(), (int)(context.meas_len_ms * context.sf_len * sizeof(cf_t))); &ring_buffer, search_buffer.data(), (int)(context.meas_len_ms * context.sf_len * sizeof(cf_t)), 1000);
if (ret < SRSRAN_SUCCESS) {
Log(error, "Ringbuffer read returned %d", ret);
return;
}
// Go to receive before finishing, so new samples can be enqueued before the thread finishes // Go to receive before finishing, so new samples can be enqueued before the thread finishes
if (state.get_state() == internal_state::measure) { if (state.get_state() == internal_state::measure) {

@ -16,7 +16,7 @@ namespace scell {
#define Log(level, fmt, ...) \ #define Log(level, fmt, ...) \
do { \ do { \
logger.level("INTRA-%s: " fmt, to_string(get_rat()).c_str(), ##__VA_ARGS__); \ logger.level("INTRA-%s-%d: " fmt, to_string(get_rat()).c_str(), get_earfcn(), ##__VA_ARGS__); \
} while (false) } while (false)
intra_measure_lte::intra_measure_lte(srslog::basic_logger& logger_, meas_itf& new_cell_itf_) : intra_measure_lte::intra_measure_lte(srslog::basic_logger& logger_, meas_itf& new_cell_itf_) :
@ -87,9 +87,8 @@ void intra_measure_lte::measure_rat(const measure_context_t& context, std::vecto
neighbour_cells.push_back(m); neighbour_cells.push_back(m);
Log(info, Log(info,
"Found neighbour cell: EARFCN=%d, PCI=%03d, RSRP=%5.1f dBm, RSRQ=%5.1f, peak_idx=%5d, " "Found neighbour cell: PCI=%03d, RSRP=%5.1f dBm, RSRQ=%5.1f, peak_idx=%5d, "
"CFO=%+.1fHz", "CFO=%+.1fHz",
m.earfcn,
m.pci, m.pci,
m.rsrp, m.rsrp,
m.rsrq, m.rsrq,

@ -13,7 +13,7 @@
#define Log(level, fmt, ...) \ #define Log(level, fmt, ...) \
do { \ do { \
logger.level("INTRA-%s: " fmt, to_string(get_rat()).c_str(), ##__VA_ARGS__); \ logger.level("INTRA-%s-%d: " fmt, to_string(get_rat()).c_str(), get_earfcn(), ##__VA_ARGS__); \
} while (false) } while (false)
namespace srsue { namespace srsue {
@ -96,15 +96,18 @@ void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector
return; return;
} }
// Check threshold // Take valid decision if SNR threshold is exceeded
if (meas.snr_dB >= thr_snr_db) { bool valid = (meas.snr_dB >= thr_snr_db);
// Log finding
if (logger.info.enabled()) { // Log finding
std::array<char, 512> str_info = {}; if ((logger.info.enabled() and valid) or logger.debug.enabled()) {
srsran_csi_rs_measure_info(&meas, str_info.data(), (uint32_t)str_info.size()); std::array<char, 512> str_info = {};
Log(info, "Found neighbour cell: ARFCN=%d PCI=%03d %s", get_earfcn(), N_id, str_info.data()); srsran_csi_rs_measure_info(&meas, str_info.data(), (uint32_t)str_info.size());
} Log(info, "%s neighbour cell: PCI=%03d %s", valid ? "Found" : "Best", N_id, str_info.data());
}
// Check threshold
if (valid) {
// Prepare found measurements // Prepare found measurements
std::vector<phy_meas_t> meas_list(1); std::vector<phy_meas_t> meas_list(1);
meas_list[0].rat = get_rat(); meas_list[0].rat = get_rat();

@ -29,9 +29,12 @@ class test_gnb
{ {
private: private:
uint32_t pci; uint32_t pci;
uint32_t sf_len = 0;
srsran_ssb_t ssb = {}; srsran_ssb_t ssb = {};
std::vector<cf_t> signal_buffer = {}; std::vector<cf_t> signal_buffer = {};
srslog::basic_logger& logger; srslog::basic_logger& logger;
srsran::channel channel;
std::vector<cf_t> buffer;
public: public:
struct args_t { struct args_t {
@ -42,15 +45,24 @@ public:
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
uint32_t ssb_period_ms = 20; uint32_t ssb_period_ms = 20;
uint16_t band; uint16_t band;
srsran::channel::args_t channel;
std::string log_level = "error";
srsran_ssb_patern_t get_ssb_pattern() const { return srsran::srsran_band_helper().get_ssb_pattern(band, ssb_scs); } srsran_ssb_patern_t get_ssb_pattern() const { return srsran::srsran_band_helper().get_ssb_pattern(band, ssb_scs); }
srsran_duplex_mode_t get_duplex_mode() const { return srsran::srsran_band_helper().get_duplex_mode(band); } srsran_duplex_mode_t get_duplex_mode() const { return srsran::srsran_band_helper().get_duplex_mode(band); }
}; };
test_gnb(const args_t& args) : logger(srslog::fetch_basic_logger("PCI=" + std::to_string(args.pci))) test_gnb(const args_t& args) :
logger(srslog::fetch_basic_logger("PCI=" + std::to_string(args.pci))), channel(args.channel, 1, logger)
{ {
logger.set_level(srslog::str_to_basic_level(args.log_level));
// Initialise internals // Initialise internals
pci = args.pci; pci = args.pci;
sf_len = (uint32_t)round(args.srate_hz / 1000);
// Allocate buffer
buffer.resize(sf_len);
// Initialise SSB // Initialise SSB
srsran_ssb_args_t ssb_args = {}; srsran_ssb_args_t ssb_args = {};
@ -76,24 +88,40 @@ public:
logger.error("Error configuring SSB"); logger.error("Error configuring SSB");
return; return;
} }
// Configure channel
channel.set_srate(args.srate_hz);
} }
int work(uint32_t sf_idx, std::vector<cf_t>& baseband_buffer) int work(uint32_t sf_idx, std::vector<cf_t>& baseband_buffer, const srsran::rf_timestamp_t& ts)
{ {
logger.set_context(sf_idx); logger.set_context(sf_idx);
// Zero buffer
srsran_vec_cf_zero(buffer.data(), (uint32_t)buffer.size());
// Check if SSB needs to be sent // Check if SSB needs to be sent
if (srsran_ssb_send(&ssb, sf_idx)) { if (srsran_ssb_send(&ssb, sf_idx)) {
// Prepare PBCH message // Prepare PBCH message
srsran_pbch_msg_nr_t msg = {}; srsran_pbch_msg_nr_t msg = {};
// Add SSB // Add SSB
if (srsran_ssb_add(&ssb, pci, &msg, baseband_buffer.data(), baseband_buffer.data()) < SRSRAN_SUCCESS) { if (srsran_ssb_add(&ssb, pci, &msg, buffer.data(), buffer.data()) < SRSRAN_SUCCESS) {
logger.error("Error adding SSB"); logger.error("Error adding SSB");
return SRSRAN_ERROR; return SRSRAN_ERROR;
} }
} }
// Run channel
cf_t* in[SRSRAN_MAX_CHANNELS] = {};
cf_t* out[SRSRAN_MAX_CHANNELS] = {};
in[0] = buffer.data();
out[0] = buffer.data();
channel.run(in, out, (uint32_t)buffer.size(), ts.get(0));
// Add buffer to baseband buffer
srsran_vec_sum_ccc(baseband_buffer.data(), buffer.data(), baseband_buffer.data(), (uint32_t)buffer.size());
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
@ -102,18 +130,23 @@ public:
struct args_t { struct args_t {
// Common execution parameters // Common execution parameters
uint32_t duration_s = 1; uint32_t duration_s = 1;
uint32_t nof_prb = 52; uint32_t nof_prb = 52;
std::string log_level = "info"; std::string log_level = "error";
std::string active_cell_list = "500"; std::string active_cell_list = "500";
std::string simulation_cell_list = "500"; uint32_t meas_len_ms = 1;
uint32_t meas_len_ms = 1; uint32_t meas_period_ms = 20;
uint32_t meas_period_ms = 20; uint32_t carier_arfcn = 634240;
uint32_t carier_arfcn = 634240; uint32_t ssb_arfcn = 634176;
uint32_t ssb_arfcn = 634176; srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; float thr_snr_db = 5.0f;
float thr_snr_db = 5.0f;
// Simulation parameters
std::string simulation_cell_list = "500";
uint32_t ssb_period_ms = 20;
float channel_delay_min = 0.0f; // Set to non-zero value to stir the delay from zero to this value in usec
float channel_delay_max = 0.0f; // Set to non-zero value to stir the delay from zero to this value in usec
// On the Fly parameters // On the Fly parameters
std::string radio_device_name = "auto"; std::string radio_device_name = "auto";
@ -179,6 +212,11 @@ public:
for (auto& e : cells) { for (auto& e : cells) {
bool false_alarm = args.pcis_to_simulate.find(e.first) == args.pcis_to_simulate.end(); bool false_alarm = args.pcis_to_simulate.find(e.first) == args.pcis_to_simulate.end();
if (args.pcis_to_simulate.empty()) {
false_alarm = (args.pcis_to_meas.count(e.first) == 0);
ideal_true_counts = args.pcis_to_meas.size() * tti_count;
}
if (false_alarm) { if (false_alarm) {
false_counts += e.second.count; false_counts += e.second.count;
} else { } else {
@ -221,26 +259,29 @@ int parse_args(int argc, char** argv, args_t& args)
// clang-format off // clang-format off
common.add_options() common.add_options()
("duration", bpo::value<uint32_t>(&args.duration_s), "Duration of the test in seconds") ("duration", bpo::value<uint32_t>(&args.duration_s)->default_value(args.duration_s), "Duration of the test in seconds")
("nof_prb", bpo::value<uint32_t>(&args.nof_prb), "Cell Number of PRB") ("nof_prb", bpo::value<uint32_t>(&args.nof_prb)->default_value(args.nof_prb), "Cell Number of PRB")
("log_level", bpo::value<std::string>(&args.log_level), "Intra measurement log level (none, warning, info, debug)") ("log_level", bpo::value<std::string>(&args.log_level)->default_value(args.log_level), "Intra measurement log level (none, warning, info, debug)")
("meas_len_ms", bpo::value<uint32_t>(&args.meas_len_ms), "Measurement length") ("meas_len_ms", bpo::value<uint32_t>(&args.meas_len_ms)->default_value(args.meas_len_ms), "Measurement length")
("meas_period_ms", bpo::value<uint32_t>(&args.meas_period_ms), "Measurement period") ("meas_period_ms", bpo::value<uint32_t>(&args.meas_period_ms)->default_value(args.meas_period_ms), "Measurement period")
("active_cell_list", bpo::value<std::string>(&args.active_cell_list), "Comma separated PCI cell list to measure") ("active_cell_list", bpo::value<std::string>(&args.active_cell_list)->default_value(args.active_cell_list), "Comma separated PCI cell list to measure")
("carrier_arfcn", bpo::value<std::uint32_t>(&args.carier_arfcn), "Carrier center frequency ARFCN") ("carrier_arfcn", bpo::value<std::uint32_t>(&args.carier_arfcn)->default_value(args.carier_arfcn), "Carrier center frequency ARFCN")
("ssb_arfcn", bpo::value<std::uint32_t>(&args.ssb_arfcn), "SSB center frequency in ARFCN") ("ssb_arfcn", bpo::value<std::uint32_t>(&args.ssb_arfcn)->default_value(args.ssb_arfcn), "SSB center frequency in ARFCN")
("thr_snr_db", bpo::value<float>(&args.thr_snr_db), "Detection threshold for SNR in dB") ("thr_snr_db", bpo::value<float>(&args.thr_snr_db)->default_value(args.thr_snr_db), "Detection threshold for SNR in dB")
; ;
over_the_air.add_options() over_the_air.add_options()
("rf.device_name", bpo::value<std::string>(&args.radio_device_name), "RF Device Name") ("rf.device_name", bpo::value<std::string>(&args.radio_device_name)->default_value(args.radio_device_name), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&args.radio_device_args), "RF Device arguments") ("rf.device_args", bpo::value<std::string>(&args.radio_device_args)->default_value(args.radio_device_args), "RF Device arguments")
("rf.log_level", bpo::value<std::string>(&args.radio_log_level), "RF Log level (none, warning, info, debug)") ("rf.log_level", bpo::value<std::string>(&args.radio_log_level)->default_value(args.radio_log_level), "RF Log level (none, warning, info, debug)")
("rf.rx_gain", bpo::value<float>(&args.rx_gain), "RF Receiver gain in dB") ("rf.rx_gain", bpo::value<float>(&args.rx_gain)->default_value(args.rx_gain), "RF Receiver gain in dB")
; ;
simulation.add_options() simulation.add_options()
("simulation_cell_list", bpo::value<std::string>(&args.simulation_cell_list), "Comma separated PCI cell list to simulate") ("simulation_cell_list", bpo::value<std::string>(&args.simulation_cell_list)->default_value(args.simulation_cell_list), "Comma separated PCI cell list to simulate")
("ssb_period", bpo::value<uint32_t>(&args.ssb_period_ms)->default_value(args.ssb_period_ms), "SSB period in ms")
("channel.delay_min", bpo::value<float>(&args.channel_delay_min)->default_value(args.channel_delay_min), "Channel delay minimum in usec.")
("channel.delay_max", bpo::value<float>(&args.channel_delay_max)->default_value(args.channel_delay_max), "Channel delay maximum in usec. Set to 0 to disable, otherwise it will stir the delay for the duration of the simulation")
; ;
options.add(common).add(over_the_air).add(simulation).add_options() options.add(common).add(over_the_air).add(simulation).add_options()
@ -380,14 +421,22 @@ int main(int argc, char** argv)
// Create test eNb's if radio is not available // Create test eNb's if radio is not available
for (const uint32_t& pci : args.pcis_to_simulate) { for (const uint32_t& pci : args.pcis_to_simulate) {
// Initialise channel and push back // Initialise channel and push back
test_gnb::args_t gnb_args = {}; test_gnb::args_t gnb_args = {};
gnb_args.pci = pci; gnb_args.pci = pci;
gnb_args.srate_hz = srate_hz; gnb_args.srate_hz = srate_hz;
gnb_args.center_freq_hz = center_freq_hz; gnb_args.center_freq_hz = center_freq_hz;
gnb_args.ssb_freq_hz = ssb_freq_hz; gnb_args.ssb_freq_hz = ssb_freq_hz;
gnb_args.ssb_scs = args.ssb_scs; gnb_args.ssb_scs = args.ssb_scs;
gnb_args.ssb_period_ms = args.meas_period_ms; gnb_args.ssb_period_ms = args.ssb_period_ms;
gnb_args.band = band; gnb_args.band = band;
gnb_args.log_level = args.log_level;
gnb_args.channel.delay_enable = std::isnormal(args.channel_delay_max);
gnb_args.channel.delay_min_us = args.channel_delay_min;
gnb_args.channel.delay_max_us = args.channel_delay_max;
gnb_args.channel.delay_period_s = args.duration_s;
gnb_args.channel.delay_init_time_s = 0.0f;
gnb_args.channel.enable = (gnb_args.channel.delay_enable || gnb_args.channel.awgn_enable ||
gnb_args.channel.fading_enable || gnb_args.channel.hst_enable);
test_gnb_v.push_back(std::unique_ptr<test_gnb>(new test_gnb(gnb_args))); test_gnb_v.push_back(std::unique_ptr<test_gnb>(new test_gnb(gnb_args)));
// Add cell to known cells // Add cell to known cells
@ -401,9 +450,9 @@ int main(int argc, char** argv)
intra_measure.set_cells_to_meas(args.pcis_to_meas); intra_measure.set_cells_to_meas(args.pcis_to_meas);
// Run loop // Run loop
srsran::rf_timestamp_t ts = {};
for (uint32_t sf_idx = 0; sf_idx < args.duration_s * 1000; sf_idx++) { for (uint32_t sf_idx = 0; sf_idx < args.duration_s * 1000; sf_idx++) {
logger.set_context(sf_idx); logger.set_context(sf_idx);
srsran::rf_timestamp_t ts = {};
// Clean buffer // Clean buffer
srsran_vec_cf_zero(baseband_buffer.data(), sf_len); srsran_vec_cf_zero(baseband_buffer.data(), sf_len);
@ -415,7 +464,7 @@ int main(int argc, char** argv)
} else { } else {
// Run gNb simulator // Run gNb simulator
for (auto& gnb : test_gnb_v) { for (auto& gnb : test_gnb_v) {
gnb->work(sf_idx, baseband_buffer); gnb->work(sf_idx, baseband_buffer, ts);
} }
// if it measuring, wait for avoiding overflowing // if it measuring, wait for avoiding overflowing

Loading…
Cancel
Save