SRSUE: all TA control logic into a single class and faster TA response

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent 3e916ac3a8
commit 198684ce32

@ -156,10 +156,6 @@ private:
srslte::phy_cfg_t config = {};
phy_args_t args = {};
/* Current time advance */
uint32_t n_ta = 0;
uint32_t n_ta_base = 0;
static void set_default_args(phy_args_t& args);
bool check_args(const phy_args_t& args);
};

@ -30,6 +30,7 @@
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
#include "srslte/srslte.h"
#include "ta_control.h"
#include <condition_variable>
#include <mutex>
#include <string.h>
@ -88,6 +89,9 @@ public:
srslte::tti_semaphore<void*> semaphore;
// Time Aligment Controller, internal thread safe
ta_control ta;
phy_common();
~phy_common();

@ -55,7 +55,7 @@ public:
cf_t* get_buffer(uint32_t cc_idx, uint32_t antenna_idx);
uint32_t get_buffer_len();
void set_tti(uint32_t tti);
void set_tx_time(srslte_timestamp_t tx_time, int next_offset);
void set_tx_time(srslte_timestamp_t tx_time);
void set_prach(cf_t* prach_ptr, float prach_power);
void set_cfo(const uint32_t& cc_idx, float cfo);
@ -111,7 +111,6 @@ private:
uint32_t tti = 0;
srslte_timestamp_t tx_time = {};
int next_offset = {};
uint32_t rssi_read_cnt = 0;
};

@ -78,7 +78,6 @@ public:
void out_of_sync() final;
void set_cfo(float cfo) final;
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t* cell, uint32_t* earfcn = nullptr);
uint32_t get_current_tti();
@ -177,8 +176,6 @@ private:
std::vector<std::unique_ptr<scell::intra_measure> > intra_freq_meas;
uint32_t current_sflen = 0;
int next_offset = 0; // Sample offset triggered by Time aligment commands
int next_radio_offset = 0; // Sample offset triggered by SFO compensation
// Pointers to other classes
stack_interface_phy_lte* stack = nullptr;
@ -344,8 +341,6 @@ private:
// This is the primary cell
srslte_cell_t cell = {};
bool started = false;
float time_adv_sec = 0;
float next_time_adv_sec = 0;
uint32_t tti = 0;
srslte_timestamp_t tti_ts = {};
srslte_timestamp_t radio_ts = {};

@ -0,0 +1,238 @@
/*
* Copyright 2013-2020 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_TA_CONTROL_H
#define SRSUE_TA_CONTROL_H
#include <inttypes.h>
#include <mutex>
#include <srslte/phy/common/phy_common.h>
namespace srsue {
class ta_control
{
private:
srslte::log* log_h = nullptr;
mutable std::mutex mutex;
uint32_t next_base_nta = 0;
float next_base_sec = 0.0f;
float current_base_sec = 0.0f;
float prev_base_sec = 0.0f;
int32_t pending_nsamples = 0;
public:
/**
* Sets the logging instance
*
* @param loh_h_ logging instance pointer
*/
void set_logger(srslte::log* log_h_) { log_h = log_h_; }
/**
* Sets the next base time in seconds, discarding previous changes.
*
* @param ta_base_sec Time Alignment value in seconds
*/
void set_base_sec(float ta_base_sec)
{
std::lock_guard<std::mutex> lock(mutex);
// Forces next base
next_base_sec = ta_base_sec;
// Update base in nta
next_base_nta = static_cast<uint32_t>(roundf(next_base_sec / SRSLTE_LTE_TS));
// Resets pending samples
pending_nsamples = 0;
// Log information information if available
if (log_h) {
log_h->info("PHY: Set TA base: n_ta: %d, ta_usec: %.1f\n", next_base_nta, next_base_sec * 1e6f);
}
}
/**
* Increments (delta) the next base time. The value in seconds will be added to the next base.
*
* @param ta_delta_sec Time Alignment increment value in seconds
*/
void add_delta_sec(float ta_delta_sec)
{
std::lock_guard<std::mutex> lock(mutex);
// Increments the next base
next_base_sec += ta_delta_sec;
// Update base in nta
next_base_nta = static_cast<uint32_t>(roundf(next_base_sec / SRSLTE_LTE_TS));
// Log information information if available
if (log_h) {
log_h->info("PHY: Set TA: ta_delta_usec: %.1f, n_ta: %d, ta_usec: %.1f\n",
ta_delta_sec * 1e6f,
next_base_nta,
next_base_sec * 1e6f);
}
}
/**
* Increments (delta) the next base time according to time alignment command from a Random Access Response (RAR).
*
* @param ta_cmd Time Alignment command
*/
void add_ta_cmd_rar(uint32_t ta_cmd)
{
std::lock_guard<std::mutex> lock(mutex);
// Update base nta
next_base_nta += srslte_N_ta_new_rar(ta_cmd);
// Update base in seconds
next_base_sec = static_cast<float>(next_base_nta) * SRSLTE_LTE_TS;
// Log information information if available
if (log_h) {
log_h->info(
"PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, next_base_nta, next_base_sec * 1e6f);
}
}
/**
* Increments (delta) the next base time according to time alignment command from a MAC Control Element.
*
* @param ta_cmd Time Alignment command
*/
void add_ta_cmd_new(uint32_t ta_cmd)
{
std::lock_guard<std::mutex> lock(mutex);
// Update base nta
next_base_nta = srslte_N_ta_new(next_base_nta, ta_cmd);
// Update base in seconds
next_base_sec = static_cast<float>(next_base_nta) * SRSLTE_LTE_TS;
// Log information information if available
if (log_h) {
log_h->info("PHY: Set TA: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, next_base_nta, next_base_sec * 1e6f);
}
}
/**
* Increments/Decrements the number pending samples for next transmission
*
* @param nsamples is the number of samples
*/
void set_pending_nsamples(int32_t nsamples)
{
std::lock_guard<std::mutex> lock(mutex);
// Increment number of pending samples
pending_nsamples += nsamples;
}
/**
* Get the previous time alignment in seconds
*
* @return Time alignment in seconds
*/
float get_previous_sec() const
{
std::lock_guard<std::mutex> lock(mutex);
// Returns the previous base
return prev_base_sec;
}
/**
* Get the current time alignment in seconds
*
* @return Time alignment in seconds
*/
float get_current_sec() const
{
std::lock_guard<std::mutex> lock(mutex);
// Returns the current base
return current_base_sec;
}
/**
* Get the current time alignment in microseconds
*
* @return Time alignment in microseconds
*/
float get_current_usec() const
{
std::lock_guard<std::mutex> lock(mutex);
// Returns the current base
return current_base_sec * 1e6f;
}
/**
* Get the current time alignment in kilometers between the eNb and the UE
*
* @return Distance based on the current time base
*/
float get_current_km() const
{
std::lock_guard<std::mutex> lock(mutex);
// Returns the current base, one direction distance
return current_base_sec * (3.6f * 3e8f / 2.0f);
}
/**
* Get the total number of pending samples to transmit, considering the time difference between the next base and the
* current base.
*
* Attention: this method changes the internal state of the class.
*
* @return the total number of pending samples considering the sampling rate
*/
int32_t get_pending_nsamples(uint32_t sampling_rate_hz)
{
std::lock_guard<std::mutex> lock(mutex);
// Convert sampling rate to float
float srate = static_cast<float>(sampling_rate_hz);
// Calculate number of samples
int32_t nsamples = static_cast<int32_t>(roundf(srate * (current_base_sec - next_base_sec)));
// Update current base
prev_base_sec = current_base_sec;
current_base_sec = next_base_sec;
// Reset pending samples
pending_nsamples = 0;
// Return number of samples
return nsamples;
}
};
} // namespace srsue
#endif // SRSUE_TA_CONTROL_H

@ -257,22 +257,12 @@ void phy::get_metrics(phy_metrics_t* m)
void phy::set_timeadv_rar(uint32_t ta_cmd)
{
n_ta = srslte_N_ta_new_rar(ta_cmd);
n_ta += n_ta_base;
sfsync.set_time_adv_sec(((float)n_ta) * SRSLTE_LTE_TS);
Info("PHY: Set TA RAR: ta_cmd: %d, n_ta: %d, ta_usec: %.1f\n", ta_cmd, n_ta, ((float)n_ta) * SRSLTE_LTE_TS * 1e6);
common.ta.add_ta_cmd_rar(ta_cmd);
}
void phy::set_timeadv(uint32_t ta_cmd)
{
uint32_t new_nta = srslte_N_ta_new(n_ta, ta_cmd);
sfsync.set_time_adv_sec(((float)new_nta) * SRSLTE_LTE_TS);
Info("PHY: Set TA: ta_cmd: %d, n_ta: %d, old_n_ta: %d, ta_usec: %.1f\n",
ta_cmd,
new_nta,
n_ta,
((float)new_nta) * SRSLTE_LTE_TS * 1e6);
n_ta = new_nta;
common.ta.add_ta_cmd_new(ta_cmd);
}
void phy::set_activation_deactivation_scell(uint32_t cmd)
@ -341,9 +331,7 @@ float phy::get_pathloss_db()
void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm, float ta_base_sec)
{
n_ta = 0; /* Reset Time aligment */
n_ta_base = (uint32_t)roundf(ta_base_sec / SRSLTE_LTE_TS);
sfsync.set_time_adv_sec(ta_base_sec);
common.ta.set_base_sec(ta_base_sec);
common.reset_radio();
if (!prach_buffer.prepare_to_send(preamble_idx, allowed_subframe, target_power_dbm)) {
Error("Preparing PRACH to send\n");
@ -370,9 +358,7 @@ void phy::radio_failure()
void phy::reset()
{
Info("Resetting PHY\n");
n_ta = 0;
n_ta_base = 0;
sfsync.set_time_adv_sec(0);
common.ta.set_base_sec(0);
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i]->reset();
}

@ -68,6 +68,8 @@ void phy_common::init(phy_args_t* _args,
args = _args;
sr_last_tx_tti = -1;
ta.set_logger(_log);
// Instantiate UL channel emulator
if (args->ul_channel_args.enable) {
ul_channel = srslte::channel_ptr(new srslte::channel(args->ul_channel_args, args->nof_carriers * args->nof_rx_ant));

@ -138,9 +138,8 @@ void sf_worker::set_tti(uint32_t tti_)
}
}
void sf_worker::set_tx_time(srslte_timestamp_t tx_time_, int next_offset_)
void sf_worker::set_tx_time(srslte_timestamp_t tx_time_)
{
next_offset = next_offset_;
tx_time = tx_time_;
}
@ -207,11 +206,13 @@ void sf_worker::work_imp()
bool rx_signal_ok = false;
bool tx_signal_ready = false;
uint32_t nof_samples = SRSLTE_SF_LEN_PRB(cell.nof_prb);
int32_t next_offset = 0;
/***** Downlink Processing *******/
{
std::lock_guard<std::mutex> lock(mutex);
/***** Downlink Processing *******/
// Loop through all carriers. carrier_idx=0 is PCell
for (uint32_t carrier_idx = 0; carrier_idx < cc_workers.size(); carrier_idx++) {
@ -230,6 +231,9 @@ void sf_worker::work_imp()
}
}
// Load TA
next_offset = phy->ta.get_pending_nsamples(nof_samples * 1000U);
/***** Uplink Generation + Transmission *******/
/* If TTI+4 is an uplink subframe (TODO: Support short PRACH and SRS in UpPts special subframes) */
@ -259,10 +263,12 @@ void sf_worker::work_imp()
// Set PRACH buffer signal pointer
if (prach_ptr) {
srslte_timestamp_sub(&tx_time, 0, phy->ta.get_current_sec());
tx_signal_ready = true;
tx_signal_ptr.set(0, prach_ptr);
prach_ptr = nullptr;
} else {
srslte_timestamp_sub(&tx_time, 0, phy->ta.get_previous_sec());
nof_samples += next_offset;
}

@ -136,9 +136,6 @@ void sync::reset()
{
in_sync_cnt = 0;
out_of_sync_cnt = 0;
time_adv_sec = 0;
next_offset = 0;
next_radio_offset = 0;
current_earfcn = -1;
srate_mode = SRATE_NONE;
sfn_p.reset();
@ -476,7 +473,7 @@ void sync::run_thread()
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
metrics.ta_us = time_adv_sec * 1e6f;
metrics.ta_us = worker_com->ta.get_current_usec();
for (uint32_t i = 0; i < worker_com->args->nof_carriers; i++) {
worker_com->set_sync_metrics(i, metrics);
}
@ -493,9 +490,9 @@ void sync::run_thread()
srslte_timestamp_t rx_time, tx_time;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
srslte_timestamp_copy(&tx_time, &rx_time);
srslte_timestamp_add(&tx_time, 0, FDD_HARQ_DELAY_DL_MS * 1e-3 - time_adv_sec);
srslte_timestamp_add(&tx_time, 0, FDD_HARQ_DELAY_DL_MS * 1e-3);
worker->set_prach(prach_ptr ? &prach_ptr[prach_sf_cnt * SRSLTE_SF_LEN_PRB(cell.nof_prb)] : NULL,
worker->set_prach(prach_ptr ? &prach_ptr[prach_sf_cnt * SRSLTE_SF_LEN_PRB(cell.nof_prb)] : nullptr,
prach_power);
// Set CFO for all Carriers
@ -505,21 +502,14 @@ void sync::run_thread()
}
worker->set_tti(tti);
worker->set_tx_time(tx_time, next_radio_offset + 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;
}
worker->set_tx_time(tx_time);
// Advance/reset prach subframe pointer
if (prach_ptr) {
prach_sf_cnt++;
if (prach_sf_cnt == prach_nof_sf) {
prach_sf_cnt = 0;
prach_ptr = NULL;
prach_ptr = nullptr;
}
}
@ -643,14 +633,6 @@ void sync::set_agc_enable(bool enable)
}
}
void sync::set_time_adv_sec(float time_adv_sec_)
{
// If transmitting earlier, transmit less samples to align time advance. If transmit later just delay next TX
next_offset = (int)round((time_adv_sec - time_adv_sec_) * srslte_sampling_freq_hz(cell.nof_prb));
next_time_adv_sec = time_adv_sec_;
Info("Applying time_adv_sec=%.1f us, next_offset=%d\n", time_adv_sec_ * 1e6, next_offset);
}
float sync::get_tx_cfo()
{
float cfo = srslte_ue_sync_get_cfo(&ue_sync);
@ -882,9 +864,9 @@ int sync::radio_recv_fnc(srslte::rf_buffer_t& data, uint32_t nsamples, srslte_ti
int offset = nsamples - current_sflen;
if (abs(offset) < 10 && offset != 0) {
next_radio_offset = offset;
worker_com->ta.set_pending_nsamples(offset);
} else if (nsamples < 10) {
next_radio_offset = nsamples;
worker_com->ta.set_pending_nsamples(nsamples);
}
log_h->debug("SYNC: received %d samples from radio\n", nsamples);

Loading…
Cancel
Save