SRSUE: moved sync SCell classes in new namespace

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent 22139afe09
commit ceac7a02c8

@ -22,7 +22,6 @@
#ifndef SRSUE_PHY_H #ifndef SRSUE_PHY_H
#define SRSUE_PHY_H #define SRSUE_PHY_H
#include "async_scell_recv.h"
#include "phy_common.h" #include "phy_common.h"
#include "phy_metrics.h" #include "phy_metrics.h"
#include "prach.h" #include "prach.h"
@ -32,6 +31,7 @@
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srsue/hdr/phy/scell/async_scell_recv.h"
#include "srsue/hdr/phy/ue_lte_phy_base.h" #include "srsue/hdr/phy/ue_lte_phy_base.h"
#include "sync.h" #include "sync.h"
@ -155,7 +155,7 @@ private:
std::vector<sf_worker*> workers; std::vector<sf_worker*> workers;
phy_common common; phy_common common;
sync sfsync; sync sfsync;
async_scell_recv_vector scell_sync; scell::async_recv_vector scell_sync;
uint32_t scell_earfcn[SRSLTE_MAX_CARRIERS - 1]; uint32_t scell_earfcn[SRSLTE_MAX_CARRIERS - 1];
prach prach_buffer; prach prach_buffer;

@ -24,8 +24,6 @@
#include <pthread.h> #include <pthread.h>
#include "prach.h"
#include "phy_common.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/thread_pool.h" #include "srslte/common/thread_pool.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
@ -33,6 +31,8 @@
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srsue/hdr/phy/phy_common.h"
#include "srsue/hdr/phy/prach.h"
#include <cassert> #include <cassert>
#include <cstdio> #include <cstdio>
@ -43,6 +43,7 @@
#include <vector> #include <vector>
namespace srsue { namespace srsue {
namespace scell {
class async_scell_recv : private thread class async_scell_recv : private thread
{ {
@ -195,9 +196,10 @@ protected:
void run_thread() override; void run_thread() override;
}; };
typedef std::unique_ptr<async_scell_recv> async_scell_recv_ptr; typedef std::unique_ptr<async_scell_recv> async_recv_ptr;
typedef std::vector<async_scell_recv_ptr> async_scell_recv_vector; typedef std::vector<async_recv_ptr> async_recv_vector;
} // namespace scell
} // namespace srsue } // namespace srsue
#endif // SRSUE_ASYNCH_SCELL_RECV_H #endif // SRSUE_ASYNCH_SCELL_RECV_H

@ -0,0 +1,78 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_INTRA_MEASURE_H
#define SRSUE_INTRA_MEASURE_H
#include <srslte/common/log.h>
#include <srslte/common/threads.h>
#include <srslte/srslte.h>
#include <srsue/hdr/phy/scell/scell_recv.h>
namespace srsue {
namespace scell {
// Class to perform intra-frequency measurements
class intra_measure : public thread
{
public:
intra_measure();
~intra_measure();
void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h);
void stop();
void add_cell(int pci);
void rem_cell(int pci);
void set_primay_cell(uint32_t earfcn, srslte_cell_t cell);
void clear_cells();
int get_offset(uint32_t pci);
void write(uint32_t tti, cf_t* data, uint32_t nsamples);
private:
void run_thread();
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
scell_recv scell;
rrc_interface_phy_lte* rrc;
srslte::log* log_h;
phy_common* common;
uint32_t current_earfcn;
uint32_t current_sflen;
srslte_cell_t primary_cell;
std::vector<int> active_pci;
srslte::tti_sync_cv tti_sync;
cf_t* search_buffer;
scell_recv::cell_info_t info[scell_recv::MAX_CELLS];
bool running;
bool receive_enabled;
bool receiving;
uint32_t measure_tti;
uint32_t receive_cnt;
srslte_ringbuffer_t ring_buffer;
};
} // namespace scell
} // namespace srsue
#endif // SRSUE_INTRA_MEASURE_H

@ -0,0 +1,74 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_MEASURE_RECV_H
#define SRSUE_MEASURE_RECV_H
#include <srslte/srslte.h>
#include "srsue/hdr/phy/phy_common.h"
namespace srsue {
namespace scell {
// Class to perform cell measurements
class measure
{
// TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements
public:
typedef enum { IDLE, MEASURE_OK, ERROR } ret_code;
~measure();
void init(cf_t* buffer[SRSLTE_MAX_PORTS],
srslte::log* log_h,
uint32_t nof_rx_antennas,
phy_common* worker_com,
uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES);
void reset();
void set_cell(srslte_cell_t cell);
ret_code run_subframe(uint32_t sf_idx);
ret_code run_multiple_subframes(cf_t* buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf);
float rssi();
float rsrp();
float rsrq();
float snr();
uint32_t frame_st_idx();
void set_rx_gain_offset(float rx_gain_offset);
private:
srslte::log* log_h;
srslte_ue_dl_t ue_dl;
srslte_ue_dl_cfg_t ue_dl_cfg;
cf_t* buffer[SRSLTE_MAX_PORTS];
uint32_t cnt;
uint32_t nof_subframes;
uint32_t current_prb;
float rx_gain_offset;
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi;
uint32_t final_offset;
const static int RSRP_MEASURE_NOF_FRAMES = 5;
};
} // namespace scell
} // namespace srsue
#endif // SRSUE_MEASURE_RECV_H

@ -0,0 +1,69 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_SCELL_RECV_H
#define SRSUE_SCELL_RECV_H
#include <srslte/common/tti_sync_cv.h>
#include <srslte/srslte.h>
#include <srsue/hdr/phy/scell/measure.h>
namespace srsue {
namespace scell {
// Class to receive secondary cell
class scell_recv
{
public:
const static int MAX_CELLS = 8;
typedef struct {
uint32_t pci;
float rsrp;
float rsrq;
uint32_t offset;
} cell_info_t;
void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com);
void deinit();
void reset();
int find_cells(cf_t* input_buffer,
float rx_gain_offset,
srslte_cell_t current_cell,
uint32_t nof_sf,
cell_info_t found_cells[MAX_CELLS]);
private:
// 36.133 9.1.2.1 for band 7
constexpr static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125;
cf_t* sf_buffer[SRSLTE_MAX_PORTS];
srslte::log* log_h;
srslte_sync_t sync_find;
bool sic_pss_enabled;
uint32_t current_fft_sz;
measure measure_p;
};
} // namespace scell
} // namespace srsue
#endif // SRSUE_SCELL_RECV_H

@ -26,7 +26,6 @@
#include <pthread.h> #include <pthread.h>
#include <srslte/phy/channel/channel.h> #include <srslte/phy/channel/channel.h>
#include "async_scell_recv.h"
#include "phy_common.h" #include "phy_common.h"
#include "prach.h" #include "prach.h"
#include "sf_worker.h" #include "sf_worker.h"
@ -36,6 +35,9 @@
#include "srslte/common/tti_sync_cv.h" #include "srslte/common/tti_sync_cv.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srsue/hdr/phy/scell/async_scell_recv.h"
#include <srsue/hdr/phy/scell/intra_measure.h>
namespace srsue { namespace srsue {
@ -54,7 +56,7 @@ public:
phy_common* _worker_com, phy_common* _worker_com,
srslte::log* _log_h, srslte::log* _log_h,
srslte::log* _log_phy_lib_h, srslte::log* _log_phy_lib_h,
async_scell_recv_vector* scell_sync_, scell::async_recv_vector* scell_sync_,
uint32_t prio, uint32_t prio,
int sync_cpu_affinity = -1); int sync_cpu_affinity = -1);
void stop(); void stop();
@ -138,116 +140,10 @@ private:
srslte_ue_mib_t ue_mib; srslte_ue_mib_t ue_mib;
}; };
// Class to perform cell measurements
class measure {
// TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements
public:
typedef enum {IDLE, MEASURE_OK, ERROR} ret_code;
~measure();
void init(cf_t* buffer[SRSLTE_MAX_PORTS],
srslte::log* log_h,
uint32_t nof_rx_antennas,
phy_common* worker_com,
uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES);
void reset();
void set_cell(srslte_cell_t cell);
ret_code run_subframe(uint32_t sf_idx);
ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf);
float rssi();
float rsrp();
float rsrq();
float snr();
uint32_t frame_st_idx();
void set_rx_gain_offset(float rx_gain_offset);
private:
srslte::log* log_h;
srslte_ue_dl_t ue_dl;
srslte_ue_dl_cfg_t ue_dl_cfg;
cf_t *buffer[SRSLTE_MAX_PORTS];
uint32_t cnt;
uint32_t nof_subframes;
uint32_t current_prb;
float rx_gain_offset;
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi;
uint32_t final_offset;
const static int RSRP_MEASURE_NOF_FRAMES = 5;
};
// Class to receive secondary cell
class scell_recv {
public:
const static int MAX_CELLS = 8;
typedef struct {
uint32_t pci;
float rsrp;
float rsrq;
uint32_t offset;
} cell_info_t;
void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com);
void deinit();
void reset();
int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]);
private:
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
srslte::log *log_h;
srslte_sync_t sync_find;
bool sic_pss_enabled;
uint32_t current_fft_sz;
measure measure_p;
};
/* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search +
* measurements offline using sync object and finding multiple cells for each N_id_2 * measurements offline using sync object and finding multiple cells for each N_id_2
*/ */
// Class to perform intra-frequency measurements
class intra_measure : public thread {
public:
intra_measure();
~intra_measure();
void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h);
void stop();
void add_cell(int pci);
void rem_cell(int pci);
void set_primay_cell(uint32_t earfcn, srslte_cell_t cell);
void clear_cells();
int get_offset(uint32_t pci);
void write(uint32_t tti, cf_t *data, uint32_t nsamples);
private:
void run_thread();
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
scell_recv scell;
rrc_interface_phy_lte* rrc;
srslte::log *log_h;
phy_common* common;
uint32_t current_earfcn;
uint32_t current_sflen;
srslte_cell_t primary_cell;
std::vector<int> active_pci;
srslte::tti_sync_cv tti_sync;
cf_t *search_buffer;
scell_recv::cell_info_t info[scell_recv::MAX_CELLS];
bool running;
bool receive_enabled;
bool receiving;
uint32_t measure_tti;
uint32_t receive_cnt;
srslte_ringbuffer_t ring_buffer;
};
// 36.133 9.1.2.1 for band 7
constexpr static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125;
std::vector<uint32_t> earfcn; std::vector<uint32_t> earfcn;
void reset(); void reset();
@ -267,7 +163,7 @@ private:
// Objects for internal use // Objects for internal use
search search_p; search search_p;
sfn_sync sfn_p; sfn_sync sfn_p;
intra_measure intra_freq_meas; scell::intra_measure intra_freq_meas;
uint32_t current_sflen; uint32_t current_sflen;
int next_offset; // Sample offset triggered by Time aligment commands int next_offset; // Sample offset triggered by Time aligment commands
@ -281,7 +177,7 @@ private:
radio_interface_phy* radio_h; radio_interface_phy* radio_h;
phy_common* worker_com; phy_common* worker_com;
prach* prach_buffer; prach* prach_buffer;
async_scell_recv_vector* scell_sync; scell::async_recv_vector* scell_sync;
srslte::channel_ptr channel_emulator = nullptr; srslte::channel_ptr channel_emulator = nullptr;
// Object for synchronization of the primary cell // Object for synchronization of the primary cell

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
file(GLOB SOURCES "*.cc") file(GLOB_RECURSE SOURCES "*.cc")
add_library(srsue_phy STATIC ${SOURCES}) add_library(srsue_phy STATIC ${SOURCES})
if(ENABLE_GUI AND SRSGUI_FOUND) if(ENABLE_GUI AND SRSGUI_FOUND)

