More cell search development

master
Xavier Arteaga 3 years ago committed by Xavier Arteaga
parent b616207ef0
commit a5130673f6

@ -53,7 +53,7 @@ typedef struct SRSRAN_API {
*/
typedef struct SRSRAN_API {
srsran_ssb_cfg_t ssb; ///< SSB configuration
uint32_t N_id; ///< Physicall cell identifier
uint32_t N_id; ///< Physical cell identifier
} srsran_ue_sync_nr_cfg_t;
/**

@ -420,6 +420,12 @@ int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg)
return SRSRAN_ERROR_INVALID_INPUTS;
}
printf("-- srate=%.2fMHz; center_freq=%.2fMHz; ssb_freq=%.2fMHz; scs=%s;\n",
cfg->srate_hz / 1e6,
cfg->center_freq_hz / 1e6,
cfg->ssb_freq_hz / 1e6,
srsran_subcarrier_spacing_to_str(cfg->scs));
// Calculate subcarrier spacing in Hz
q->scs_hz = (float)SRSRAN_SUBC_SPACING_NR(cfg->scs);
@ -1127,6 +1133,14 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
return SRSRAN_ERROR;
}
if (fabs(q->cfg.ssb_freq_hz - 1842.05e6) < 1e6) {
printf("-- freq=%.3f; N_id=%d; EPRE=%+.2f; RSRP=%+.2f;\n",
q->cfg.ssb_freq_hz,
N_id,
measurements.epre_dB,
measurements.rsrp_dB);
}
// Save result
res->N_id = N_id;
res->t_offset = t_offset;

@ -307,4 +307,4 @@ clean_exit:
test_context_free(&ctx);
return ret;
}
}

@ -175,7 +175,7 @@ static int ue_sync_nr_run_track(srsran_ue_sync_nr_t* q, cf_t* buffer)
return SRSRAN_ERROR;
}
// If the PBCH message was NOT decoded, transition to track
// If the PBCH message was NOT decoded, transition to find
if (!pbch_msg.crc) {
q->state = SRSRAN_UE_SYNC_NR_STATE_FIND;
return SRSRAN_SUCCESS;

@ -39,9 +39,14 @@ public:
bool init(const args_t& args, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
int set_sync_cfg(const srsran_ue_sync_nr_cfg_t& cfg);
int recv_callback(srsran::rf_buffer_t& rf_buffer, srsran_timestamp_t* timestamp);
bool run_sfn_sync();
void run_stack_tti();
srsran_slot_cfg_t get_slot_cfg();
private:
const static int MIN_TTI_JUMP = 1; ///< Time gap reported to stack after receiving subframe
const static int MAX_TTI_JUMP = 1000; ///< Maximum time gap tolerance in RF stream metadata
@ -54,7 +59,8 @@ private:
srsran_timestamp_t stack_tti_ts_new = {};
srsran_timestamp_t stack_tti_ts = {};
bool forced_rx_time_init = true; // Rx time sync after first receive from radio
uint32_t tti = 0;
srsran::rf_buffer_t sfn_sync_buff = {};
srsran_slot_cfg_t slot_cfg = {};
};
} // namespace nr
} // namespace srsue

@ -67,9 +67,9 @@ public:
sync_sa(srslog::basic_logger& logger, worker_pool& workers_);
~sync_sa();
bool init(const args_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
bool init(const args_t& args_, stack_interface_phy_nr* stack_, srsran::radio_interface_phy* radio_);
bool reset();
void stop();
void stop();
sync_state::state_t get_state();
// The following methods control the SYNC state machine
@ -82,7 +82,7 @@ public:
private:
stack_interface_phy_nr* stack = nullptr; ///< Stand-Alone RRC interface
srsran::radio_interface_phy* radio = nullptr; ///< Radio object
srslog::basic_logger& logger; ///< General PHY logger
srslog::basic_logger& logger; ///< General PHY logger
worker_pool& workers;
// FSM that manages RRC commands for cell search/select/sync procedures
@ -99,6 +99,8 @@ private:
bool is_pending_tx_end = false;
uint32_t cell_search_nof_trials = 0;
const static uint32_t cell_search_max_trials = 100;
uint32_t sfn_sync_nof_trials = 0;
const static uint32_t sfn_sync_max_trials = 100;
cell_search::ret_t cs_ret;
cell_search searcher;
@ -108,7 +110,7 @@ private:
bool wait_idle();
void run_state_idle();
void run_state_cell_search();
void run_state_cell_select();
void run_state_sfn_sync();
void run_state_cell_camping();
int radio_recv_fnc(srsran::rf_buffer_t& data, srsran_timestamp_t* rx_time);

@ -80,4 +80,4 @@ cell_search::ret_t cell_search::run_slot(const cf_t* buffer, uint32_t slot_sz)
}
} // namespace nr
} // namespace srsue
} // namespace srsue

@ -15,14 +15,14 @@
namespace srsue {
namespace nr {
slot_sync::slot_sync(srslog::basic_logger& logger_) : logger(logger_) {}
slot_sync::slot_sync(srslog::basic_logger& logger_) : logger(logger_), sfn_sync_buff(1) {}
slot_sync::~slot_sync()
{
srsran_ue_sync_nr_free(&ue_sync_nr);
}
int sync_sa_recv_callback(void* ptr, cf_t** buffer, uint32_t nsamples, srsran_timestamp_t* ts)
static int slot_sync_recv_callback(void* ptr, cf_t** buffer, uint32_t nsamples, srsran_timestamp_t* ts)
{
if (ptr == nullptr) {
return SRSRAN_ERROR_INVALID_INPUTS;
@ -45,6 +45,8 @@ bool slot_sync::init(const args_t& args, stack_interface_phy_nr* stack_, srsran:
ue_sync_nr_args.disable_cfo = args.disable_cfo;
ue_sync_nr_args.pbch_dmrs_thr = args.pbch_dmrs_thr;
ue_sync_nr_args.cfo_alpha = args.cfo_alpha;
ue_sync_nr_args.recv_obj = this;
ue_sync_nr_args.recv_callback = slot_sync_recv_callback;
if (srsran_ue_sync_nr_init(&ue_sync_nr, &ue_sync_nr_args) < SRSRAN_SUCCESS) {
logger.error("Error initiating UE SYNC NR object");
@ -54,6 +56,16 @@ bool slot_sync::init(const args_t& args, stack_interface_phy_nr* stack_, srsran:
return true;
}
int slot_sync::set_sync_cfg(const srsran_ue_sync_nr_cfg_t& cfg)
{
if (srsran_ue_sync_nr_set_cfg(&ue_sync_nr, &cfg) < SRSRAN_SUCCESS) {
logger.error("SYNC: failed to set cell configuration for N_id %d", cfg.N_id);
return SRSRAN_ERROR;
}
return SRSRAN_SUCCESS;
}
int slot_sync::recv_callback(srsran::rf_buffer_t& data, srsran_timestamp_t* rx_time)
{
// This function is designed for being called from the UE sync object which will pass a null rx_time in case
@ -88,6 +100,21 @@ int slot_sync::recv_callback(srsran::rf_buffer_t& data, srsran_timestamp_t* rx_t
return data.get_nof_samples();
}
bool slot_sync::run_sfn_sync()
{
srsran_ue_sync_nr_outcome_t outcome = {};
if (srsran_ue_sync_nr_zerocopy(&ue_sync_nr, sfn_sync_buff.to_cf_t(), &outcome) < SRSRAN_SUCCESS) {
logger.error("SYNC: error in zerocopy");
return false;
}
if (outcome.in_sync) {
slot_cfg.idx = outcome.sfn * SRSRAN_NSLOTS_PER_SF_NR(srsran_subcarrier_spacing_15kHz) + outcome.sf_idx;
}
return outcome.in_sync;
}
void slot_sync::run_stack_tti()
{ // check timestamp reset
if (forced_rx_time_init || srsran_timestamp_iszero(&stack_tti_ts) ||
@ -118,8 +145,8 @@ void slot_sync::run_stack_tti()
}
// Run stack
logger.debug("run_stack_tti: calling stack tti=%d, tti_jump=%d", tti, tti_jump);
stack->run_tti(tti, tti_jump);
logger.debug("run_stack_tti: calling stack tti=%d, tti_jump=%d", slot_cfg.idx, tti_jump);
stack->run_tti(slot_cfg.idx, tti_jump);
logger.debug("run_stack_tti: stack called");
}
@ -127,5 +154,10 @@ void slot_sync::run_stack_tti()
srsran_timestamp_copy(&stack_tti_ts, &stack_tti_ts_new);
}
srsran_slot_cfg_t slot_sync::get_slot_cfg()
{
return slot_cfg;
}
} // namespace nr
} // namespace srsue

@ -157,6 +157,15 @@ bool sync_sa::cell_select_run(const phy_interface_rrc_nr::cell_select_args_t& re
logger.info("Tuning Tx channel %d to %.2f MHz", 0, req.carrier.ul_center_frequency_hz / 1e6);
radio->set_tx_freq(0, req.carrier.ul_center_frequency_hz);
// Configure cell
srsran_ue_sync_nr_cfg_t cfg = {};
cfg.N_id = req.carrier.pci;
cfg.ssb = req.ssb_cfg;
if (slot_synchronizer.set_sync_cfg(cfg)) {
logger.error("Cell Search: Failed setting slot synchronizer configuration");
return false;
}
// SFN synchronization
phy_state.run_sfn_sync();
if (phy_state.is_camping()) {
@ -176,7 +185,7 @@ sync_state::state_t sync_sa::get_state()
void sync_sa::run_state_idle()
{
#define test 0
#define test 1
if (radio->is_init() && test) {
logger.debug("Discarding samples and sending tx_end");
srsran::rf_buffer_t rf_buffer = {};
@ -197,30 +206,60 @@ void sync_sa::run_state_cell_search()
// Receive samples
srsran::rf_buffer_t rf_buffer = {};
rf_buffer.set_nof_samples(slot_sz);
rf_buffer.set(0, rx_buffer);
rf_buffer.set(0, rx_buffer + slot_sz);
if (not slot_synchronizer.recv_callback(rf_buffer, last_rx_time.get_ptr(0))) {
logger.error("SYNC: receiving from radio\n");
}
// Run Searcher
cs_ret = searcher.run_slot(rx_buffer, slot_sz);
cs_ret = searcher.run_slot(rx_buffer, 2 * slot_sz);
if (cs_ret.result < 0) {
logger.error("Failed to run searcher. Transitioning to IDLE...");
}
srsran_vec_cf_copy(rx_buffer, rx_buffer + slot_sz, slot_sz);
cell_search_nof_trials++;
if (cs_ret.result == cell_search::ret_t::CELL_FOUND) {
logger.error("CELL FOUND!");
rrc_interface_phy_nr::cell_search_result_t result = {};
result.cell_found = true;
result.pci = cs_ret.ssb_res.N_id;
result.pbch_msg = cs_ret.ssb_res.pbch_msg;
result.measurements = cs_ret.ssb_res.measurements;
stack->cell_search_found_cell(result);
}
// Leave CELL_SEARCH state if error or success and transition to IDLE
if (cs_ret.result || cell_search_nof_trials >= cell_search_max_trials) {
if (/*cs_ret.result || */ cell_search_nof_trials >= cell_search_max_trials) {
phy_state.state_exit();
}
}
void sync_sa::run_state_cell_select()
void sync_sa::run_state_sfn_sync()
{
// TODO
tti = 10240 - 4;
phy_state.state_exit();
// Run SFN synchronization
if (slot_synchronizer.run_sfn_sync()) {
tti = slot_synchronizer.get_slot_cfg().idx;
logger.info("SYNC: SFN synchronised successfully (SFN=%d). Transitioning to IDLE...",
tti / SRSRAN_NSLOTS_PER_FRAME_NR(srsran_subcarrier_spacing_15kHz));
phy_state.state_exit();
return;
}
// If not synchonized, increment number of trials
sfn_sync_nof_trials++;
// Abort SFN synchronization if the maximum number of trials is reached
if (sfn_sync_nof_trials >= sfn_sync_max_trials) {
logger.info("SYNC: The SFN sync reached the maximum number of trials (%d). Transitioning to IDLE...",
sfn_sync_nof_trials);
phy_state.state_exit(false);
}
}
void sync_sa::run_state_cell_camping()
@ -271,7 +310,7 @@ void sync_sa::run_thread()
run_state_cell_search();
break;
case sync_state::SFN_SYNC:
run_state_cell_select();
run_state_sfn_sync();
break;
case sync_state::CAMPING:
run_state_cell_camping();
@ -324,4 +363,4 @@ void sync_sa::worker_end(const srsran::phy_common_interface::worker_context_t& w
}
} // namespace nr
} // namespace srsue
} // namespace srsue

