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:
parent
080b4a327c
commit
0b6efb657e
|
@ -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(×tamp, 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(×tamp, _timestamp);
|
||||
}
|
||||
|
||||
|
@ -119,6 +124,11 @@ private:
|
|||
cf_t** get_buffer_ptr() { return buffer; }
|
||||
|
||||
void get_timestamp(srslte_timestamp_t* _timestamp) { srslte_timestamp_copy(_timestamp, ×tamp); }
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue