SRSUE: CA can be performed without requiring clock synchronization between RF devices. Added Asynchronous SCell Synch metrics to console trace

This commit is contained in:
Xavier Arteaga 2019-05-17 13:03:29 +02:00 committed by Andre Puschmann
parent 080b4a327c
commit 0b6efb657e
11 changed files with 122 additions and 39 deletions

View File

@ -58,6 +58,8 @@ public:
void out_of_sync();
void set_cfo(float cfo);
float get_tx_cfo();
// From UE configuration
void set_agc_enable(bool enable);
bool set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell, uint32_t dl_earfcn);
@ -68,7 +70,7 @@ public:
double set_rx_gain(double gain);
int radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time);
bool tti_align(uint32_t tti);
void read_sf(cf_t** dst, srslte_timestamp_t* timestamp);
void read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* next_offset);
private:
class phch_scell_recv_buffer
@ -76,12 +78,14 @@ private:
private:
uint32_t tti;
srslte_timestamp_t timestamp;
int next_offset;
cf_t* buffer[SRSLTE_MAX_PORTS];
public:
phch_scell_recv_buffer()
{
tti = 0;
next_offset = 0;
bzero(&timestamp, sizeof(timestamp));
for (cf_t*& b : buffer) {
b = nullptr;
@ -108,9 +112,10 @@ private:
}
}
void set_sf(uint32_t _tti, srslte_timestamp_t* _timestamp)
void set_sf(uint32_t _tti, srslte_timestamp_t* _timestamp, const int& _next_offset)
{
tti = _tti;
next_offset = _next_offset;
srslte_timestamp_copy(&timestamp, _timestamp);
}
@ -119,6 +124,11 @@ private:
cf_t** get_buffer_ptr() { return buffer; }
void get_timestamp(srslte_timestamp_t* _timestamp) { srslte_timestamp_copy(_timestamp, &timestamp); }
void get_next_offset(int* _next_offset)
{
if (_next_offset)
*_next_offset = next_offset;
}
};
static const uint32_t ASYNC_NOF_BUFFERS = SRSLTE_NOF_SF_X_FRAME;
@ -165,6 +175,8 @@ private:
uint32_t in_sync_cnt;
cf_t* sf_buffer[SRSLTE_MAX_PORTS];
uint32_t current_sflen;
int next_radio_offset;
const static uint32_t NOF_OUT_OF_SYNC_SF = 200;
const static uint32_t NOF_IN_SYNC_SF = 100;

View File

@ -150,8 +150,8 @@ public:
void get_dl_metrics(dl_metrics_t m[SRSLTE_MAX_CARRIERS]);
void set_ul_metrics(const ul_metrics_t m, uint32_t cc_idx);
void get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_CARRIERS]);
void set_sync_metrics(const sync_metrics_t& m);
void get_sync_metrics(sync_metrics_t& m);
void set_sync_metrics(const uint32_t& cc_idx, const sync_metrics_t& m);
void get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS]);
void reset();
@ -223,7 +223,7 @@ private:
ul_metrics_t ul_metrics[SRSLTE_MAX_CARRIERS];
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
sync_metrics_t sync_metrics[SRSLTE_MAX_CARRIERS];
uint32_t sync_metrics_count;
bool sync_metrics_read;

View File

@ -55,7 +55,7 @@ struct ul_metrics_t
struct phy_metrics_t
{
sync_metrics_t sync;
sync_metrics_t sync[SRSLTE_MAX_CARRIERS];
dl_metrics_t dl[SRSLTE_MAX_CARRIERS];
ul_metrics_t ul[SRSLTE_MAX_CARRIERS];
uint32_t nof_active_cc;

View File

@ -53,7 +53,7 @@ public:
void set_tti(uint32_t tti, uint32_t tx_worker_cnt);
void set_tx_time(uint32_t radio_idx, srslte_timestamp_t tx_time, int next_offset);
void set_prach(cf_t* prach_ptr, float prach_power);
void set_cfo(float cfo);
void set_cfo(const uint32_t& cc_idx, float cfo);
void set_tdd_config(srslte_tdd_config_t config);
void set_pcell_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg);

