Calibrated CFO loop default values

master
Ismael Gomez 7 years ago
parent 46f15c19e6
commit dd8bacf466

@ -546,7 +546,7 @@ int main(int argc, char **argv) {
exit(-1);
}
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.1);
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.005);
srslte_chest_dl_average_subframe(&ue_dl.chest, prog_args.average_subframe);
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
@ -959,7 +959,7 @@ void *plot_thread_run(void *arg) {
plot_real_init(&pce);
plot_real_setTitle(&pce, "Channel Response - Magnitude");
plot_real_setLabels(&pce, "Index", "dB");
plot_real_setYAxisScale(&pce, -40, 40);
plot_real_setYAxisScale(&pce, -M_PI, M_PI);
plot_real_init(&p_sync);
plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value");
@ -995,7 +995,11 @@ void *plot_thread_run(void *arg) {
tmp_plot2[g+i] = -80;
}
}
plot_real_setNewData(&pce, tmp_plot2, sz);
uint32_t nrefs = 2*ue_dl.cell.nof_prb;
for (i=0;i<nrefs;i++) {
tmp_plot2[i] = cargf(ue_dl.chest.tmp_cfo_estimate[i]);
}
plot_real_setNewData(&pce, tmp_plot2, nrefs);
if (!prog_args.input_file_name) {
if (plot_track) {

@ -452,7 +452,15 @@ typedef struct {
std::string snr_estim_alg;
bool cfo_integer_enabled;
float cfo_correct_tol_hz;
float cfo_ema;
float cfo_pss_ema;
float cfo_ref_ema;
float cfo_loop_bw_pss;
float cfo_loop_bw_ref;
float cfo_loop_ref_min;
float cfo_loop_pss_tol;
uint32_t cfo_loop_pss_conv;
uint32_t cfo_ref_mask;
bool average_subframe_enabled;
int time_correct_period;
bool sfo_correct_disable;
std::string sss_algorithm;

@ -111,13 +111,19 @@ typedef struct SRSLTE_API {
bool decode_sss_on_track;
bool cfo_is_copied;
bool cfo_correct_enable;
float cfo_current_value;
float cfo_loop_bw;
float cfo_pss_tol;
float cfo_ref_tol;
float cfo_loop_bw_pss;
float cfo_loop_bw_ref;
float cfo_pss_min;
float cfo_ref_min;
float cfo_ref_max;
uint32_t pss_stable_cnt;
uint32_t pss_stable_timeout;
bool pss_is_stable;
uint32_t peak_idx;
int next_rf_sample_offset;
int last_sample_offset;
@ -198,10 +204,12 @@ SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q,
srslte_ue_sync_t *src_obj);
SRSLTE_API void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q,
float bw,
float bw_pss,
float bw_ref,
float pss_tol,
float ref_tol,
float ref_max);
float ref_max,
uint32_t pss_stable_timeout);
SRSLTE_API void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q,
float ema);

@ -40,7 +40,7 @@
#define CFO_EMA_ALPHA 0.1
#define CP_EMA_ALPHA 0.1
#define DEFAULT_CFO_TOL 50.0 // Hz
#define DEFAULT_CFO_TOL 0.0 // Hz
static bool fft_size_isvalid(uint32_t fft_size) {
if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) {

@ -47,10 +47,14 @@
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0
#define DEFAULT_SFO_EMA_COEFF 0.1
#define DEFAULT_CFO_BW 0.7
#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation. Avoids ping-pong effect
#define DEFAULT_CFO_REF_TOL 5 // typical accuracy of REF estimation
#define DEFAULT_CFO_REF_MAX 300 // Maximum detection offset of REF based estimation
#define DEFAULT_CFO_BW 0.2
#define DEFAULT_CFO_PSS_MIN 500 // typical bias of PSS estimation.
#define DEFAULT_CFO_REF_MIN 0 // typical bias of REF estimation
#define DEFAULT_CFO_REF_MAX 500 // Maximum detection offset of REF based estimation
#define DEFAULT_PSS_STABLE_TIMEOUT 100 // Time after which the PSS is considered to be stable and we accept REF-CFO
#define DEFAULT_CFO_EMA_TRACK 0.1
cf_t dummy_buffer0[15*2048/2];
cf_t dummy_buffer1[15*2048/2];
@ -116,6 +120,7 @@ clean_exit:
void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q)
{
q->cfo_is_copied = false;
q->cfo_current_value = 0;
srslte_sync_cfo_reset(&q->strack);
srslte_sync_cfo_reset(&q->sfind);
@ -129,6 +134,7 @@ void srslte_ue_sync_reset(srslte_ue_sync_t *q) {
} else {
q->sf_idx = 9;
}
q->pss_stable_timeout = false;
q->state = SF_FIND;
q->frame_ok_cnt = 0;
q->frame_no_cnt = 0;
@ -218,11 +224,15 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
q->max_prb = max_prb;
q->cfo_ref_max = DEFAULT_CFO_REF_MAX;
q->cfo_ref_tol = DEFAULT_CFO_REF_TOL;
q->cfo_pss_tol = DEFAULT_CFO_PSS_TOL;
q->cfo_loop_bw = DEFAULT_CFO_BW;
q->cfo_ref_min = DEFAULT_CFO_REF_MIN;
q->cfo_pss_min = DEFAULT_CFO_PSS_MIN;
q->cfo_loop_bw_pss = DEFAULT_CFO_BW;
q->cfo_loop_bw_ref = DEFAULT_CFO_BW;
q->cfo_correct_enable = true;
q->pss_stable_cnt = 0;
q->pss_stable_timeout = DEFAULT_PSS_STABLE_TIMEOUT;
if (search_cell) {
/* If the cell is unkown, we search PSS/SSS in 5 ms */
@ -269,11 +279,11 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q,
srslte_sync_set_cfo_cp_enable(&q->strack, false);
srslte_sync_set_cfo_pss_enable(&q->strack, true);
srslte_sync_set_pss_filt_enable(&q->strack, true);
srslte_sync_set_sss_filt_enable(&q->strack, true);
srslte_sync_set_sss_filt_enable(&q->strack, false);
// FIXME: CP detection not working very well. Not supporting Extended CP right now
srslte_sync_cp_en(&q->strack, false);
srslte_sync_cp_en(&q->sfind, false);
srslte_sync_cp_en(&q->sfind, false);
srslte_sync_sss_en(&q->strack, true);
@ -368,6 +378,9 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell)
srslte_sync_set_threshold(&q->sfind, 2.0);
srslte_sync_set_threshold(&q->strack, 1.2);
srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1);
srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1);
} else {
q->sfind.cp = cell.cp;
q->strack.cp = cell.cp;
@ -376,7 +389,7 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell)
srslte_sync_set_N_id_2(&q->strack, cell.id%3);
srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1);
srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1);
srslte_sync_set_cfo_ema_alpha(&q->strack, DEFAULT_CFO_EMA_TRACK);
/* In find phase and if the cell is known, do not average pss correlation
* because we only capture 1 subframe and do not know where the peak is.
@ -402,22 +415,31 @@ void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *
memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t));
}
void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, float pss_tol, float ref_tol, float ref_max) {
q->cfo_loop_bw = bw;
q->cfo_pss_tol = pss_tol;
q->cfo_ref_tol = ref_tol;
void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw_pss, float bw_ref,
float pss_tol, float ref_tol, float ref_max,
uint32_t pss_stable_conv_time) {
q->cfo_loop_bw_pss = bw_pss;
q->cfo_loop_bw_ref = bw_ref;
q->cfo_pss_min = pss_tol;
q->cfo_ref_min = ref_tol;
q->cfo_ref_max = ref_max;
q->pss_stable_timeout = pss_stable_conv_time;
}
void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) {
srslte_sync_set_cfo_ema_alpha(&q->sfind, ema);
srslte_sync_set_cfo_ema_alpha(&q->strack, ema);
}
void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float ref_cfo)
{
if (fabsf(ref_cfo)*15000 > q->cfo_ref_tol && fabsf(ref_cfo)*15000 < q->cfo_ref_max) {
q->cfo_current_value += ref_cfo*q->cfo_loop_bw;
// Accept REF-based CFO adjustments only after PSS CFO is stable
if (q->pss_is_stable) {
if (fabsf(ref_cfo)*15000 > q->cfo_ref_min) {
if (fabsf(ref_cfo)*15000 > q->cfo_ref_max) {
ref_cfo = (ref_cfo>0?q->cfo_ref_max:-q->cfo_ref_max)/15000;
}
q->cfo_current_value += ref_cfo*q->cfo_loop_bw_ref;
}
}
}
@ -437,12 +459,16 @@ float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) {
void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, srslte_ue_sync_t *src_obj) {
// Copy find object internal CFO averages
srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind);
srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind);
// Current CFO is tracking-phase CFO of previous object
q->cfo_current_value = srslte_ue_sync_get_cfo(src_obj);
q->cfo_current_value = src_obj->cfo_current_value;
q->cfo_is_copied = true;
}
void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {}
void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {
srslte_sync_set_cfo_tol(&q->strack, cfo_tol);
srslte_sync_set_cfo_tol(&q->sfind, cfo_tol);
}
float srslte_ue_sync_get_sfo(srslte_ue_sync_t *q) {
return q->mean_sfo/5e-3;
@ -507,10 +533,12 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS
q->mean_sample_offset = 0;
/* Goto Tracking state */
q->state = SF_TRACK;
q->state = SF_TRACK;
/* Set CFO values. Since we correct before track, the initial track state is CFO=0 Hz */
q->cfo_current_value = srslte_sync_get_cfo(&q->sfind);
if (!q->cfo_is_copied) {
q->cfo_current_value = srslte_sync_get_cfo(&q->sfind);
}
srslte_sync_cfo_reset(&q->strack);
}
@ -550,9 +578,18 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) {
/* Adjust current CFO estimation with PSS
* Since sync track has enabled only PSS-based correlation, get_cfo() returns that value only, already filtered.
*/
INFO("TRACK: cfo_current: %f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack));
if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_tol) {
q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw;
INFO("TRACK: cfo_current=%f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack));
if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_min) {
q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw_pss;
q->pss_stable_cnt = 0;
q->pss_is_stable = false;
} else {
if (!q->pss_is_stable) {
q->pss_stable_cnt++;
if (q->pss_stable_cnt >= q->pss_stable_timeout) {
q->pss_is_stable = true;
}
}
}
// Compute cumulative moving average time offset */
@ -694,7 +731,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
ret = SRSLTE_ERROR;
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
return SRSLTE_ERROR;
case SRSLTE_SYNC_FOUND:
case SRSLTE_SYNC_FOUND:
ret = find_peak_ok(q, input_buffer);
break;
case SRSLTE_SYNC_FOUND_NOSPACE:
@ -769,9 +806,9 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
fprintf(stderr, "Error processing tracking peak\n");
q->state = SF_FIND;
return SRSLTE_SUCCESS;
}
q->frame_total_cnt++;
}
q->frame_total_cnt++;
}
break;
}