@ -213,12 +213,13 @@ private:
public:
struct args_t {
srsue::phy_args_nr_t phy;
ue_dummy_stack::args_t stack;
srsue::phy_args_nr_t phy;
ue_dummy_stack::args_t stack;
};
dummy_ue(const args_t& args, srsran::radio_interface_phy* radio) : stack(args.stack, phy), phy("PHY")
{
srsran_assert(phy.init(args.phy, &stack, radio), "Failed to initialise PHY");
srsran_assert(phy.init(args.phy, &stack, radio) == SRSRAN_SUCCESS, "Failed to initialise PHY");
phy.wait_initialize();
}
bool start_cell_search(const srsue::phy_interface_stack_nr::cell_search_args_t& args)
@ -275,13 +276,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>();
@ -301,23 +302,68 @@ int main(int argc, char** argv)
}
// Create dummy UE
dummy_ue::args_t ue_args = {};
dummy_ue::args_t ue_args = {};
ue_args.phy.log.phy_level = args.phy_log_level;
ue_args.stack.log_level = args.stack_log_level;
ue_args.stack.log_level = args.stack_log_level;
dummy_ue ue(ue_args, radio.get());
// Transition PHY to cell search
srsue::phy_nr_sa::cell_search_args_t cell_search_req = {};
cell_search_req.srate_hz = args.srate_hz;
cell_search_req.center_freq_hz = args.base_carrier.dl_center_frequency_hz;
cell_search_req.ssb_freq_hz = args.base_carrier.ssb_center_freq_hz;
cell_search_req.ssb_scs = args.ssb_scs;
cell_search_req.ssb_pattern = args.ssb_pattern;
cell_search_req.duplex_mode = args.duplex_mode;
srsran_assert(ue.start_cell_search(cell_search_req), "Failed cell search start");
for (uint32_t i = 0; i < args.duration_ms; i++) {
ue.run_tti();
// Base cell search arguments
srsue::phy_nr_sa::cell_search_args_t cs_args = {};
cs_args.srate_hz = args.srate_hz;
cs_args.center_freq_hz = args.base_carrier.dl_center_frequency_hz;
cs_args.ssb_scs = args.ssb_scs;
cs_args.ssb_pattern = args.ssb_pattern;
cs_args.duplex_mode = args.duplex_mode;
std::vector<srsue::phy_nr_sa::cell_search_args_t> v_cs_args = {};
/*if (std::isnormal(args.base_carrier.ssb_center_freq_hz)) {
cs_args.ssb_freq_hz = args.base_carrier.ssb_center_freq_hz;
v_cs_args.push_back(cs_args);
} else*/
{
srsran::srsran_band_helper bands;
// Deduce band number
uint16_t band = bands.get_band_from_dl_freq_Hz(args.base_carrier.dl_center_frequency_hz);
srsran_assert(band != UINT16_MAX, "Invalid band");
// Get sync raster
srsran::srsran_band_helper::sync_raster_t ss = bands.get_sync_raster(band, args.ssb_scs);
srsran_assert(ss.valid(), "Invalid synchronization raster");
// Calculate SSB center frequency boundaries
double ssb_bw_hz = SRSRAN_SSB_BW_SUBC * bands.get_ssb_scs(band);
double ssb_center_freq_min_hz = args.base_carrier.dl_center_frequency_hz - (args.srate_hz * 0.7 - ssb_bw_hz) / 2.0;
double ssb_center_freq_max_hz = args.base_carrier.dl_center_frequency_hz + (args.srate_hz * 0.7 - ssb_bw_hz) / 2.0;
uint32_t ssb_scs_hz = SRSRAN_SUBC_SPACING_NR(args.ssb_scs);
// Iterate every possible synchronization raster
while (not ss.end()) {
// Get SSB center frequency
double abs_freq_ssb_hz = ss.get_frequency();
uint32_t offset = (uint32_t)std::abs(std::round(abs_freq_ssb_hz - args.base_carrier.dl_center_frequency_hz));
// Use frequency if it is within the range
if ((abs_freq_ssb_hz > ssb_center_freq_min_hz) and (abs_freq_ssb_hz < ssb_center_freq_max_hz) and
(offset % ssb_scs_hz == 0)) {
cs_args.ssb_freq_hz = abs_freq_ssb_hz;
v_cs_args.push_back(cs_args);
}
// Next frequency
ss.next();
}
}
// For each SSB center frequency...
for (const srsue::phy_nr_sa::cell_search_args_t& cs_args_ : v_cs_args) {
// 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++) {
ue.run_tti();
}
}
// Tear down UE

Loading…
Cancel
Save