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->epre_dB,
measure->n0_dB,
measure->snr_dB);
measure->snr_dB,
measure->delay_us);
// Append measured CFO and the maximum CFO that can be measured
if (isnormal(measure->cfo_hz_max)) {

@ -212,7 +212,7 @@ void channel::run(cf_t* in[SRSRAN_MAX_CHANNELS],
// Logging
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]) {
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
*/
#define SSB_CORR_SZ 4
#define SSB_CORR_SZ 2
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);
// Find maximum
uint32_t this_max_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
float corr = SRSRAN_CSQABS(q->tmp_time[this_max_idx]);
uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
// 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
if (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;
}
}
@ -817,4 +827,4 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q, uint32_t N_id, const cf_t* in, srsra
}
return SRSRAN_SUCCESS;
}
}

@ -13,7 +13,7 @@
#define Log(level, fmt, ...) \
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)
namespace srsue {
@ -117,6 +117,8 @@ void intra_measure_base::write(uint32_t tti, cf_t* data, uint32_t nsamples)
last_measure_tti = tti;
srsran_ringbuffer_reset(&ring_buffer);
Log(debug, "Start writing");
// Force receive state
write(tti, data, nsamples);
}
@ -134,6 +136,7 @@ void intra_measure_base::write(uint32_t tti, cf_t* data, uint32_t nsamples)
} else {
// As soon as there are enough samples in the buffer, transition to measure
if (srsran_ringbuffer_status(&ring_buffer) >= required_nbytes) {
Log(debug, "Starting search and measurements");
state.set_state(internal_state::measure);
}
}
@ -146,8 +149,12 @@ void intra_measure_base::measure_proc()
std::set<uint32_t> cells_to_measure = {};
// Read data from buffer and find cells in it
srsran_ringbuffer_read(
&ring_buffer, search_buffer.data(), (int)(context.meas_len_ms * context.sf_len * sizeof(cf_t)));
int ret = srsran_ringbuffer_read_timed(
&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
if (state.get_state() == internal_state::measure) {

@ -16,7 +16,7 @@ namespace scell {
#define Log(level, fmt, ...) \
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)
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);
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",
m.earfcn,
m.pci,
m.rsrp,
m.rsrq,

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

@ -29,9 +29,12 @@ class test_gnb
{
private:
uint32_t pci;
uint32_t sf_len = 0;
srsran_ssb_t ssb = {};
std::vector<cf_t> signal_buffer = {};
srslog::basic_logger& logger;
srsran::channel channel;
std::vector<cf_t> buffer;
public:
struct args_t {
@ -42,15 +45,24 @@ public:
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
uint32_t ssb_period_ms = 20;
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_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
pci = args.pci;
pci = args.pci;
sf_len = (uint32_t)round(args.srate_hz / 1000);
// Allocate buffer
buffer.resize(sf_len);
// Initialise SSB
srsran_ssb_args_t ssb_args = {};
@ -76,24 +88,40 @@ public:
logger.error("Error configuring SSB");
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);
// Zero buffer
srsran_vec_cf_zero(buffer.data(), (uint32_t)buffer.size());
// Check if SSB needs to be sent
if (srsran_ssb_send(&ssb, sf_idx)) {
// Prepare PBCH message
srsran_pbch_msg_nr_t msg = {};
// 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");
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;
}
@ -102,18 +130,23 @@ public:
struct args_t {
// Common execution parameters
uint32_t duration_s = 1;
uint32_t nof_prb = 52;
std::string log_level = "info";
std::string active_cell_list = "500";
std::string simulation_cell_list = "500";
uint32_t meas_len_ms = 1;
uint32_t meas_period_ms = 20;
uint32_t carier_arfcn = 634240;
uint32_t ssb_arfcn = 634176;
srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
float thr_snr_db = 5.0f;
uint32_t duration_s = 1;
uint32_t nof_prb = 52;
std::string log_level = "error";
std::string active_cell_list = "500";
uint32_t meas_len_ms = 1;
uint32_t meas_period_ms = 20;
uint32_t carier_arfcn = 634240;
uint32_t ssb_arfcn = 634176;
srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz;
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
std::string radio_device_name = "auto";
@ -179,6 +212,11 @@ public:
for (auto& e : cells) {
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) {
false_counts += e.second.count;
} else {
@ -221,26 +259,29 @@ int parse_args(int argc, char** argv, args_t& args)
// clang-format off
common.add_options()
("duration", bpo::value<uint32_t>(&args.duration_s), "Duration of the test in seconds")
("nof_prb", bpo::value<uint32_t>(&args.nof_prb), "Cell Number of PRB")
("log_level", bpo::value<std::string>(&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_period_ms", bpo::value<uint32_t>(&args.meas_period_ms), "Measurement period")
("active_cell_list", bpo::value<std::string>(&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")
("ssb_arfcn", bpo::value<std::uint32_t>(&args.ssb_arfcn), "SSB center frequency in ARFCN")
("thr_snr_db", bpo::value<float>(&args.thr_snr_db), "Detection threshold for SNR in dB")
("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)->default_value(args.nof_prb), "Cell Number of PRB")
("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)->default_value(args.meas_len_ms), "Measurement length")
("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)->default_value(args.active_cell_list), "Comma separated PCI cell list to measure")
("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)->default_value(args.ssb_arfcn), "SSB center frequency in ARFCN")
("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()
("rf.device_name", bpo::value<std::string>(&args.radio_device_name), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&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.rx_gain", bpo::value<float>(&args.rx_gain), "RF Receiver gain in dB")
("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)->default_value(args.radio_device_args), "RF Device arguments")
("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)->default_value(args.rx_gain), "RF Receiver gain in dB")
;
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()
@ -380,14 +421,22 @@ int main(int argc, char** argv)
// Create test eNb's if radio is not available
for (const uint32_t& pci : args.pcis_to_simulate) {
// Initialise channel and push back
test_gnb::args_t gnb_args = {};
gnb_args.pci = pci;
gnb_args.srate_hz = srate_hz;
gnb_args.center_freq_hz = center_freq_hz;
gnb_args.ssb_freq_hz = ssb_freq_hz;
gnb_args.ssb_scs = args.ssb_scs;
gnb_args.ssb_period_ms = args.meas_period_ms;
gnb_args.band = band;
test_gnb::args_t gnb_args = {};
gnb_args.pci = pci;
gnb_args.srate_hz = srate_hz;
gnb_args.center_freq_hz = center_freq_hz;
gnb_args.ssb_freq_hz = ssb_freq_hz;
gnb_args.ssb_scs = args.ssb_scs;
gnb_args.ssb_period_ms = args.ssb_period_ms;
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)));
// 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);
// Run loop
srsran::rf_timestamp_t ts = {};
for (uint32_t sf_idx = 0; sf_idx < args.duration_s * 1000; sf_idx++) {
logger.set_context(sf_idx);
srsran::rf_timestamp_t ts = {};
// Clean buffer
srsran_vec_cf_zero(baseband_buffer.data(), sf_len);
@ -415,7 +464,7 @@ int main(int argc, char** argv)
} else {
// Run gNb simulator
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

Loading…
Cancel
Save