@ -38,7 +38,7 @@
#define MAX_SFLEN SRSLTE_SF_LEN(srslte_symbol_sz(max_prb))
#define DEFAULT_CFO_TOL 50.0 // Hz
#define DEFAULT_CFO_TOL 0.0 // Hz
int srslte_ue_ul_init(srslte_ue_ul_t *q,
cf_t *out_buffer,

@ -42,131 +42,138 @@
namespace srsue {
class chest_feedback_itf
{
public:
virtual void set_cfo(float cfo) = 0;
};
/* Subclass that manages variables common to all workers */
class phch_common {
public:
/* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args;
rrc_interface_phy *rrc;
mac_interface_phy *mac;
srslte_ue_ul_t ue_ul;
/* Power control variables */
float pathloss;
float cur_pathloss;
float p0_preamble;
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp_db;
float avg_rsrq_db;
float rx_gain_offset;
float avg_snr_db;
float avg_noise;
float avg_rsrp;
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
uint32_t last_dl_tti[2*HARQ_DELAY_MS];
int last_ul_tbs[2*HARQ_DELAY_MS];
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,
srslte::log *_log,
srslte::radio *_radio,
rrc_interface_phy *rrc,
mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void set_nof_mutex(uint32_t nof_mutex);
bool sr_enabled;
int sr_last_tx_tti;
srslte::radio* get_radio();
void set_cell(const srslte_cell_t &c);
uint32_t get_nof_prb();
void set_dl_metrics(const dl_metrics_t &m);
void get_dl_metrics(dl_metrics_t &m);
void set_ul_metrics(const ul_metrics_t &m);
void get_ul_metrics(ul_metrics_t &m);
void set_sync_metrics(const sync_metrics_t &m);
void get_sync_metrics(sync_metrics_t &m);
void reset_ul();
private:
std::vector<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
srslte::log *log_h;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[TTIMOD_SZ];
bool is_first_tx;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell;
dl_metrics_t dl_metrics;
uint32_t dl_metrics_count;
bool dl_metrics_read;
ul_metrics_t ul_metrics;
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
uint32_t sync_metrics_count;
bool sync_metrics_read;
};
class phch_common {
public:
/* Common variables used by all phy workers */
phy_interface_rrc::phy_cfg_t *config;
phy_args_t *args;
rrc_interface_phy *rrc;
mac_interface_phy *mac;
srslte_ue_ul_t ue_ul;
/* Power control variables */
float pathloss;
float cur_pathloss;
float p0_preamble;
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp_db;
float avg_rsrq_db;
float rx_gain_offset;
float avg_snr_db;
float avg_noise;
float avg_rsrp;
// Save last TBS for mcs>28 cases
int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS];
uint32_t last_dl_tti[2*HARQ_DELAY_MS];
int last_ul_tbs[2*HARQ_DELAY_MS];
uint32_t last_ul_tti[2*HARQ_DELAY_MS];
srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS];
phch_common(uint32_t max_mutex = 3);
void init(phy_interface_rrc::phy_cfg_t *config,
phy_args_t *args,
srslte::log *_log,
srslte::radio *_radio,
rrc_interface_phy *rrc,
mac_interface_phy *_mac);
/* For RNTI searches, -1 means now or forever */
void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_ul_rnti(uint32_t tti);
srslte_rnti_type_t get_ul_rnti_type();
void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1);
uint16_t get_dl_rnti(uint32_t tti);
srslte_rnti_type_t get_dl_rnti_type();
void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]);
bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL);
void reset_pending_ack(uint32_t tti);
void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs);
bool get_pending_ack(uint32_t tti);
bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs);
void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
void set_nof_mutex(uint32_t nof_mutex);
bool sr_enabled;
int sr_last_tx_tti;
srslte::radio* get_radio();
void set_cell(const srslte_cell_t &c);
uint32_t get_nof_prb();
void set_dl_metrics(const dl_metrics_t &m);
void get_dl_metrics(dl_metrics_t &m);
void set_ul_metrics(const ul_metrics_t &m);
void get_ul_metrics(ul_metrics_t &m);
void set_sync_metrics(const sync_metrics_t &m);
void get_sync_metrics(sync_metrics_t &m);
void reset_ul();
private:
std::vector<pthread_mutex_t> tx_mutex;
bool is_first_of_burst;
srslte::radio *radio_h;
float cfo;
srslte::log *log_h;
bool ul_rnti_active(uint32_t tti);
bool dl_rnti_active(uint32_t tti);
uint16_t ul_rnti, dl_rnti;
srslte_rnti_type_t ul_rnti_type, dl_rnti_type;
int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end;
float time_adv_sec;
srslte_dci_rar_grant_t rar_grant;
bool rar_grant_pending;
uint32_t rar_grant_tti;
typedef struct {
bool enabled;
uint32_t I_lowest;
uint32_t n_dmrs;
} pending_ack_t;
pending_ack_t pending_ack[TTIMOD_SZ];
bool is_first_tx;
uint32_t nof_workers;
uint32_t nof_mutex;
uint32_t max_mutex;
srslte_cell_t cell;
dl_metrics_t dl_metrics;
uint32_t dl_metrics_count;
bool dl_metrics_read;
ul_metrics_t ul_metrics;
uint32_t ul_metrics_count;
bool ul_metrics_read;
sync_metrics_t sync_metrics;
uint32_t sync_metrics_count;
bool sync_metrics_read;
};
} // namespace srsue
#endif // UEPHYWORKERCOMMON_H