@ -198,7 +198,7 @@ void phy::run_thread()
// Load Asynchronous SCell objects // Load Asynchronous SCell objects
for (int i = 0; i < (int)args.nof_radios - 1; i++) { for (int i = 0; i < (int)args.nof_radios - 1; i++) {
auto t = async_scell_recv_ptr(new async_scell_recv()); auto t = scell::async_recv_ptr(new scell::async_scell_recv());
t->init(radio, &common, log_h); t->init(radio, &common, log_h);
scell_sync.push_back(std::move(t)); scell_sync.push_back(std::move(t));
} }

@ -19,7 +19,7 @@
* *
*/ */
#include "srsue/hdr/phy/async_scell_recv.h" #include "srsue/hdr/phy/scell/async_scell_recv.h"
#include "srsue/hdr/phy/phy_common.h" #include "srsue/hdr/phy/phy_common.h"
#include <srslte/interfaces/ue_interfaces.h> #include <srslte/interfaces/ue_interfaces.h>
#include <srslte/phy/ch_estimation/chest_dl.h> #include <srslte/phy/ch_estimation/chest_dl.h>
@ -44,6 +44,7 @@
#endif #endif
namespace srsue { namespace srsue {
namespace scell {
async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV") async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV")
{ {
@ -617,4 +618,5 @@ void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* n
pthread_mutex_unlock(&mutex_buffer); pthread_mutex_unlock(&mutex_buffer);
} }
} // namespace scell
} // namespace srsue } // namespace srsue

@ -0,0 +1,199 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsue/hdr/phy/scell/intra_measure.h"
#define Error(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->warning(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->debug(fmt, ##__VA_ARGS__)
namespace srsue {
namespace scell {
intra_measure::intra_measure() : scell(), thread("SYNC_INTRA_MEASURE")
{
rrc = nullptr;
common = nullptr;
search_buffer = nullptr;
log_h = nullptr;
current_earfcn = 0;
current_sflen = 0;
measure_tti = 0;
receive_cnt = 0;
running = false;
receive_enabled = false;
receiving = false;
ZERO_OBJECT(info);
ZERO_OBJECT(ring_buffer);
ZERO_OBJECT(primary_cell);
}
intra_measure::~intra_measure()
{
srslte_ringbuffer_free(&ring_buffer);
scell.deinit();
free(search_buffer);
}
void intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h)
{
this->rrc = rrc;
this->log_h = log_h;
this->common = common;
receive_enabled = false;
// Start scell
scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common);
search_buffer =
(cf_t*)srslte_vec_malloc(common->args->intra_freq_meas_len_ms * SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB) * sizeof(cf_t));
if (srslte_ringbuffer_init(
&ring_buffer, sizeof(cf_t) * common->args->intra_freq_meas_len_ms * 2 * SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) {
return;
}
running = true;
start(INTRA_FREQ_MEAS_PRIO);
}
void intra_measure::stop()
{
running = false;
srslte_ringbuffer_stop(&ring_buffer);
tti_sync.increase();
wait_thread_finish();
}
void intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell)
{
this->current_earfcn = earfcn;
current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(cell.nof_prb);
this->primary_cell = cell;
}
void intra_measure::clear_cells()
{
active_pci.clear();
receive_enabled = false;
receiving = false;
receive_cnt = 0;
srslte_ringbuffer_reset(&ring_buffer);
}
void intra_measure::add_cell(int pci)
{
if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) {
active_pci.push_back(pci);
receive_enabled = true;
Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci);
} else {
Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci);
}
}
int intra_measure::get_offset(uint32_t pci)
{
for (auto& i : info) {
if (i.pci == pci) {
return i.offset;
}
}
return -1;
}
void intra_measure::rem_cell(int pci)
{
auto newEnd = std::remove(active_pci.begin(), active_pci.end(), pci);
if (newEnd != active_pci.end()) {
active_pci.erase(newEnd, active_pci.end());
if (active_pci.empty()) {
receive_enabled = false;
}
Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %zu\n", pci, active_pci.size());
} else {
Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci);
}
}
void intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples)
{
if (receive_enabled) {
if ((tti % common->args->intra_freq_meas_period_ms) == 0) {
receiving = true;
receive_cnt = 0;
measure_tti = tti;
srslte_ringbuffer_reset(&ring_buffer);
}
if (receiving) {
if (srslte_ringbuffer_write(&ring_buffer, data, nsamples * sizeof(cf_t)) < (int)(nsamples * sizeof(cf_t))) {
Warning("Error writting to ringbuffer\n");
receiving = false;
} else {
receive_cnt++;
if (receive_cnt == common->args->intra_freq_meas_len_ms) {
tti_sync.increase();
receiving = false;
}
}
}
}
}
void intra_measure::run_thread()
{
while (running) {
if (running) {
tti_sync.wait();
}
if (running) {
// Read data from buffer and find cells in it
srslte_ringbuffer_read(
&ring_buffer, search_buffer, common->args->intra_freq_meas_len_ms * current_sflen * sizeof(cf_t));
int found_cells = scell.find_cells(
search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info);
receiving = false;
for (int i = 0; i < found_cells; i++) {
rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci);
}
// Look for other cells not found automatically
}
}
}
} // namespace scell
} // namespace srsue

@ -0,0 +1,223 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsue/hdr/phy/scell/measure.h"
#define Error(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->warning(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->debug(fmt, ##__VA_ARGS__)
namespace srsue {
namespace scell {
void measure::init(cf_t* buffer[SRSLTE_MAX_PORTS],
srslte::log* log_h,
uint32_t nof_rx_antennas,
phy_common* worker_com,
uint32_t nof_subframes)
{
this->log_h = log_h;
this->nof_subframes = nof_subframes;
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
this->buffer[i] = buffer[i];
}
if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) {
Error("SYNC: Initiating ue_dl_measure\n");
return;
}
worker_com->set_ue_dl_cfg(&ue_dl_cfg);
reset();
}
measure::~measure()
{
srslte_ue_dl_free(&ue_dl);
}
void measure::reset()
{
cnt = 0;
mean_rsrp = 0;
mean_rsrq = 0;
mean_snr = 0;
mean_rssi = 0;
}
void measure::set_cell(srslte_cell_t cell)
{
current_prb = cell.nof_prb;
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
Error("SYNC: Setting cell: initiating ue_dl_measure\n");
}
reset();
}
float measure::rssi()
{
return 10 * log10(mean_rssi);
}
float measure::rsrp()
{
return 10 * log10(mean_rsrp) + 30 - rx_gain_offset;
}
float measure::rsrq()
{
return 10 * log10(mean_rsrq);
}
float measure::snr()
{
return mean_snr;
}
uint32_t measure::frame_st_idx()
{
return final_offset;
}
void measure::set_rx_gain_offset(float rx_gain_offset)
{
this->rx_gain_offset = rx_gain_offset;
}
measure::ret_code measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf)
{
uint32_t sf_len = (uint32_t)SRSLTE_SF_LEN_PRB(current_prb);
ret_code ret = IDLE;
int sf_start = offset - sf_len / 2;
while (sf_start < 0 && sf_idx < max_sf) {
Info("INTRA: sf_start=%d, sf_idx=%d\n", sf_start, sf_idx);
sf_start += sf_len;
sf_idx++;
}
#ifdef FINE_TUNE_OFFSET_WITH_RS
float max_rsrp = -200;
int best_test_sf_start = 0;
int test_sf_start = 0;
bool found_best = false;
// Fine-tune sf_start using RS
for (uint32_t n = 0; n < 5; n++) {
test_sf_start = sf_start - 2 + n;
if (test_sf_start >= 0) {
cf_t* buf_m[SRSLTE_MAX_PORTS];
buf_m[0] = &input_buffer[test_sf_start];
uint32_t cfi;
if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) {
Error("MEAS: Measuring RSRP: Estimating channel\n");
return ERROR;
}
float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest);
if (rsrp > max_rsrp) {
max_rsrp = rsrp;
best_test_sf_start = test_sf_start;
found_best = true;
}
}
}
Debug("INTRA: fine-tuning sf_start: %d, found_best=%d, rem_sf=%d\n", sf_start, found_best, nof_sf);
sf_start = found_best ? best_test_sf_start : sf_start;
#endif
if (sf_start >= 0 && sf_start < (int)(sf_len * max_sf)) {
uint32_t nof_sf = (sf_len * max_sf - sf_start) / sf_len;
final_offset = (uint32_t)sf_start;
for (uint32_t i = 0; i < nof_sf; i++) {
memcpy(buffer[0], &input_buffer[sf_start + i * sf_len], sizeof(cf_t) * sf_len);
ret = run_subframe((sf_idx + i) % 10);
if (ret != IDLE) {
return ret;
}
}
if (ret != ERROR) {
return MEASURE_OK;
}
} else {
Error("INTRA: not running because sf_start=%d, offset=%d, sf_len*max_sf=%d*%d\n", sf_start, offset, sf_len, max_sf);
ret = ERROR;
}
return ret;
}
measure::ret_code measure::run_subframe(uint32_t sf_idx)
{
srslte_dl_sf_cfg_t sf_cfg;
ZERO_OBJECT(sf_cfg);
sf_cfg.tti = sf_idx;
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg, &ue_dl_cfg)) {
log_h->error("SYNC: Measuring RSRP: Estimating channel\n");
return ERROR;
}
float rsrp = ue_dl.chest_res.rsrp;
float rsrq = ue_dl.chest_res.rsrq;
float snr = ue_dl.chest_res.snr_db;
float rssi = srslte_vec_avg_power_cf(buffer[0], (uint32_t)SRSLTE_SF_LEN_PRB(current_prb));
if (cnt == 0) {
mean_rsrp = rsrp;
mean_rsrq = rsrq;
mean_snr = snr;
mean_rssi = rssi;
} else {
mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt);
mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt);
mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt);
mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt);
}
cnt++;
log_h->debug(
"SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", cnt, nof_subframes, sf_idx, rsrp, snr);
if (cnt >= nof_subframes) {
return MEASURE_OK;
} else {
return IDLE;
}
}
} // namespace scell
} // namespace srsue

