Added subframe averaging option in chest_dl. Optional in pdsch_ue

This commit is contained in:
Ismael Gomez 2017-11-29 20:28:04 +01:00
parent 6e0c24c7ee
commit 46f15c19e6
5 changed files with 137 additions and 49 deletions

View File

@ -90,6 +90,8 @@ typedef struct {
uint32_t file_nof_prb;
uint32_t file_nof_ports;
uint32_t file_cell_id;
bool enable_cfo_ref;
bool average_subframe;
char *rf_args;
uint32_t rf_nof_rx_ant;
double rf_freq;
@ -120,7 +122,9 @@ void args_default(prog_args_t *args) {
args->file_offset_freq = 0;
args->rf_args = "";
args->rf_freq = -1.0;
args->rf_nof_rx_ant = 1;
args->rf_nof_rx_ant = 1;
args->enable_cfo_ref = false;
args->average_subframe = false;
#ifdef ENABLE_AGC_DEFAULT
args->rf_gain = -1.0;
#else
@ -137,7 +141,7 @@ void args_default(prog_args_t *args) {
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog);
printf("Usage: %s [agpPoOcildFRDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog);
#ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", args->rf_args);
printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant);
@ -158,6 +162,8 @@ void usage(prog_args_t *args, char *prog) {
printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled");
printf("\t-F Enable RS-based CFO correction [Default %s]\n", args->enable_cfo_ref?"Disabled":"Enabled");
printf("\t-R Average channel estimates on 1 ms [Default %s]\n", args->average_subframe?"Disabled":"Enabled");
printf("\t-t Add time offset [Default %d]\n", args->time_offset);
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
@ -179,7 +185,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) {
while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMN")) != -1) {
switch (opt) {
case 'i':
args->input_file_name = argv[optind];
@ -211,6 +217,12 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'C':
args->disable_cfo = true;
break;
case 'F':
args->enable_cfo_ref = true;
break;
case 'R':
args->average_subframe = true;
break;
case 't':
args->time_offset = atoi(argv[optind]);
break;
@ -533,7 +545,10 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.1);
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 */
srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti);
@ -655,6 +670,7 @@ int main(int argc, char **argv) {
decode_pdsch = false;
}
}
gettimeofday(&t[1], NULL);
if (decode_pdsch) {
if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe
@ -677,6 +693,12 @@ int main(int argc, char **argv) {
}
}
}
// Feed-back ue_sync with chest_dl CFO estimation
if (sfidx == 5 && prog_args.enable_cfo_ref) {
srslte_ue_sync_set_cfo_ref(&ue_sync, srslte_chest_dl_get_cfo(&ue_dl.chest));
}
}else{ // MBSFN subframe
n = srslte_ue_dl_decode_mbsfn(&ue_dl,
sf_buffer,
@ -773,7 +795,7 @@ int main(int argc, char **argv) {
/* Print basic Parameters */
PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers);
PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant));
PRINT_LINE(" CFO: %+7.2f kHz", srslte_ue_sync_get_cfo(&ue_sync));
PRINT_LINE(" CFO: %+7.2f Hz", srslte_ue_sync_get_cfo(&ue_sync));
PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise));
PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate);
PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials));
@ -973,7 +995,7 @@ void *plot_thread_run(void *arg) {
tmp_plot2[g+i] = -80;
}
}
plot_real_setNewData(&pce, tmp_plot2, sz);
plot_real_setNewData(&pce, tmp_plot2, sz);
if (!prog_args.input_file_name) {
if (plot_track) {

View File

@ -68,7 +68,8 @@ typedef struct {
cf_t *pilot_estimates_average;
cf_t *pilot_recv_signal;
cf_t *tmp_noise;
cf_t *tmp_cfo_estimate;
#ifdef FREQ_SEL_SNR
float snr_vector[12000];
float pilot_power[12000];
@ -84,8 +85,9 @@ typedef struct {
float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float cfo;
bool cfo_estimate_enable;
bool cfo_estimate_enable;
uint32_t cfo_estimate_sf_mask;
float cfo_ema;
/* Use PSS for noise estimation in LS linear interpolation mode */
cf_t pss_signal[SRSLTE_PSS_LEN];
@ -95,6 +97,7 @@ typedef struct {
srslte_chest_dl_noise_alg_t noise_alg;
int last_nof_antennas;
bool average_subframe;
} srslte_chest_dl_t;
@ -148,7 +151,13 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q,
uint32_t port_id,
uint32_t rxant_id);
SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask);
SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q,
bool enable,
uint32_t mask,
float ema);
SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q,
bool enable);
SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q);

View File