View File

@ -269,7 +269,8 @@ private:
intra_measure intra_freq_meas;
uint32_t current_sflen;
int next_offset;
int next_offset; // Sample offset triggered by Time aligment commands
int next_radio_offset[SRSLTE_MAX_RADIOS]; // Sample offset triggered by SFO compensation
// Pointers to other classes
stack_interface_phy_lte* stack;

View File

@ -79,7 +79,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
// Print PHY metrics for first CC
file << float_to_string(metrics.phy.dl[0].rsrp, 2);
file << float_to_string(metrics.phy.dl[0].pathloss, 2);
file << float_to_string(metrics.phy.sync.cfo, 2);
file << float_to_string(metrics.phy.sync[0].cfo, 2);
file << float_to_string(metrics.phy.dl[0].mcs, 2);
file << float_to_string(metrics.phy.dl[0].sinr, 2);
file << float_to_string(metrics.phy.dl[0].turbo_iters, 2);
@ -104,7 +104,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
file << float_to_string(0, 2);
}
file << float_to_string(metrics.phy.sync.ta_us, 2);
file << float_to_string(metrics.phy.sync[0].ta_us, 2);
file << float_to_string(metrics.phy.ul[0].mcs, 2);
file << float_to_string((float)metrics.stack.mac[0].ul_buffer, 2);

View File

@ -79,7 +79,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us
cout << " " << r;
cout << float_to_string(metrics.phy.dl[r].rsrp, 2);
cout << float_to_string(metrics.phy.dl[r].pathloss, 2);
cout << float_to_eng_string(metrics.phy.sync.cfo, 2);
cout << float_to_eng_string(metrics.phy.sync[r].cfo, 2);
cout << float_to_string(metrics.phy.dl[r].mcs, 2);
cout << float_to_string(metrics.phy.dl[r].sinr, 2);
cout << float_to_string(metrics.phy.dl[r].turbo_iters, 2);
@ -91,7 +91,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us
cout << float_to_string(0, 1) << "%";
}
cout << float_to_string(metrics.phy.sync.ta_us, 2);
cout << float_to_string(metrics.phy.sync[r].ta_us, 2);
cout << float_to_string(metrics.phy.ul[r].mcs, 2);
cout << float_to_eng_string((float)metrics.stack.mac[r].ul_buffer, 2);

View File

@ -56,6 +56,8 @@ async_scell_recv::async_scell_recv() : thread()
bzero(sf_buffer, sizeof(sf_buffer));
running = false;
radio_idx = 1;
current_sflen = 0;
next_radio_offset = 0;
}
async_scell_recv::~async_scell_recv()
@ -160,6 +162,25 @@ void async_scell_recv::set_cfo(float cfo)
srslte_ue_sync_set_cfo_ref(&ue_sync, cfo);
}
float async_scell_recv::get_tx_cfo()
{
float cfo = srslte_ue_sync_get_cfo(&ue_sync);
float ret = cfo * ul_dl_factor;
if (worker_com->args->cfo_is_doppler) {
ret *= -1;
} else {
/* Compensates the radio frequency offset applied equally to DL and UL. Does not work in doppler mode */
if (radio_h->get_freq_offset() != 0.0f) {
const float offset_hz = (float)radio_h->get_freq_offset() * (1.0f - ul_dl_factor);
ret = cfo - offset_hz;
}
}
return ret / 15000;
}
void async_scell_recv::set_agc_enable(bool enable)
{
do_agc = enable;
@ -187,6 +208,13 @@ int async_scell_recv::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsam
if (running) {
if (radio_h->rx_now(radio_idx, data, nsamples, rx_time)) {
int offset = nsamples - current_sflen;
if (abs(offset) < 10 && offset != 0) {
next_radio_offset += offset;
} else if (nsamples < 10) {
next_radio_offset += nsamples;
}
log_h->debug("SYNC: received %d samples from radio\n", nsamples);
ret = nsamples;
} else {
@ -288,6 +316,8 @@ bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell
double srate = srslte_sampling_freq_hz(_cell->nof_prb);
radio_h->set_rx_srate(radio_idx, srate);
radio_h->set_tx_srate(radio_idx, srate);
current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(_cell->nof_prb);
Info("Setting SRate to %.2f MHz\n", srate / 1e6);
}
@ -385,7 +415,8 @@ void async_scell_recv::state_write_buffer()
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
// Extract essential information
buffer->set_sf(tti, &rx_time);
buffer->set_sf(tti, &rx_time, next_radio_offset);
next_radio_offset = 0;
// Increment write index
buffer_write_idx = (buffer_write_idx + 1) % ASYNC_NOF_BUFFERS;
@ -448,6 +479,17 @@ void async_scell_recv::run_thread()
break;
}
// Load metrics
sync_metrics_t metrics = {};
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
metrics.ta_us = NAN;
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
if (worker_com->args->carrier_map[i].radio_idx == radio_idx) {
worker_com->set_sync_metrics(i, metrics);
}
}
// Increment tti
tti = (tti + 1) % 10240;
} else if (ret == 0) {
@ -533,7 +575,7 @@ bool async_scell_recv::tti_align(uint32_t tti)
return ret;
}
void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp)
void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* next_offset)
{
pthread_mutex_lock(&mutex_buffer);
@ -567,6 +609,7 @@ void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp)
}
buffer->get_timestamp(timestamp);
buffer->get_next_offset(next_offset);
// Increment read index
buffer_read_idx = (buffer_read_idx + 1) % ASYNC_NOF_BUFFERS;