@ -0,0 +1,245 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsue/hdr/phy/scell/scell_recv.h"
#define Error(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->warning(fmt, ##__VA_ARGS__)
#define Info(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) \
if (SRSLTE_DEBUG_ENABLED) \
log_h->debug(fmt, ##__VA_ARGS__)
namespace srsue {
namespace scell {
/**********
* Secondary cell receiver
*/
void scell_recv::init(srslte::log* _log_h, bool _sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com)
{
log_h = _log_h;
sic_pss_enabled = _sic_pss_enabled;
// and a separate ue_sync instance
uint32_t max_fft_sz = srslte_symbol_sz(100);
uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz);
sf_buffer[0] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * max_sf_size);
if (!sf_buffer[0]) {
ERROR("Error allocating %d samples for scell\n", max_sf_size);
return;
}
measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window);
// do this different we don't need all this search window.
if (srslte_sync_init(&sync_find, max_sf_window * max_sf_size, 5 * max_sf_size, max_fft_sz)) {
ERROR("Error initiating sync_find\n");
return;
}
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
srslte_sync_cp_en(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_threshold(&sync_find, 1.7);
srslte_sync_set_em_alpha(&sync_find, 0.3);
// Configure FIND object behaviour (this configuration is always the same)
srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0);
srslte_sync_set_cfo_i_enable(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_pss_filt_enable(&sync_find, true);
srslte_sync_set_sss_eq_enable(&sync_find, true);
sync_find.pss.chest_on_filter = true;
sync_find.sss_channel_equalize = false;
reset();
}
void scell_recv::deinit()
{
srslte_sync_free(&sync_find);
free(sf_buffer[0]);
}
void scell_recv::reset()
{
current_fft_sz = 0;
measure_p.reset();
}
int scell_recv::find_cells(
cf_t* input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS])
{
uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb);
uint32_t sf_len = SRSLTE_SF_LEN(fft_sz);
if (fft_sz != current_fft_sz) {
if (srslte_sync_resize(&sync_find, nof_sf * sf_len, 5 * sf_len, fft_sz)) {
ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz);
return SRSLTE_ERROR;
}
current_fft_sz = fft_sz;
}
int nof_cells = 0;
uint32_t peak_idx = 0;
uint32_t sf_idx = 0;
int cell_id = 0;
srslte_cell_t found_cell;
found_cell = cell;
measure_p.set_rx_gain_offset(rx_gain_offset);
for (uint32_t n_id_2 = 0; n_id_2 < 3; n_id_2++) {
found_cell.id = 10000;
if (n_id_2 != (cell.id % 3) || sic_pss_enabled) {
srslte_sync_set_N_id_2(&sync_find, n_id_2);
srslte_sync_find_ret_t sync_res;
do {
srslte_sync_reset(&sync_find);
srslte_sync_cfo_reset(&sync_find);
sync_res = SRSLTE_SYNC_NOFOUND;
cell_id = 0;
float max_peak = -1;
uint32_t max_sf5 = 0;
uint32_t max_sf_idx = 0;
for (uint32_t sf5_cnt = 0; sf5_cnt < nof_sf / 5; sf5_cnt++) {
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt * 5 * sf_len, &peak_idx);
Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n",
n_id_2,
sf5_cnt,
nof_sf / 5,
sync_res,
srslte_sync_get_sf_idx(&sync_find),
peak_idx,
sync_find.peak_value);
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
max_sf5 = sf5_cnt;
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
cell_id = srslte_sync_get_cell_id(&sync_find);
}
}
switch (sync_res) {
case SRSLTE_SYNC_ERROR:
return SRSLTE_ERROR;
ERROR("Error finding correlation peak\n");
return SRSLTE_ERROR;
case SRSLTE_SYNC_FOUND:
sf_idx = (10 - max_sf_idx - 5 * (max_sf5 % 2)) % 10;
if (cell_id >= 0) {
// We found the same cell as before, look another N_id_2
if ((uint32_t)cell_id == found_cell.id || (uint32_t)cell_id == cell.id) {
Debug("INTRA: n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n",
n_id_2,
cell_id,
found_cell.id,
cell.id);
sync_res = SRSLTE_SYNC_NOFOUND;
} else {
// We found a new cell ID
found_cell.id = (uint32_t)cell_id;
found_cell.nof_ports = 1; // Use port 0 only for measurement
measure_p.set_cell(found_cell);
// Correct CFO
/*
srslte_cfo_correct(&sync_find.cfo_corr_frame,
input_buffer,
input_cfo_corrected,
-srslte_sync_get_cfo(&sync_find)/sync_find.fft_size);
*/
switch (measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) {
default:
// Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition
if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) {
cells[nof_cells].pci = found_cell.id;
cells[nof_cells].rsrp = measure_p.rsrp();
cells[nof_cells].rsrq = measure_p.rsrq();
cells[nof_cells].offset = measure_p.frame_st_idx();
Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, "
"sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n",
nof_cells,
cell_id,
measure_p.rsrp(),
measure_p.frame_st_idx(),
sync_find.peak_value,
sf_idx,
max_sf5,
n_id_2,
15000 * srslte_sync_get_cfo(&sync_find));
nof_cells++;
/*
if (sic_pss_enabled) {
srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]);
}*/
} else {
Info("INTRA: Found neighbour cell but RSRP=%.1f dBm is below threshold (%.1f dBm)\n",
measure_p.rsrp(),
ABSOLUTE_RSRP_THRESHOLD_DBM);
}
break;
case measure::ERROR:
Error("INTRA: Measuring neighbour cell\n");
return SRSLTE_ERROR;
}
}
} else {
sync_res = SRSLTE_SYNC_NOFOUND;
}
break;
case SRSLTE_SYNC_FOUND_NOSPACE:
/* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */
break;
default:
break;
}
} while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled && nof_cells < MAX_CELLS);
}
}
return nof_cells;
}
} // namespace scell
} // namespace srsue

