Intra-frequency miscellanous changes

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 7b159563ab
commit 5eadc06dd4

@ -41,7 +41,7 @@ SRSRAN_API int srsran_refsignal_dl_sync_set_cell(srsran_refsignal_dl_sync_t* q,
SRSRAN_API void srsran_refsignal_dl_sync_free(srsran_refsignal_dl_sync_t* q);
SRSRAN_API void srsran_refsignal_dl_sync_run(srsran_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples);
SRSRAN_API int srsran_refsignal_dl_sync_run(srsran_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples);
SRSRAN_API void srsran_refsignal_dl_sync_measure_sf(srsran_refsignal_dl_sync_t* q,
cf_t* buffer,

@ -367,151 +367,154 @@ int refsignal_dl_sync_find_peak(srsran_refsignal_dl_sync_t* q, cf_t* buffer, uin
return ret;
}
void srsran_refsignal_dl_sync_run(srsran_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
int srsran_refsignal_dl_sync_run(srsran_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
{
if (q) {
uint32_t sf_len = q->ifft.sf_sz;
uint32_t sf_count = 0;
float rsrp_lin = 0.0f;
float rsrp_lin_min = +INFINITY;
float rsrp_lin_max = -INFINITY;
float rssi_lin = 0.0f;
float cfo_acc = 0.0f;
float cfo_min = +INFINITY;
float cfo_max = -INFINITY;
float sss_strength_avg = 0.0f;
float sss_strength_false_avg = 0.0f;
float rsrp_false_avg = 0.0f;
bool false_alarm = false;
// Stage 1: find peak
int peak_idx = refsignal_dl_sync_find_peak(q, buffer, nsamples);
// Stage 2: Proccess subframes
if (peak_idx >= 0) {
// Calculate initial subframe index and sample
uint32_t sf_idx_init = SRSRAN_NOF_SF_X_FRAME - (peak_idx / sf_len) % SRSRAN_NOF_SF_X_FRAME;
uint32_t n_init = peak_idx % sf_len;
for (uint32_t sf_idx = sf_idx_init, n = n_init; n < (nsamples - sf_len + 1);
sf_idx = (sf_idx + 1) % SRSRAN_NOF_SF_X_FRAME, n += sf_len) {
cf_t* buf = &buffer[n];
// Measure subframe rsrp, rssi and accumulate
float rsrp = 0.0f, rssi = 0.0f, cfo = 0.0f;
srsran_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo);
// Update measurements
rsrp_lin += rsrp;
rsrp_lin_min = SRSRAN_MIN(rsrp_lin_min, rsrp);
rsrp_lin_max = SRSRAN_MAX(rsrp_lin_max, rsrp);
rssi_lin += rssi;
cfo_acc += cfo;
cfo_min = SRSRAN_MIN(cfo_min, cfo);
cfo_max = SRSRAN_MAX(cfo_max, cfo);
// Compute PSS/SSS strength
if (sf_idx % (SRSRAN_NOF_SF_X_FRAME / 2) == 0) {
float sss_strength = 0.0f;
float sss_strength_false = 0.0f;
refsignal_dl_pss_sss_strength(q, buf, sf_idx, NULL, &sss_strength, &sss_strength_false);
float rsrp_false = 0.0f;
srsran_refsignal_dl_sync_measure_sf(q, buf, sf_idx + 1, &rsrp_false, NULL, NULL);
sss_strength_avg += sss_strength;
sss_strength_false_avg += sss_strength_false;
rsrp_false_avg += rsrp_false;
}
// Increment counter
sf_count++;
if (q == NULL || buffer == NULL) {
return SRSRAN_ERROR_INVALID_INPUTS;
}
uint32_t sf_len = q->ifft.sf_sz;
uint32_t sf_count = 0;
float rsrp_lin = 0.0f;
float rsrp_lin_min = +INFINITY;
float rsrp_lin_max = -INFINITY;
float rssi_lin = 0.0f;
float cfo_acc = 0.0f;
float cfo_min = +INFINITY;
float cfo_max = -INFINITY;
float sss_strength_avg = 0.0f;
float sss_strength_false_avg = 0.0f;
float rsrp_false_avg = 0.0f;
bool false_alarm = false;
// Stage 1: find peak
int peak_idx = refsignal_dl_sync_find_peak(q, buffer, nsamples);
// Stage 2: Proccess subframes
if (peak_idx >= 0) {
// Calculate initial subframe index and sample
uint32_t sf_idx_init = SRSRAN_NOF_SF_X_FRAME - (peak_idx / sf_len) % SRSRAN_NOF_SF_X_FRAME;
uint32_t n_init = peak_idx % sf_len;
for (uint32_t sf_idx = sf_idx_init, n = n_init; n < (nsamples - sf_len + 1);
sf_idx = (sf_idx + 1) % SRSRAN_NOF_SF_X_FRAME, n += sf_len) {
cf_t* buf = &buffer[n];
// Measure subframe rsrp, rssi and accumulate
float rsrp = 0.0f, rssi = 0.0f, cfo = 0.0f;
srsran_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo);
// Update measurements
rsrp_lin += rsrp;
rsrp_lin_min = SRSRAN_MIN(rsrp_lin_min, rsrp);
rsrp_lin_max = SRSRAN_MAX(rsrp_lin_max, rsrp);
rssi_lin += rssi;
cfo_acc += cfo;
cfo_min = SRSRAN_MIN(cfo_min, cfo);
cfo_max = SRSRAN_MAX(cfo_max, cfo);
// Compute PSS/SSS strength
if (sf_idx % (SRSRAN_NOF_SF_X_FRAME / 2) == 0) {
float sss_strength = 0.0f;
float sss_strength_false = 0.0f;
refsignal_dl_pss_sss_strength(q, buf, sf_idx, NULL, &sss_strength, &sss_strength_false);
float rsrp_false = 0.0f;
srsran_refsignal_dl_sync_measure_sf(q, buf, sf_idx + 1, &rsrp_false, NULL, NULL);
sss_strength_avg += sss_strength;
sss_strength_false_avg += sss_strength_false;
rsrp_false_avg += rsrp_false;
}
// Average measurements
if (sf_count) {
rsrp_lin /= sf_count;
rssi_lin /= sf_count;
cfo_acc /= sf_count;
sss_strength_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
sss_strength_false_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
rsrp_false_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
}
// Increment counter
sf_count++;
}
// RSRP conversion to dB
float rsrp_dB_min = srsran_convert_power_to_dBm(rsrp_lin_min);
float rsrp_dB_max = srsran_convert_power_to_dBm(rsrp_lin_max);
float rsrp_dB = srsran_convert_power_to_dBm(rsrp_lin);
float rsrp_false_dB = srsran_convert_power_to_dBm(rsrp_false_avg);
// Stage 3: Final false alarm decision
uint32_t false_count = 0;
if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_MILD) {
false_count++;
}
// Average measurements
if (sf_count) {
rsrp_lin /= sf_count;
rssi_lin /= sf_count;
cfo_acc /= sf_count;
sss_strength_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
sss_strength_false_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
rsrp_false_avg /= (2.0f * sf_count / SRSRAN_NOF_SF_X_FRAME);
}
if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_MILD) {
false_count++;
}
// RSRP conversion to dB
float rsrp_dB_min = srsran_convert_power_to_dBm(rsrp_lin_min);
float rsrp_dB_max = srsran_convert_power_to_dBm(rsrp_lin_max);
float rsrp_dB = srsran_convert_power_to_dBm(rsrp_lin);
float rsrp_false_dB = srsran_convert_power_to_dBm(rsrp_false_avg);
// Stage 3: Final false alarm decision
uint32_t false_count = 0;
if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_MILD) {
false_count++;
}
if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_MILD) {
false_count++;
}
if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_MILD) {
false_count++;
}
if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_MILD) {
false_count++;
}
if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_MILD) {
false_count++;
}
// Allow only one check fail
if (false_count > REFSIGNAL_DL_MAX_FAULT_CHECK) {
false_alarm = true;
}
if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_MILD) {
false_count++;
}
INFO("-- pci=%03d; rsrp_dB=(%+.1f|%+.1f|%+.1f); rsrp_max-min=%.1f; rsrp_false_ratio=%.1f; "
"cfo=(%.1f|%.1f|%.1f); cfo_max-min=%.1f; sss_ratio=%f; false_count=%d;",
q->refsignal.cell.id,
rsrp_dB_min,
rsrp_dB,
rsrp_dB_max,
rsrp_dB_max - rsrp_dB_min,
rsrp_dB - rsrp_false_dB,
cfo_min,
cfo_acc,
cfo_max,
cfo_max - cfo_min,
sss_strength_avg / sss_strength_false_avg,
false_count);
if (!false_alarm) {
// Calculate in dBm
q->rsrp_dBfs = rsrp_dB;
// Calculate RSSI in dBm
q->rssi_dBfs = srsran_convert_power_to_dBm(rssi_lin);
// Calculate RSRQ
q->rsrq_dB = srsran_convert_power_to_dB(q->refsignal.cell.nof_prb) + q->rsrp_dBfs - q->rssi_dBfs;
q->found = true;
q->cfo_Hz = cfo_acc;
q->peak_index = peak_idx;
} else {
refsignal_set_results_not_found(q);
}
// Allow only one check fail
if (false_count > REFSIGNAL_DL_MAX_FAULT_CHECK) {
false_alarm = true;
}
INFO("-- pci=%03d; rsrp_dB=(%+.1f|%+.1f|%+.1f); rsrp_max-min=%.1f; rsrp_false_ratio=%.1f; "
"cfo=(%.1f|%.1f|%.1f); cfo_max-min=%.1f; sss_ratio=%f; false_count=%d;",
q->refsignal.cell.id,
rsrp_dB_min,
rsrp_dB,
rsrp_dB_max,
rsrp_dB_max - rsrp_dB_min,
rsrp_dB - rsrp_false_dB,
cfo_min,
cfo_acc,
cfo_max,
cfo_max - cfo_min,
sss_strength_avg / sss_strength_false_avg,
false_count);
if (!false_alarm) {
// Calculate in dBm
q->rsrp_dBfs = rsrp_dB;
// Calculate RSSI in dBm
q->rssi_dBfs = srsran_convert_power_to_dBm(rssi_lin);
// Calculate RSRQ
q->rsrq_dB = srsran_convert_power_to_dB(q->refsignal.cell.nof_prb) + q->rsrp_dBfs - q->rssi_dBfs;
q->found = true;
q->cfo_Hz = cfo_acc;
q->peak_index = peak_idx;
} else {
refsignal_set_results_not_found(q);
}
} else {
refsignal_set_results_not_found(q);
}
return SRSRAN_SUCCESS;
}
void srsran_refsignal_dl_sync_measure_sf(srsran_refsignal_dl_sync_t* q,

@ -29,7 +29,7 @@ namespace scell {
class intra_measure_base : public srsran::thread
{
/*
* The intra-cell measurment has 5 different states:
* The intra-cell measurement has 5 different states:
* - idle: it has been initiated and it is waiting to get configured to start capturing samples. From any state
* except quit can transition to idle.
* - wait: waits for the TTI trigger to transition to receive
@ -40,7 +40,7 @@ class intra_measure_base : public srsran::thread
*
* FSM abstraction:
*
* +------+ set_cells_to_meas +------+ intra_freq_meas_period_ms +---------+
* +------+ set_cells_to_meas +------+ receive_tti_trigger +---------+
* | Idle | --------------------->| Wait |------------------------------>| Receive |
* +------+ +------+ +---------+
* ^ ^ | stop +------+
@ -48,6 +48,9 @@ class intra_measure_base : public srsran::thread
* init +---------+ intra_freq_meas_len_ms | +------+
* meas_stop | Measure |<----------------------------------+
* +---------+
*
* This class has been designed to be thread safe. Any method can be called from different threads as long as
* init_generic is called when the FSM is in idle.
*/
public:
/**
@ -64,7 +67,7 @@ public:
* @brief Describes the default generic configuration arguments
*/
struct args_t {
double srate_hz = 0.0; ///< Sampling rate in Hz, set to 0.0 for maximum
double srate_hz = 0.0; ///< Sampling rate in Hz, optional for LTE, compulsory for NR
uint32_t len_ms = 20; ///< Amount of time to accumulate
uint32_t period_ms = 200; ///< Minimum time interval between measurements, set to 0 for free-run
uint32_t tti_period = 0; ///< Measurement TTI trigger period, set to 0 to trigger at any TTI
@ -250,8 +253,13 @@ private:
/**
* @brief Pure virtual function to perform measurements
* @note The context is pass-by-value to protect it from concurrency. However, the buffer is pass-by-reference
* as it is protected by the state.
* @param context Provides current measurement context
* @param buffer Provides current measurement context
* @return True if the measurement functions are executed without errors, otherwise false
*/
virtual void measure_rat(const measure_context_t& context, std::vector<cf_t>& buffer) = 0;
virtual bool measure_rat(measure_context_t context, std::vector<cf_t>& buffer) = 0;
/**
* @brief Measurement process helper method. Encapsulates the neighbour cell measurement functionality

@ -67,8 +67,9 @@ private:
* @brief LTE specific measurement process
* @param context Measurement context
* @param buffer Provides the baseband buffer to perform the measurements
* @return True if no error happens, otherwise false
*/
void measure_rat(const measure_context_t& context, std::vector<cf_t>& buffer) override;
bool measure_rat(measure_context_t context, std::vector<cf_t>& buffer) override;
srslog::basic_logger& logger;
srsran_cell_t serving_cell = {}; ///< Current serving cell in the EARFCN, to avoid reporting it

@ -107,8 +107,9 @@ private:
* @attention It searches and measures the SSB with best SNR
* @param context Measurement context
* @param buffer Provides the baseband buffer to perform the measurements
* @return True if no error happen, otherwise false
*/
void measure_rat(const measure_context_t& context, std::vector<cf_t>& buffer) override;
bool measure_rat(measure_context_t context, std::vector<cf_t>& buffer) override;
srslog::basic_logger& logger;
uint32_t cc_idx = 0;

@ -38,9 +38,16 @@ void intra_measure_base::init_generic(uint32_t cc_idx_, const args_t& args)
context.trigger_tti_offset = args.tti_offset;
context.rx_gain_offset_db = args.rx_gain_offset_db;
context.sf_len = SRSRAN_SF_LEN_PRB(SRSRAN_MAX_PRB);
// Compute subframe length from the sampling rate if available
if (std::isnormal(args.srate_hz)) {
context.sf_len = (uint32_t)round(args.srate_hz / 1000.0);
} else if (get_rat() == srsran::srsran_rat_t::lte) {
// Select maximum subframe size for LTE
context.sf_len = SRSRAN_SF_LEN_PRB(SRSRAN_MAX_PRB);
} else {
// No maximum subframe length is defined for other RATs
ERROR("A sampling rate was expected for %s. Undefined behaviour.", srsran::to_string(get_rat()).c_str());
return;
}
// Calculate the new required bytes
@ -54,6 +61,7 @@ void intra_measure_base::init_generic(uint32_t cc_idx_, const args_t& args)
// Initialise buffer for the maximum number of PRB
if (srsran_ringbuffer_init(&ring_buffer, max_required_bytes) < SRSRAN_SUCCESS) {
ERROR("Error initiating ringbuffer");
return;
}
}
@ -86,7 +94,7 @@ void intra_measure_base::meas_stop()
// Transition state to idle
// Ring-buffer shall not be reset, it will automatically be reset as soon as the FSM transitions to receive
state.set_state(internal_state::idle);
Log(info, "Disabled neighbour cell search for EARFCN %d", get_earfcn());
Log(info, "Disabled neighbour cell search");
}
void intra_measure_base::set_cells_to_meas(const std::set<uint32_t>& pci)
@ -95,7 +103,7 @@ void intra_measure_base::set_cells_to_meas(const std::set<uint32_t>& pci)
context.active_pci = pci;
active_pci_mutex.unlock();
state.set_state(internal_state::wait_first);
Log(info, "Received list of %zd neighbour cells to measure in EARFCN %d.", pci.size(), get_earfcn());
Log(info, "Received list of %zd neighbour cells to measure", pci.size());
}
void intra_measure_base::write(cf_t* data, uint32_t nsamples)
@ -108,7 +116,7 @@ void intra_measure_base::write(cf_t* data, uint32_t nsamples)
// Try writing in the buffer
if (srsran_ringbuffer_write(&ring_buffer, data, nbytes) < nbytes) {
Log(warning, "Error writing to ringbuffer (EARFCN=%d)", get_earfcn());
Log(warning, "Error writing to ringbuffer");
// Transition to wait, so it can keep receiving without stopping the component operation
state.set_state(internal_state::wait);
@ -154,11 +162,11 @@ void intra_measure_base::run_tti(uint32_t tti, cf_t* data, uint32_t nsamples)
void intra_measure_base::measure_proc()
{
std::set<uint32_t> cells_to_measure = {};
// Read data from buffer and find cells in it
int ret = srsran_ringbuffer_read_timed(
&ring_buffer, search_buffer.data(), (int)(context.meas_len_ms * context.sf_len * sizeof(cf_t)), 1000);
// As this function is called once the ring-buffer has enough data to process, it is not expected to fail
if (ret < SRSRAN_SUCCESS) {
Log(error, "Ringbuffer read returned %d", ret);
return;
@ -171,7 +179,9 @@ void intra_measure_base::measure_proc()
}
// Perform measurements for the actual RAT
measure_rat(context, search_buffer);
if (not measure_rat(context, search_buffer)) {
Log(error, "Error measuring RAT");
}
}
void intra_measure_base::run_thread()

@ -47,7 +47,7 @@ void intra_measure_lte::set_primary_cell(uint32_t earfcn, srsran_cell_t cell)
set_current_sf_len((uint32_t)SRSRAN_SF_LEN_PRB(cell.nof_prb));
}
void intra_measure_lte::measure_rat(const measure_context_t& context, std::vector<cf_t>& buffer)
bool intra_measure_lte::measure_rat(measure_context_t context, std::vector<cf_t>& buffer)
{
std::set<uint32_t> cells_to_measure = context.active_pci;
@ -68,8 +68,16 @@ void intra_measure_lte::measure_rat(const measure_context_t& context, std::vecto
srsran_cell_t cell = serving_cell;
cell.id = id;
srsran_refsignal_dl_sync_set_cell(&refsignal_dl_sync, cell);
srsran_refsignal_dl_sync_run(&refsignal_dl_sync, buffer.data(), context.meas_len_ms * context.sf_len);
if (srsran_refsignal_dl_sync_set_cell(&refsignal_dl_sync, cell) < SRSRAN_SUCCESS) {
Log(error, "Error setting refsignal DL cell");
return false;
}
if (srsran_refsignal_dl_sync_run(&refsignal_dl_sync, buffer.data(), context.meas_len_ms * context.sf_len) <
SRSRAN_SUCCESS) {
Log(error, "Error running refsignal DL measurements");
return false;
}
if (refsignal_dl_sync.found) {
phy_meas_t m = {};
@ -96,6 +104,8 @@ void intra_measure_lte::measure_rat(const measure_context_t& context, std::vecto
if (not neighbour_cells.empty()) {
context.new_cell_itf.new_cell_meas(context.cc_idx, neighbour_cells);
}
return true;
}
} // namespace scell

@ -81,7 +81,7 @@ bool intra_measure_nr::set_config(uint32_t arfcn, const config_t& cfg)
return true;
}
void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector<cf_t>& buffer)
bool intra_measure_nr::measure_rat(const measure_context_t context, std::vector<cf_t>& buffer)
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
@ -90,6 +90,7 @@ void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector
uint32_t N_id = 0;
if (srsran_ssb_csi_search(&ssb, buffer.data(), context.sf_len * context.meas_len_ms, &N_id, &meas) < SRSRAN_SUCCESS) {
Log(error, "Error searching for SSB");
return false;
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
@ -98,7 +99,7 @@ void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector
// Early return if the found PCI matches with the serving cell ID
if (serving_cell_pci == (int)N_id) {
return;
return true;
}
// Take valid decision if SNR threshold is exceeded
@ -124,6 +125,8 @@ void intra_measure_nr::measure_rat(const measure_context_t& context, std::vector
// Push measurements to higher layers
context.new_cell_itf.new_cell_meas(cc_idx, meas_list);
}
return true;
}
} // namespace scell

Loading…
Cancel
Save