View File

@ -68,7 +68,7 @@ phy_common::phy_common(uint32_t max_workers) : tx_sem(max_workers)
bzero(&ul_metrics, sizeof(ul_metrics_t) * SRSLTE_MAX_CARRIERS);
ul_metrics_read = true;
ul_metrics_count = 0;
bzero(&sync_metrics, sizeof(sync_metrics_t));
ZERO_OBJECT(sync_metrics);
sync_metrics_read = true;
sync_metrics_count = 0;
@ -643,23 +643,26 @@ void phy_common::get_ul_metrics(ul_metrics_t m[SRSLTE_MAX_RADIOS])
ul_metrics_read = true;
}
void phy_common::set_sync_metrics(const sync_metrics_t& m)
void phy_common::set_sync_metrics(const uint32_t& cc_idx, const sync_metrics_t& m)
{
if (sync_metrics_read) {
sync_metrics = m;
sync_metrics[cc_idx] = m;
sync_metrics_count = 1;
sync_metrics_read = false;
if (cc_idx == 0)
sync_metrics_read = false;
} else {
sync_metrics_count++;
sync_metrics.cfo = sync_metrics.cfo + (m.cfo - sync_metrics.cfo) / sync_metrics_count;
sync_metrics.sfo = sync_metrics.sfo + (m.sfo - sync_metrics.sfo) / sync_metrics_count;
if (cc_idx == 0)
sync_metrics_count++;
sync_metrics[cc_idx].cfo = sync_metrics[cc_idx].cfo + (m.cfo - sync_metrics[cc_idx].cfo) / sync_metrics_count;
sync_metrics[cc_idx].sfo = sync_metrics[cc_idx].sfo + (m.sfo - sync_metrics[cc_idx].sfo) / sync_metrics_count;
}
}
void phy_common::get_sync_metrics(sync_metrics_t& m)
void phy_common::get_sync_metrics(sync_metrics_t m[SRSLTE_MAX_CARRIERS])
{
m = sync_metrics;
for (uint32_t i = 0; i < args->nof_carriers; i++) {
m[i] = sync_metrics[i];
}
sync_metrics_read = true;
}

View File