@ -67,7 +67,7 @@ void sync::init(radio_interface_phy* _radio,
phy_common* _worker_com, phy_common* _worker_com,
srslte::log* _log_h, srslte::log* _log_h,
srslte::log* _log_phy_lib_h, srslte::log* _log_phy_lib_h,
async_scell_recv_vector* scell_sync_, scell::async_recv_vector* scell_sync_,
uint32_t prio, uint32_t prio,
int sync_cpu_affinity) int sync_cpu_affinity)
{ {
@ -1250,388 +1250,6 @@ sync::sfn_sync::decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, cf_t* ext_buf
return IDLE; return IDLE;
} }
/*********
* Measurement class
*/
void sync::measure::init(cf_t* buffer[SRSLTE_MAX_PORTS],
srslte::log* log_h,
uint32_t nof_rx_antennas,
phy_common* worker_com,
uint32_t nof_subframes)
{
this->log_h = log_h;
this->nof_subframes = nof_subframes;
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
this->buffer[i] = buffer[i];
}
if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) {
Error("SYNC: Initiating ue_dl_measure\n");
return;
}
worker_com->set_ue_dl_cfg(&ue_dl_cfg);
reset();
}
sync::measure::~measure()
{
srslte_ue_dl_free(&ue_dl);
}
void sync::measure::reset()
{
cnt = 0;
mean_rsrp = 0;
mean_rsrq = 0;
mean_snr = 0;
mean_rssi = 0;
}
void sync::measure::set_cell(srslte_cell_t cell)
{
current_prb = cell.nof_prb;
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
Error("SYNC: Setting cell: initiating ue_dl_measure\n");
}
reset();
}
float sync::measure::rssi()
{
return 10*log10(mean_rssi);
}
float sync::measure::rsrp()
{
return 10*log10(mean_rsrp) + 30 - rx_gain_offset;
}
float sync::measure::rsrq()
{
return 10*log10(mean_rsrq);
}
float sync::measure::snr()
{
return mean_snr;
}
uint32_t sync::measure::frame_st_idx()
{
return final_offset;
}
void sync::measure::set_rx_gain_offset(float rx_gain_offset)
{
this->rx_gain_offset = rx_gain_offset;
}
sync::measure::ret_code
sync::measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf)
{
uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb);
ret_code ret = IDLE;
int sf_start = offset-sf_len/2;
while (sf_start < 0 && sf_idx < max_sf) {
Info("INTRA: sf_start=%d, sf_idx=%d\n", sf_start, sf_idx);
sf_start += sf_len;
sf_idx ++;
}
#ifdef FINE_TUNE_OFFSET_WITH_RS
float max_rsrp = -200;
int best_test_sf_start = 0;
int test_sf_start = 0;
bool found_best = false;
// Fine-tune sf_start using RS
for (uint32_t n=0;n<5;n++) {
test_sf_start = sf_start-2+n;
if (test_sf_start >= 0) {
cf_t *buf_m[SRSLTE_MAX_PORTS];
buf_m[0] = &input_buffer[test_sf_start];
uint32_t cfi;
if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) {
Error("MEAS: Measuring RSRP: Estimating channel\n");
return ERROR;
}
float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest);
if (rsrp > max_rsrp) {
max_rsrp = rsrp;
best_test_sf_start = test_sf_start;
found_best = true;
}
}
}
Debug("INTRA: fine-tuning sf_start: %d, found_best=%d, rem_sf=%d\n", sf_start, found_best, nof_sf);
sf_start = found_best?best_test_sf_start:sf_start;
#endif
if (sf_start >= 0 && sf_start < (int) (sf_len*max_sf)) {
uint32_t nof_sf = (sf_len*max_sf - sf_start)/sf_len;
final_offset = sf_start;
for (uint32_t i=0;i<nof_sf;i++) {
memcpy(buffer[0], &input_buffer[sf_start+i*sf_len], sizeof(cf_t)*sf_len);
ret = run_subframe((sf_idx+i)%10);
if (ret != IDLE) {
return ret;
}
}
if (ret != ERROR) {
return MEASURE_OK;
}
} else {
Error("INTRA: not running because sf_start=%d, offset=%d, sf_len*max_sf=%d*%d\n", sf_start, offset, sf_len, max_sf);
ret = ERROR;
}
return ret;
}
sync::measure::ret_code sync::measure::run_subframe(uint32_t sf_idx)
{
srslte_dl_sf_cfg_t sf_cfg;
ZERO_OBJECT(sf_cfg);
sf_cfg.tti = sf_idx;
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg, &ue_dl_cfg)) {
log_h->error("SYNC: Measuring RSRP: Estimating channel\n");
return ERROR;
}
float rsrp = ue_dl.chest_res.rsrp;
float rsrq = ue_dl.chest_res.rsrq;
float snr = ue_dl.chest_res.snr_db;
float rssi = srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb));
if (cnt == 0) {
mean_rsrp = rsrp;
mean_rsrq = rsrq;
mean_snr = snr;
mean_rssi = rssi;
} else {
mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt);
mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt);
mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt);
mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt);
}
cnt++;
log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n",
cnt, nof_subframes, sf_idx, rsrp, snr);
if (cnt >= nof_subframes) {
return MEASURE_OK;
} else {
return IDLE;
}
}
/**********
* Secondary cell receiver
*/
void sync::scell_recv::init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com)
{
this->log_h = log_h;
this->sic_pss_enabled = sic_pss_enabled;
// and a separate ue_sync instance
uint32_t max_fft_sz = srslte_symbol_sz(100);
uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz);
sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size);
if (!sf_buffer[0]) {
ERROR("Error allocating %d samples for scell\n", max_sf_size);
return;
}
measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window);
//do this different we don't need all this search window.
if(srslte_sync_init(&sync_find, max_sf_window*max_sf_size, 5*max_sf_size, max_fft_sz)) {
ERROR("Error initiating sync_find\n");
return;
}
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
srslte_sync_cp_en(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_threshold(&sync_find, 1.7);
srslte_sync_set_em_alpha(&sync_find, 0.3);
// Configure FIND object behaviour (this configuration is always the same)
srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0);
srslte_sync_set_cfo_i_enable(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_pss_filt_enable(&sync_find, true);
srslte_sync_set_sss_eq_enable(&sync_find, true);
sync_find.pss.chest_on_filter = true;
sync_find.sss_channel_equalize = false;
reset();
}
void sync::scell_recv::deinit()
{
srslte_sync_free(&sync_find);
free(sf_buffer[0]);
}
void sync::scell_recv::reset()
{
current_fft_sz = 0;
measure_p.reset();
}
int sync::scell_recv::find_cells(
cf_t* input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS])
{
uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb);
uint32_t sf_len = SRSLTE_SF_LEN(fft_sz);
if (fft_sz != current_fft_sz) {
if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) {
ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz);
return SRSLTE_ERROR;
}
current_fft_sz = fft_sz;
}
int nof_cells = 0;
uint32_t peak_idx = 0;
uint32_t sf_idx = 0;
int cell_id = 0;
srslte_cell_t found_cell;
found_cell = cell;
measure_p.set_rx_gain_offset(rx_gain_offset);
for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) {
found_cell.id = 10000;
if (n_id_2 != (cell.id%3) || sic_pss_enabled) {
srslte_sync_set_N_id_2(&sync_find, n_id_2);
srslte_sync_find_ret_t sync_res;
do {
srslte_sync_reset(&sync_find);
srslte_sync_cfo_reset(&sync_find);
sync_res = SRSLTE_SYNC_NOFOUND;
cell_id = 0;
float max_peak = -1;
uint32_t max_sf5 = 0;
uint32_t max_sf_idx = 0;
for (uint32_t sf5_cnt=0;sf5_cnt<nof_sf/5;sf5_cnt++) {
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx);
Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n",
n_id_2, sf5_cnt, nof_sf/5, sync_res, srslte_sync_get_sf_idx(&sync_find), peak_idx, sync_find.peak_value);
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
max_sf5 = sf5_cnt;
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
cell_id = srslte_sync_get_cell_id(&sync_find);
}
}
switch(sync_res) {
case SRSLTE_SYNC_ERROR:
return SRSLTE_ERROR;
ERROR("Error finding correlation peak\n");
return SRSLTE_ERROR;
case SRSLTE_SYNC_FOUND:
sf_idx = (10-max_sf_idx - 5*(max_sf5%2))%10;
if (cell_id >= 0) {
// We found the same cell as before, look another N_id_2
if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) {
Debug("INTRA: n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n", n_id_2, cell_id, found_cell.id, cell.id);
sync_res = SRSLTE_SYNC_NOFOUND;
} else {
// We found a new cell ID
found_cell.id = cell_id;
found_cell.nof_ports = 1; // Use port 0 only for measurement
measure_p.set_cell(found_cell);
// Correct CFO
/*
srslte_cfo_correct(&sync_find.cfo_corr_frame,
input_buffer,
input_cfo_corrected,
-srslte_sync_get_cfo(&sync_find)/sync_find.fft_size);
*/
switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf))
{
default:
// Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition
if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) {
cells[nof_cells].pci = found_cell.id;
cells[nof_cells].rsrp = measure_p.rsrp();
cells[nof_cells].rsrq = measure_p.rsrq();
cells[nof_cells].offset = measure_p.frame_st_idx();
Info(
"INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n",
nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value,
sf_idx, max_sf5, n_id_2, 15000 * srslte_sync_get_cfo(&sync_find));
nof_cells++;
/*
if (sic_pss_enabled) {
srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]);
}*/
} else {
Info("INTRA: Found neighbour cell but RSRP=%.1f dBm is below threshold (%.1f dBm)\n",
measure_p.rsrp(), ABSOLUTE_RSRP_THRESHOLD_DBM);
}
break;
case measure::ERROR:
Error("INTRA: Measuring neighbour cell\n");
return SRSLTE_ERROR;
}
}
} else {
sync_res = SRSLTE_SYNC_NOFOUND;
}
break;
case SRSLTE_SYNC_FOUND_NOSPACE:
/* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */
break;
default:
break;
}
} while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled && nof_cells < MAX_CELLS);
}
}
return nof_cells;
}
/********** /**********
* PHY measurements * PHY measurements
* *
@ -1669,159 +1287,4 @@ int sync::meas_stop(uint32_t earfcn, int pci)
return -1; return -1;
} }
sync::intra_measure::intra_measure() : scell(), thread("SYNC_INTRA_MEASURE")
{
rrc = NULL;
common = NULL;
search_buffer = NULL;
log_h = NULL;
current_earfcn = 0;
current_sflen = 0;
measure_tti = 0;
receive_cnt = 0;
running = false;
receive_enabled = false;
receiving = false;
ZERO_OBJECT(info);
ZERO_OBJECT(ring_buffer);
ZERO_OBJECT(primary_cell);
}
sync::intra_measure::~intra_measure()
{
srslte_ringbuffer_free(&ring_buffer);
scell.deinit();
free(search_buffer);
}
void sync::intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h)
{
this->rrc = rrc;
this->log_h = log_h;
this->common = common;
receive_enabled = false;
// Start scell
scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common);
search_buffer = (cf_t*) srslte_vec_malloc(common->args->intra_freq_meas_len_ms*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t));
if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*common->args->intra_freq_meas_len_ms*2*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) {
return;
}
running = true;
start(INTRA_FREQ_MEAS_PRIO);
}
void sync::intra_measure::stop()
{
running = false;
srslte_ringbuffer_stop(&ring_buffer);
tti_sync.increase();
wait_thread_finish();
}
void sync::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell)
{
this->current_earfcn = earfcn;
current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb);
this->primary_cell = cell;
}
void sync::intra_measure::clear_cells()
{
active_pci.clear();
receive_enabled = false;
receiving = false;
receive_cnt = 0;
srslte_ringbuffer_reset(&ring_buffer);
}
void sync::intra_measure::add_cell(int pci)
{
if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) {
active_pci.push_back(pci);
receive_enabled = true;
Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci);
} else {
Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci);
}
}
int sync::intra_measure::get_offset(uint32_t pci)
{
for (int i=0;i<scell_recv::MAX_CELLS;i++) {
if (info[i].pci == pci) {
return info[i].offset;
}
}
return -1;
}
void sync::intra_measure::rem_cell(int pci)
{
std::vector<int>::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci);
if (newEnd != active_pci.end()) {
active_pci.erase(newEnd, active_pci.end());
if (active_pci.size() == 0) {
receive_enabled = false;
}
Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %zu\n", pci, active_pci.size());
} else {
Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci);
}
}
void sync::intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples)
{
if (receive_enabled) {
if ((tti%common->args->intra_freq_meas_period_ms) == 0) {
receiving = true;
receive_cnt = 0;
measure_tti = tti;
srslte_ringbuffer_reset(&ring_buffer);
}
if (receiving == true) {
if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) {
Warning("Error writting to ringbuffer\n");
receiving = false;
} else {
receive_cnt++;
if (receive_cnt == common->args->intra_freq_meas_len_ms) {
tti_sync.increase();
receiving = false;
}
}
}
}
}
void sync::intra_measure::run_thread()
{
while(running) {
if (running) {
tti_sync.wait();
}
if (running) {
// Read data from buffer and find cells in it
srslte_ringbuffer_read(&ring_buffer, search_buffer, common->args->intra_freq_meas_len_ms*current_sflen*sizeof(cf_t));
int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info);
receiving = false;
for (int i=0;i<found_cells;i++) {
rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci);
}
// Look for other cells not found automatically
}
}
}
} }

Loading…
Cancel
Save