@ -115,6 +115,8 @@ typedef struct SRSLTE_API {
float cfo_current_value;
float cfo_loop_bw;
float cfo_pss_tol;
float cfo_ref_tol;
float cfo_ref_max;
uint32_t peak_idx;
int next_rf_sample_offset;
@ -197,11 +199,15 @@ SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q,
SRSLTE_API void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q,
float bw,
float pss_tol);
float pss_tol,
float ref_tol,
float ref_max);
SRSLTE_API void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q,
float ema);
SRSLTE_API void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float res_cfo);
SRSLTE_API void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q,
bool enable);

View File

@ -102,25 +102,30 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
}
q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->tmp_noise) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
q->tmp_cfo_estimate = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->tmp_cfo_estimate) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_estimates) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_estimates_average) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
}
q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size);
if (!q->pilot_recv_signal) {
perror("malloc");
goto clean_exit;
@ -175,6 +180,9 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
if (q->tmp_noise) {
free(q->tmp_noise);
}
if (q->tmp_cfo_estimate) {
free(q->tmp_cfo_estimate);
}
srslte_interp_linear_vector_free(&q->srslte_interp_linvec);
srslte_interp_linear_free(&q->srslte_interp_lin);
srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn);
@ -241,6 +249,10 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id)
{
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
if (q->average_subframe) {
nref /= 4;
}
/* Substract noisy pilot estimates */
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref);
@ -305,9 +317,13 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t fidx_offset = 0;
/* Interpolate in the frequency domain */
if (q->average_subframe) {
nsymbols = 1;
}
// we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation
for (l=0;l<(nsymbols);l++) {
for (l=0;l<nsymbols;l++) {
if (ch_mode == SRSLTE_SF_MBSFN) {
if (l == 0) {
fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0);
@ -329,34 +345,41 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t
}
/* Now interpolate in the time domain between symbols */
if (ch_mode == SRSLTE_SF_MBSFN) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
} else {
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
} else {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
}
if (q->average_subframe) {
// If we average per subframe, just copy the estimates in the time domain
for (l=0;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) {
memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb);
}
} else {
if (ch_mode == SRSLTE_SF_MBSFN) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1);
} else {
if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
if (SRSLTE_CP_ISNORM(q->cell.cp)) {
if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2);
} else {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5);
}
} else {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
}
if (nsymbols == 4) {
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2);
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2);
} else {
srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5);
srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4);
}
}
}
}
}
@ -392,6 +415,15 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
// Average in the time domain if enabled
if (q->average_subframe) {
for (int l=1;l<nsymbols;l++) {
srslte_vec_sum_ccc(&input[l*nref], input, input, nref);
}
srslte_vec_sc_prod_cfc(input, 1.0/((float) nsymbols), input, nref);
nsymbols = 1;
}
// Average in the frequency domain
for (int l=0;l<nsymbols;l++) {
srslte_conv_same_cf(&input[l*nref], q->smooth_filter, &output[l*nref], nref, q->smooth_filter_len);
@ -424,11 +456,11 @@ float chest_estimate_cfo(srslte_chest_dl_t *q)
for (int i=0;i<2;i++) {
srslte_vec_prod_conj_ccc(&q->pilot_estimates[i*npilots/4],
&q->pilot_estimates[(i+2)*npilots/4],
&q->tmp_noise[i*npilots/4],
&q->tmp_cfo_estimate[i*npilots/4],
npilots/4);
}
// Average all angles
cf_t sum = srslte_vec_acc_cc(q->tmp_noise, npilots/2);
cf_t sum = srslte_vec_acc_cc(q->tmp_cfo_estimate, npilots/2);
// Compute CFO
return -cargf(sum)*n/(ns*(n+ng))/2/M_PI;
@ -459,7 +491,7 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
}
if (q->cfo_estimate_enable && ((1<<sf_idx) & q->cfo_estimate_sf_mask)) {
q->cfo = chest_estimate_cfo(q);
q->cfo = SRSLTE_VEC_EMA(chest_estimate_cfo(q), q->cfo, q->cfo_ema);
}
/* Compute RSRP for the channel estimates in this port */
@ -542,8 +574,14 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT
return SRSLTE_SUCCESS;
}
void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask)
void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable)
{
q->average_subframe = enable;
}
void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask, float ema)
{
q->cfo_ema = ema;
q->cfo_estimate_enable = enable;
q->cfo_estimate_sf_mask = mask;
}

View File

@ -48,7 +48,9 @@
#define DEFAULT_SFO_EMA_COEFF 0.1
#define DEFAULT_CFO_BW 0.7
#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation
#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
cf_t dummy_buffer0[15*2048/2];
cf_t dummy_buffer1[15*2048/2];
@ -215,6 +217,8 @@ 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_correct_enable = true;
@ -398,9 +402,11 @@ 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) {
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;
q->cfo_ref_max = ref_max;
}
void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) {
@ -408,6 +414,13 @@ void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float 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;
}
}
uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q) {
return q->sf_idx;
}