@ -41,7 +41,7 @@ namespace srsue {
typedef _Complex float cf_t;
class phch_recv : public thread
class phch_recv : public thread, public chest_feedback_itf
{
public:
phch_recv();
@ -65,6 +65,9 @@ public:
bool status_is_sync();
// from chest_feedback_itf
void set_cfo(float cfo);
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t *cell);

@ -45,7 +45,7 @@ public:
~phch_worker();
void reset();
void set_common(phch_common *phy);
bool init(uint32_t max_prb, srslte::log *log);
bool init(uint32_t max_prb, srslte::log *log, chest_feedback_itf *chest_loop);
bool set_cell(srslte_cell_t cell);
@ -66,6 +66,8 @@ public:
int read_ce_abs(float *ce_abs);
int read_pdsch_d(cf_t *pdsch_d);
void start_plot();
float get_ref_cfo();
private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
@ -114,6 +116,7 @@ private:
/* Common objects */
phch_common *phy;
srslte::log *log_h;
chest_feedback_itf *chest_loop;
srslte_cell_t cell;
bool mem_initiated;
bool cell_initiated;

@ -199,13 +199,46 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"Enables integer CFO estimation and correction.")
("expert.cfo_correct_tol_hz",
bpo::value<float>(&args->expert.phy.cfo_correct_tol_hz)->default_value(50.0),
"Tolerance (in Hz) for digial CFO compensation.")
bpo::value<float>(&args->expert.phy.cfo_correct_tol_hz)->default_value(0.0),
"Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.")
("expert.cfo_ema",
bpo::value<float>(&args->expert.phy.cfo_ema)->default_value(0.4),
"CFO Exponential Moving Average coefficient. Lower makes it more robust to noise "
"but vulnerable to periodic interruptions due to VCO corrections.")
("expert.cfo_pss_ema",
bpo::value<float>(&args->expert.phy.cfo_pss_ema)->default_value(0.1),
"CFO Exponential Moving Average coefficient for PSS estimation during TRACK.")
("expert.cfo_ref_ema",
bpo::value<float>(&args->expert.phy.cfo_ref_ema)->default_value(0.01),
"CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition")
("expert.cfo_ref_mask",
bpo::value<uint32_t>(&args->expert.phy.cfo_ref_mask)->default_value(1023),
"Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)")
("expert.cfo_loop_bw_pss",
bpo::value<float>(&args->expert.phy.cfo_loop_bw_pss)->default_value(0.05),
"CFO feedback loop bandwidth for samples from PSS")
("expert.cfo_loop_bw_ref",
bpo::value<float>(&args->expert.phy.cfo_loop_bw_ref)->default_value(0.01),
"CFO feedback loop bandwidth for samples from RS")
("expert.cfo_loop_pss_tol",
bpo::value<float>(&args->expert.phy.cfo_loop_pss_tol)->default_value(300),
"Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop"
"and RS estimations are used instead (when available)")
("expert.cfo_loop_ref_min",
bpo::value<float>(&args->expert.phy.cfo_loop_ref_min)->default_value(0),
"Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop")
("expert.cfo_loop_pss_conv",
bpo::value<uint32_t>(&args->expert.phy.cfo_loop_pss_conv)->default_value(50),
"After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.")
("expert.average_subframe_enabled",
bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true),
"Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
("expert.time_correct_period",
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),