@ -158,11 +158,9 @@ void sf_worker::set_prach(cf_t* prach_ptr, float prach_power)
this->prach_power = prach_power;
}
void sf_worker::set_cfo(float cfo)
void sf_worker::set_cfo(const uint32_t& cc_idx, float cfo)
{
for (uint32_t cc_idx = 0; cc_idx < cc_workers.size(); cc_idx++) {
cc_workers[cc_idx]->set_cfo(cfo);
}
cc_workers[cc_idx]->set_cfo(cfo);
}
void sf_worker::set_crnti(uint16_t rnti)
@ -402,9 +400,9 @@ float sf_worker::get_sync_error()
float sf_worker::get_cfo()
{
sync_metrics_t sync_metrics = {};
sync_metrics_t sync_metrics[SRSLTE_MAX_CARRIERS] = {};
phy->get_sync_metrics(sync_metrics);
return sync_metrics.cfo;
return sync_metrics[0].cfo;
}
} // namespace srsue

View File

@ -147,6 +147,7 @@ void sync::reset()
tx_worker_cnt = 0;
time_adv_sec = 0;
next_offset = 0;
ZERO_OBJECT(next_radio_offset);
srate_mode = SRATE_NONE;
current_earfcn = -1;
sfn_p.reset();
@ -477,20 +478,24 @@ void sync::run_thread()
// Request TTI aligment
if (scell_sync->at(i)->tti_align(tti)) {
scell_sync->at(i)->read_sf(buffer[i + 1], &tx_time);
scell_sync->at(i)->read_sf(buffer[i + 1], &tx_time, &next_radio_offset[i + 1]);
srslte_timestamp_add(&tx_time, 0, TX_DELAY * 1e-3 - time_adv_sec);
} else {
// Failed, keep default Timestamp
// Error("SCell asynchronous failed to synchronise (%d)\n", i);
}
worker->set_tx_time(i + 1, tx_time, next_offset);
worker->set_tx_time(i + 1, tx_time, next_radio_offset[i + 1] + next_offset);
}
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
metrics.ta_us = time_adv_sec*1e6;
worker_com->set_sync_metrics(metrics);
metrics.ta_us = time_adv_sec * 1e6f;
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
if (worker_com->args->carrier_map[i].radio_idx == 0) {
worker_com->set_sync_metrics(i, metrics);
}
}
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
@ -511,10 +516,31 @@ void sync::run_thread()
}
worker->set_prach(prach_ptr?&prach_ptr[prach_sf_cnt*SRSLTE_SF_LEN_PRB(cell.nof_prb)]:NULL, prach_power);
worker->set_cfo(get_tx_cfo());
// Set CFO for all Carriers
for (uint32_t cc = 0; cc < worker_com->args->nof_carriers; cc++) {
float cfo;
// Get radio index for the given carrier
uint32_t radio_idx = worker_com->args->carrier_map[cc].radio_idx;
if (radio_idx == 0) {
// Use local CFO
cfo = get_tx_cfo();
} else {
// Request CFO in the asynchronous receiver
cfo = scell_sync->at(radio_idx - 1)->get_tx_cfo();
}
worker->set_cfo(cc, cfo);
}
worker->set_tti(tti, tx_worker_cnt);
worker->set_tx_time(0, tx_time, next_offset);
worker->set_tx_time(0, tx_time, next_radio_offset[0] + next_offset);
next_offset = 0;
ZERO_OBJECT(next_radio_offset);
// Process time aligment command
if (next_time_adv_sec != time_adv_sec) {
time_adv_sec = next_time_adv_sec;
}
@ -867,7 +893,7 @@ bool sync::set_frequency()
void sync::set_sampling_rate()
{
float new_srate = (float)srslte_sampling_freq_hz(cell.nof_prb);
current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb);
current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(cell.nof_prb);
if (current_srate != new_srate || srate_mode != SRATE_CAMP) {
current_srate = new_srate;
Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate/1000000);
@ -900,9 +926,9 @@ int sync::radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte
if (radio_h->rx_now(0, data, nsamples, rx_time)) {
int offset = nsamples - current_sflen;
if (abs(offset) < 10 && offset != 0) {
next_offset += offset;
next_radio_offset[0] = offset;
} else if (nsamples < 10) {
next_offset += nsamples;
next_radio_offset[0] = nsamples;
}
log_h->debug("SYNC: received %d samples from radio\n", nsamples);