@ -98,9 +98,6 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_
srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2);
// Set options defined in expert section
set_ue_sync_opts(&cs.ue_sync);
last_gain = 40;
if (do_agc) {
srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain);
@ -184,6 +181,11 @@ void phch_recv::radio_error() {
radio_is_resetting=false;
}
void phch_recv::set_cfo(float cfo) {
Debug("set_ref_cfo=%f\n",cfo*15000);
srslte_ue_sync_set_cfo_ref(&ue_sync, cfo);
}
bool phch_recv::wait_radio_reset() {
int cnt=0;
while(cnt < 20 && radio_is_resetting) {
@ -211,8 +213,13 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) {
srslte_ue_sync_set_cfo_i_enable(q, true);
}
srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_ema);
srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema);
srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz);
srslte_ue_sync_set_cfo_loop_bw(q, worker_com->args->cfo_loop_bw_pss, worker_com->args->cfo_loop_bw_ref,
worker_com->args->cfo_loop_pss_tol,
worker_com->args->cfo_loop_ref_min,
worker_com->args->cfo_loop_pss_tol,
worker_com->args->cfo_loop_pss_conv);
int time_correct_period = worker_com->args->time_correct_period;
if (time_correct_period > 0) {
@ -320,15 +327,13 @@ int phch_recv::cell_search(int force_N_id_2) {
return false;
}
// Set options defined in expert section
set_ue_sync_opts(&ue_mib_sync.ue_sync);
if (do_agc) {
srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain);
}
srslte_ue_sync_reset(&ue_mib_sync.ue_sync);
srslte_ue_sync_copy_cfo(&ue_mib_sync.ue_sync, &cs.ue_sync);
Info("Copied cfo=%f Hz from cs_sync to ue_mib\n", srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync));
/* Find and decode MIB */
int sfn_offset;
@ -341,6 +346,7 @@ int phch_recv::cell_search(int force_N_id_2) {
srslte_ue_sync_reset(&ue_sync);
srslte_ue_sync_copy_cfo(&ue_sync, &ue_mib_sync.ue_sync);
Info("Copied cfo=%f Hz from ue_mib_sync to ue_sync\n", srslte_ue_sync_get_cfo(&ue_sync));
if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, &cell, NULL);
@ -731,6 +737,9 @@ void phch_recv::run_thread() {
worker->set_cfo(ul_dl_factor * metrics.cfo / 15000);
worker_com->set_sync_metrics(metrics);
Debug("current_cfo=%f, pss_stable_cnt=%d, cfo_pss=%f Hz\n",
metrics.cfo, ue_sync.pss_stable_cnt, srslte_sync_get_cfo(&ue_sync.strack)*15000);
worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */

@ -57,7 +57,9 @@ namespace srsue {
phch_worker::phch_worker() : tr_exec(10240)
{
phy = NULL;
phy = NULL;
chest_loop = NULL;
bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
mem_initiated = false;
@ -104,9 +106,11 @@ void phch_worker::set_common(phch_common* phy_)
phy = phy_;
}
bool phch_worker::init(uint32_t max_prb, srslte::log *log_h)
bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, chest_feedback_itf *chest_loop)
{
this->log_h = log_h;
this->chest_loop = chest_loop;
// ue_sync in phy.cc requires a buffer for 3 subframes
for (uint32_t i=0;i<phy->args->nof_rx_ant;i++) {
signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb));
@ -126,6 +130,8 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h)
return false;
}
srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled);
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask, phy->args->cfo_ref_ema);
srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, true);
@ -134,6 +140,10 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h)
return true;
}
float phch_worker::get_ref_cfo() {
return srslte_chest_dl_get_cfo(&ue_dl.chest);
}
bool phch_worker::set_cell(srslte_cell_t cell_)
{
if (cell.id != cell_.id || !cell_initiated) {
@ -221,6 +231,11 @@ void phch_worker::work_imp()
bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0;
// Call feedback loop for chest
if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) {
chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest));
}
if (chest_ok && snr_th_ok) {
/***** Downlink Processing *******/
@ -394,11 +409,8 @@ void phch_worker::work_imp()
bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = false;
if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti) || phy->get_pending_rar(tti)) {
decode_pdcch = true;
}
bool decode_pdcch = true;
/* Without a grant, we might need to do fft processing if need to decode PHICH */
if (phy->get_pending_ack(tti) || decode_pdcch) {
@ -1213,13 +1225,18 @@ int phch_worker::read_ce_abs(float *ce_abs) {
int sz = srslte_symbol_sz(cell.nof_prb);
bzero(ce_abs, sizeof(float)*sz);
int g = (sz - 12*cell.nof_prb)/2;
for (i = 0; i < 12*cell.nof_prb; i++) {
/* for (i = 0; i < 12*cell.nof_prb; i++) {
ce_abs[g+i] = 20 * log10f(cabsf(ue_dl.ce_m[0][0][i]));
if (isinf(ce_abs[g+i])) {
ce_abs[g+i] = -80;
}
}
return sz;
*/
uint32_t nrefs = 2*ue_dl.cell.nof_prb;
for (i=0;i<nrefs;i++) {
ce_abs[i] = 15000*0.463208685*cargf(ue_dl.chest.tmp_cfo_estimate[i])/M_PI;
}
return nrefs;
}
int phch_worker::read_pdsch_d(cf_t* pdsch_d)
@ -1298,7 +1315,7 @@ void phch_worker::update_measurements()
}
// Compute SNR
phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise);
phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise);
// Store metrics
dl_metrics.n = phy->avg_noise;
@ -1371,7 +1388,7 @@ void *plot_thread_run(void *arg) {
plot_real_init(&pce);
plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude");
plot_real_setLabels(&pce, (char*) "Index", (char*) "dB");
plot_real_setYAxisScale(&pce, -40, 40);
plot_real_setYAxisScale(&pce, -1000, 1000);
plot_scatter_init(&pconst);
plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols");

@ -37,7 +37,6 @@
#include "srslte/common/threads.h"
#include "srslte/common/log.h"
#include "phy/phy.h"
#include "phy/phch_worker.h"
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
@ -134,7 +133,7 @@ void phy::run_thread() {
// Add workers to workers pool and start threads
for (uint32_t i=0;i<nof_workers;i++) {
workers[i].set_common(&workers_common);
workers[i].init(SRSLTE_MAX_PRB, (srslte::log*) log_vec[i]);
workers[i].init(SRSLTE_MAX_PRB, (srslte::log*) log_vec[i], &sf_recv);
workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO, args->worker_cpu_mask);
}

@ -137,13 +137,7 @@ enable = false
# equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any
# non-negative real number to indicate a regularized zf coefficient.
# Default is MMSE.
# cfo_ema: CFO Exponential Moving Average coefficient. Lower makes it more robust to noise
# but vulnerable to periodic interruptions due to VCO corrections.
# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement
# and may lead to incorrect synchronization. Use with caution.
# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that
# a new table will be generated more often.
# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c),
# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c),
# good for long channels. For best performance at highest SNR reduce it to 1.
# sfo_correct_disable: Disables phase correction before channel estimation to compensate for
# sampling frequency offset. Default is enabled.
@ -155,10 +149,28 @@ enable = false
#
# pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance.
#
# average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe.
# Needs accurate CFO correction.
#
# metrics_csv_enable: Write UE metrics to CSV file.
#
# metrics_csv_filename: File path to use for CSV metrics.
#
# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement
# and may lead to incorrect synchronization. Use with caution.
# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that
# a new table will be generated more often.
#
# cfo_pss_ema: CFO Exponential Moving Average coefficient for PSS estimation during TRACK.
# cfo_ref_ema: CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition
# cfo_ref_mask: Bitmask for subframes on which to run RS estimation (set to 0 to disable, default sf=[1, 5])
# cfo_loop_bw: CFO feedback loop bandwidth for samples from PSS or RS
# cfo_loop_pss_tol: Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop
# and RS estimations are used instead (when available)
# cfo_loop_ref_min: Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop
# cfo_loop_pss_timeout: After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively,
# RS adjustments are allowed.
#
#####################################################################
[expert]
#ip_netmask = 255.255.255.0
@ -172,17 +184,27 @@ enable = false
#attach_enable_64qam = false
#nof_phy_threads = 2
#equalizer_mode = mmse
#cfo_ema = 0.4
#cfo_integer_enabled = false
#cfo_correct_tol_hz = 50
#time_correct_period = 5
#sfo_correct_disable = false
#sss_algorithm = full
#estimator_fil_w = 0.1
#average_subframe_enabled = true
#pregenerate_signals = false
#metrics_csv_enable = false
#metrics_csv_filename = /tmp/ue_metrics.csv
# CFO related values
#cfo_integer_enabled = false
#cfo_correct_tol_hz = 0
#cfo_pss_ema = 0.1
#cfo_ref_ema = 0.01
#cfo_ref_mask = 1023
#cfo_loop_bw_pss = 0.05
#cfo_loop_bw_ref = 0.01
#cfo_loop_pss_tol = 300
#cfo_loop_ref_min = 0
#cfo_loop_pss_conv = 50
#####################################################################
# Manual RF calibration
#

Loading…
Cancel
Save