From 83aba931e3a9156df5c48683d2277984666a0f0e Mon Sep 17 00:00:00 2001 From: ismagom Date: Mon, 9 Nov 2015 19:15:33 +0100 Subject: [PATCH] Added CP-based autocorrelation CFO estimation. Added integer CFO estimation/correction. Improved overall synchronization performance --- matlab/sync/cfo_test.m | 46 ++++++--- matlab/sync/cp_corr.m | 2 +- matlab/sync/find_pss.m | 4 +- matlab/sync/lte_pss_zc.m | 2 - srslte/examples/pdsch_ue.c | 21 ++-- srslte/include/srslte/srslte.h | 1 + srslte/include/srslte/sync/pss.h | 5 + srslte/include/srslte/sync/sync.h | 30 +++++- srslte/lib/sync/src/cp.c | 54 +++++++++- srslte/lib/sync/src/pss.c | 31 +++--- srslte/lib/sync/src/sync.c | 146 ++++++++++++++++++++++------ srslte/lib/sync/test/CMakeLists.txt | 3 + srslte/lib/sync/test/pss_mex.c | 4 +- srslte/lib/sync/test/sync_test.c | 2 +- srslte/lib/ue/src/ue_sync.c | 60 +++++++----- 15 files changed, 297 insertions(+), 114 deletions(-) diff --git a/matlab/sync/cfo_test.m b/matlab/sync/cfo_test.m index 6835cbd58..cd957fb5c 100644 --- a/matlab/sync/cfo_test.m +++ b/matlab/sync/cfo_test.m @@ -2,25 +2,41 @@ clear; sym_len=128; hflen = (sym_len/128)*1920*5; samp_rate = (sym_len/128)*1920000; -N_id_2=1; -input=read_complex('../../build/lte_signal.dat', hflen*200); +N_id_2=0; +input=read_complex('../../debug/lte_signal.dat', hflen*240); -cp0_len=160*sym_len/2048; -cp1_len=144*sym_len/2048; +addpath('../../debug/srslte/lib/sync/test') -%t = (0:length(input)-1).'/samp_rate; -%input = input .* exp(-1i*2*pi*2000.0*t); +off=100; +halfframes=reshape(input(hflen-off+1:end-hflen-off),hflen,[]); +[n m]=size(halfframes); -subframes=reshape(input,hflen,[]); -[n m]=size(subframes); +fo=linspace(-30000,30000,m); -cfdl=struct('NDLRB',6,'CyclicPrefix','Normal','DuplexMode','FDD'); -cfo=zeros(m,2); +nreal=1; + +cfdl=struct('NDLRB',6,'CyclicPrefix','Normal','NCellID',0,'CellRefP',1,'DuplexMode','FDD'); +cfo=zeros(m,3); +toffset=zeros(m,2); for i=1:m - [toffset, cfo(i,2)] = find_pss(subframes(:,i),N_id_2); - cfo(i,1) = lteFrequencyOffset(cfdl,subframes(:,i),toffset)/15000; + x = halfframes(:,i); + t = (0:n-1).'/samp_rate; + x = x .* exp(1i*2*pi*fo(i).*t); + cfo_=zeros(nreal,2); + idx_=zeros(nreal,2); + for j=1:nreal + y=awgn(x,5); + cfo_(j,1) = lteFrequencyOffset(cfdl,y)/15000; + [idx_(j,1), cfo_(j,2)] = find_pss(y,N_id_2); + [idx_(j,2), corr] = srslte_cp_synch(cfdl,y); + cfo_(j,3) = -angle(corr(idx_(j,2)+1))/2/pi; + idx_(j,1) = idx_(j,1)-961; + end + cfo(i,:)=mean(cfo_,1); + toffset(i,:)=mean(idx_,1); end -plot(cfo*15000) -legend('Matlab','PSS-based') -disp(mean(cfo)*15) +error=abs(cfo-repmat(fo',1,3)/15000); +semilogy(fo/15000,error) +%plot(fo/15000,toffset) +legend('Matlab','PSS-based','CP-based') diff --git a/matlab/sync/cp_corr.m b/matlab/sync/cp_corr.m index e212fb034..90c00bcb7 100644 --- a/matlab/sync/cp_corr.m +++ b/matlab/sync/cp_corr.m @@ -6,4 +6,4 @@ for i=theta:theta+L-1 l1=l1+abs(x(i))^2+abs(x(i+N))^2; end -lambda=l0;%2*abs(l0)-rho*l1; +lambda=l1;%2*abs(l0)-rho*l1; diff --git a/matlab/sync/find_pss.m b/matlab/sync/find_pss.m index c4b460173..139173dab 100644 --- a/matlab/sync/find_pss.m +++ b/matlab/sync/find_pss.m @@ -3,10 +3,10 @@ function [ fs, cfo, p_m, w2] = find_pss( x, N_id_2) c=lte_pss_zc(N_id_2); cc=[zeros(33,1); c; zeros(33,1)]; ccf=[0; cc(65:128); cc(2:64)]; - ccf=conj(ifft(ccf)); + ccf=sqrt(128)*conj(ifft(ccf)); w2=conv(x,ccf); [m, fs]=max(abs(w2)); - + y=ccf.*x(fs-128:fs-1); y0=y(1:64); y1=y(65:length(y)); diff --git a/matlab/sync/lte_pss_zc.m b/matlab/sync/lte_pss_zc.m index 4bacf1917..1cf94af88 100644 --- a/matlab/sync/lte_pss_zc.m +++ b/matlab/sync/lte_pss_zc.m @@ -1,7 +1,5 @@ function[a]=lte_pss_zc(cell_id) % Function returns 1 out of 3 possible Zadoff-Chu sequences used in LTE. -% zadoff_chu element 32 left out. corresponds to DC carrier and is -% therefore not transmitted Nzc=62; u=0; diff --git a/srslte/examples/pdsch_ue.c b/srslte/examples/pdsch_ue.c index 72e9f6135..6937a29d9 100644 --- a/srslte/examples/pdsch_ue.c +++ b/srslte/examples/pdsch_ue.c @@ -435,7 +435,7 @@ int main(int argc, char **argv) { #endif ue_sync.correct_cfo = !prog_args.disable_cfo; - + INFO("\nEntering main loop...\n\n", 0); /* Main loop */ while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { @@ -469,7 +469,8 @@ int main(int argc, char **argv) { decode_pdsch = true; } else { /* We are looking for SIB1 Blocks, 2search only in appropiate places */ - if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { + // Decode only RV=0 + if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%8)==0)) { decode_pdsch = true; } else { decode_pdsch = false; @@ -480,9 +481,12 @@ int main(int argc, char **argv) { if (prog_args.rnti != SRSLTE_SIRNTI) { n = srslte_ue_dl_decode(&ue_dl, &sf_buffer[prog_args.time_offset], data, srslte_ue_sync_get_sfidx(&ue_sync)); } else { + // RV for SIB1 is predefined + uint32_t k = (sfn/2)%4; + uint32_t rv = ((uint32_t) ceilf((float)1.5*k))%4; n = srslte_ue_dl_decode_rnti_rv(&ue_dl, &sf_buffer[prog_args.time_offset], data, srslte_ue_sync_get_sfidx(&ue_sync), - SRSLTE_SIRNTI, ((int) ceilf((float)3*(((sfn)/2)%4)/2))%4); + SRSLTE_SIRNTI, rv); } if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); @@ -678,12 +682,13 @@ void *plot_thread_run(void *arg) { if (!prog_args.input_file_name) { if (plot_track) { - int max = srslte_vec_max_fi(ue_sync.strack.pss.conv_output_avg, ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1); - srslte_vec_sc_prod_fff(ue_sync.strack.pss.conv_output_avg, - 1/ue_sync.strack.pss.conv_output_avg[max], + srslte_pss_synch_t *pss_obj = srslte_sync_get_cur_pss_obj(&ue_sync.strack); + int max = srslte_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size+pss_obj->fft_size-1); + srslte_vec_sc_prod_fff(pss_obj->conv_output_avg, + 1/pss_obj->conv_output_avg[max], tmp_plot2, - ue_sync.strack.pss.frame_size+ue_sync.strack.pss.fft_size-1); - plot_real_setNewData(&p_sync, tmp_plot2, ue_sync.strack.pss.frame_size); + pss_obj->frame_size+pss_obj->fft_size-1); + plot_real_setNewData(&p_sync, tmp_plot2, pss_obj->frame_size); } else { int max = srslte_vec_max_fi(ue_sync.sfind.pss.conv_output_avg, ue_sync.sfind.pss.frame_size+ue_sync.sfind.pss.fft_size-1); srslte_vec_sc_prod_fff(ue_sync.sfind.pss.conv_output_avg, diff --git a/srslte/include/srslte/srslte.h b/srslte/include/srslte/srslte.h index fcef7490b..e4bb8c3cc 100644 --- a/srslte/include/srslte/srslte.h +++ b/srslte/include/srslte/srslte.h @@ -115,6 +115,7 @@ #include "srslte/sync/sss.h" #include "srslte/sync/sync.h" #include "srslte/sync/cfo.h" +#include "srslte/sync/cp.h" #ifdef __cplusplus } diff --git a/srslte/include/srslte/sync/pss.h b/srslte/include/srslte/sync/pss.h index eda734f5d..a2abe9598 100644 --- a/srslte/include/srslte/sync/pss.h +++ b/srslte/include/srslte/sync/pss.h @@ -98,6 +98,11 @@ SRSLTE_API int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size); +SRSLTE_API int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, + uint32_t frame_size, + uint32_t fft_size, + int cfo_i); + SRSLTE_API int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size); diff --git a/srslte/include/srslte/sync/sync.h b/srslte/include/srslte/sync/sync.h index 2dcde5244..74b61211c 100644 --- a/srslte/include/srslte/sync/sync.h +++ b/srslte/include/srslte/sync/sync.h @@ -53,6 +53,7 @@ #include "srslte/sync/pss.h" #include "srslte/sync/sss.h" #include "srslte/sync/cfo.h" +#include "srslte/sync/cp.h" #define SRSLTE_SYNC_FFT_SZ_MIN 64 #define SRSLTE_SYNC_FFT_SZ_MAX 2048 @@ -61,7 +62,11 @@ typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t; typedef struct SRSLTE_API { srslte_pss_synch_t pss; + srslte_pss_synch_t pss_i[2]; srslte_sss_synch_t sss; + srslte_cp_synch_t cp_synch; + cf_t *cfo_i_corr[2]; + float threshold; float peak_value; float mean_peak_value; @@ -70,12 +75,17 @@ typedef struct SRSLTE_API { uint32_t sf_idx; uint32_t fft_size; uint32_t frame_size; + uint32_t max_offset; float mean_cfo; + int cfo_i; + bool find_cfo_i; + float cfo_ema_alpha; + uint32_t nof_symbols; + uint32_t cp_len; srslte_cfo_t cfocorr; sss_alg_t sss_alg; bool detect_cp; bool sss_en; - bool correct_cfo; srslte_cp_t cp; uint32_t m0; uint32_t m1; @@ -89,6 +99,7 @@ typedef struct SRSLTE_API { SRSLTE_API int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, + uint32_t max_offset, uint32_t fft_size); SRSLTE_API void srslte_sync_free(srslte_sync_t *q); @@ -140,6 +151,14 @@ SRSLTE_API float srslte_sync_get_cfo(srslte_sync_t *q); /* Sets known CFO to avoid long transients due to average */ SRSLTE_API void srslte_sync_set_cfo(srslte_sync_t *q, float cfo); +/* Set integer CFO */ +SRSLTE_API void srslte_sync_set_cfo_i(srslte_sync_t *q, + int cfo_i); + +/* Sets the exponential moving average coefficient for CFO averaging */ +SRSLTE_API void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, + float alpha); + /* Gets the CP length estimation from the last call to synch_run() */ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); @@ -147,10 +166,16 @@ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp); +/* Enable integer CFO detection */ +SRSLTE_API void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, + bool enabled); + /* Enables/Disables SSS detection */ SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, bool enabled); +SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); + SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_is_en(srslte_sync_t *q); @@ -159,8 +184,5 @@ SRSLTE_API bool srslte_sync_sss_is_en(srslte_sync_t *q); SRSLTE_API void srslte_sync_cp_en(srslte_sync_t *q, bool enabled); -SRSLTE_API void srslte_sync_correct_cfo(srslte_sync_t *q, - bool enabled); - #endif // SYNC_ diff --git a/srslte/lib/sync/src/cp.c b/srslte/lib/sync/src/cp.c index b11199b25..888c0ef40 100644 --- a/srslte/lib/sync/src/cp.c +++ b/srslte/lib/sync/src/cp.c @@ -25,8 +25,56 @@ * */ +#include +#include "srslte/sync/cp.h" +#include "srslte/utils/vector.h" +#include "srslte/utils/debug.h" + +int srslte_cp_synch_init(srslte_cp_synch_t *q, uint32_t symbol_sz) +{ + q->symbol_sz = symbol_sz; + + q->corr = srslte_vec_malloc(sizeof(cf_t) * q->symbol_sz); + if (!q->corr) { + perror("malloc"); + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; +} + +void srslte_cp_synch_free(srslte_cp_synch_t *q) +{ + if (q->corr) { + free(q->corr); + } +} + +uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) +{ + if (max_offset <= q->symbol_sz) { + for (int i=0;icorr[i] = 0; + cf_t *inputPtr = input; + for (int n=0;ncorr[i] += srslte_vec_dot_prod_conj_ccc(&inputPtr[i], &inputPtr[i+q->symbol_sz], cplen)/nof_symbols; + inputPtr += q->symbol_sz+cplen; + } + } + uint32_t max_idx = srslte_vec_max_abs_ci(q->corr, max_offset); + return max_idx; + } else { + return 0; + } +} + +cf_t srslte_cp_synch_corr_output(srslte_cp_synch_t *q, uint32_t offset) +{ + if (offset < q->symbol_sz) { + return q->corr[offset]; + } else { + return 0; + } +} -/** TODO: Cyclic-prefix based synchronization - * - */ diff --git a/srslte/lib/sync/src/pss.c b/srslte/lib/sync/src/pss.c index 2917413be..af386375c 100644 --- a/srslte/lib/sync/src/pss.c +++ b/srslte/lib/sync/src/pss.c @@ -39,7 +39,8 @@ #include "srslte/utils/debug.h" -int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_time, cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_size) { +int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_time, cf_t *pss_signal_freq, + uint32_t N_id_2, uint32_t fft_size, int cfo_i) { srslte_dft_plan_t plan; cf_t pss_signal_pad[2048]; int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -52,10 +53,9 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_time, cf_t *pss_signal_freq, u bzero(pss_signal_pad, fft_size * sizeof(cf_t)); bzero(pss_signal_freq, fft_size * sizeof(cf_t)); - memcpy(&pss_signal_pad[(fft_size-SRSLTE_PSS_LEN)/2], pss_signal_time, SRSLTE_PSS_LEN * sizeof(cf_t)); + memcpy(&pss_signal_pad[(fft_size-SRSLTE_PSS_LEN)/2+cfo_i], pss_signal_time, SRSLTE_PSS_LEN * sizeof(cf_t)); - /* Convert signal into the time domain */ - + /* Convert signal into the time domain */ if (srslte_dft_plan(&plan, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { return SRSLTE_ERROR; } @@ -80,12 +80,17 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_time, cf_t *pss_signal_freq, u int srslte_pss_synch_init(srslte_pss_synch_t *q, uint32_t frame_size) { return srslte_pss_synch_init_fft(q, frame_size, 128); } + +int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { + return srslte_pss_synch_init_fft_offset(q, frame_size, fft_size, 0); +} + /* Initializes the PSS synchronization object. * * It correlates a signal of frame_size samples with the PSS sequence in the frequency * domain. The PSS sequence is transformed using fft_size samples. */ -int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { +int srslte_pss_synch_init_fft_offset(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t fft_size, int offset) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL) { @@ -100,8 +105,7 @@ int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32 q->ema_alpha = 0.1; buffer_size = fft_size + frame_size + 1; - - + if (srslte_dft_plan(&q->dftp_input, fft_size, SRSLTE_DFT_FORWARD, SRSLTE_DFT_COMPLEX)) { fprintf(stderr, "Error creating DFT plan \n"); goto clean_and_exit; @@ -146,7 +150,7 @@ int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32 goto clean_and_exit; } /* The PSS is translated into the time domain for each N_id_2 */ - if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size)) { + if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; } @@ -298,8 +302,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe #ifdef CONVOLUTION_FFT memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); - conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, - q->pss_signal_time[q->N_id_2], q->conv_output); + conv_output_len = srslte_conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_time[q->N_id_2], q->conv_output); #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -359,10 +362,8 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - if (*corr_peak_value < 2.0) { - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, + DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); - } } #else if (corr_peak_value) { @@ -379,8 +380,6 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe return ret; } -SRSLTE_API cf_t *tmp2; - /* Computes frequency-domain channel estimation of the PSS symbol * input signal is in the time-domain. * ce is the returned frequency-domain channel estimates. @@ -398,8 +397,6 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS return SRSLTE_ERROR; } - tmp2 = input_fft; - /* Transform to frequency-domain */ srslte_dft_run_c(&q->dftp_input, input, input_fft); diff --git a/srslte/lib/sync/src/sync.c b/srslte/lib/sync/src/sync.c index 7f0b03276..5680b57b1 100644 --- a/srslte/lib/sync/src/sync.c +++ b/srslte/lib/sync/src/sync.c @@ -25,6 +25,7 @@ * */ +#include #include #include #include @@ -36,7 +37,7 @@ #include "srslte/sync/cfo.h" #define MEANPEAK_EMA_ALPHA 0.2 -#define CFO_EMA_ALPHA 0.1 +#define CFO_EMA_ALPHA 0.9 #define CP_EMA_ALPHA 0.2 static bool fft_size_isvalid(uint32_t fft_size) { @@ -47,7 +48,7 @@ static bool fft_size_isvalid(uint32_t fft_size) { } } -int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t fft_size) { +int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -59,18 +60,30 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t fft_size) { bzero(q, sizeof(srslte_sync_t)); q->detect_cp = true; - q->cp = SRSLTE_CP_NORM; q->mean_peak_value = 0.0; q->sss_en = true; - q->correct_cfo = true; q->mean_cfo = 0; q->N_id_2 = 1000; q->N_id_1 = 1000; + q->cfo_i = 0; + q->find_cfo_i = false; + q->cfo_ema_alpha = CFO_EMA_ALPHA; q->fft_size = fft_size; q->frame_size = frame_size; + q->max_offset = max_offset; q->sss_alg = SSS_PARTIAL_3; + + for (int i=0;i<2;i++) { + q->cfo_i_corr[i] = srslte_vec_malloc(sizeof(cf_t)*q->frame_size); + if (!q->cfo_i_corr[i]) { + perror("malloc"); + goto clean_exit; + } + } - if (srslte_pss_synch_init_fft(&q->pss, frame_size, fft_size)) { + srslte_sync_set_cp(q, SRSLTE_CP_NORM); + + if (srslte_pss_synch_init_fft(&q->pss, max_offset, fft_size)) { fprintf(stderr, "Error initializing PSS object\n"); goto clean_exit; } @@ -84,7 +97,12 @@ int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t fft_size) { goto clean_exit; } - DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size); + if (srslte_cp_synch_init(&q->cp_synch, fft_size)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + DEBUG("SYNC init with frame_size=%d, max_offset=%d and fft_size=%d\n", frame_size, max_offset, fft_size); ret = SRSLTE_SUCCESS; } else { @@ -103,6 +121,13 @@ void srslte_sync_free(srslte_sync_t *q) { srslte_pss_synch_free(&q->pss); srslte_sss_synch_free(&q->sss); srslte_cfo_free(&q->cfocorr); + srslte_cp_synch_free(&q->cp_synch); + for (int i=0;i<2;i++) { + if (q->cfo_i_corr[i]) { + free(q->cfo_i_corr[i]); + } + srslte_pss_synch_free(&q->pss_i[i]); + } } } @@ -110,6 +135,19 @@ void srslte_sync_set_threshold(srslte_sync_t *q, float threshold) { q->threshold = threshold; } +void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, bool enabled) { + q->find_cfo_i = enabled; + for (int i=0;i<2;i++) { + int offset=(i==0)?-1:1; + if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + fprintf(stderr, "Error initializing PSS object\n"); + } + for (int t=0;tframe_size;t++) { + q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); + } + } +} + void srslte_sync_sss_en(srslte_sync_t *q, bool enabled) { q->sss_en = enabled; } @@ -141,13 +179,21 @@ uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q) { } float srslte_sync_get_cfo(srslte_sync_t *q) { - return q->mean_cfo; + return q->mean_cfo + q->cfo_i; } void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) { q->mean_cfo = cfo; } +void srslte_sync_set_cfo_i(srslte_sync_t *q, int cfo_i) { + q->cfo_i = cfo_i; +} + +void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha) { + q->cfo_ema_alpha = alpha; +} + float srslte_sync_get_last_peak_value(srslte_sync_t *q) { return q->peak_value; } @@ -156,10 +202,6 @@ float srslte_sync_get_peak_value(srslte_sync_t *q) { return q->mean_peak_value; } -void srslte_sync_correct_cfo(srslte_sync_t *q, bool enabled) { - q->correct_cfo = enabled; -} - void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { q->detect_cp = enabled; } @@ -177,6 +219,8 @@ srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) { } void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) { q->cp = cp; + q->cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(1,q->fft_size):SRSLTE_CP_LEN_EXT(q->fft_size); + q->nof_symbols = q->frame_size/(q->fft_size+q->cp_len)-1; } void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) { @@ -272,6 +316,10 @@ int sync_sss(srslte_sync_t *q, cf_t *input, uint32_t peak_pos, srslte_cp_t cp) { } } +srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) { + srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + return pss_obj[q->cfo_i+1]; +} /** Finds the PSS sequence previously defined by a call to srslte_sync_set_N_id_2() * around the position find_offset in the buffer input. @@ -298,12 +346,61 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32 *peak_position = 0; } + /* Estimate CFO using CP */ + uint32_t cp_offset = srslte_cp_synch(&q->cp_synch, input, q->nof_symbols, q->nof_symbols, SRSLTE_CP_LEN_NORM(1,q->fft_size)); + cf_t cp_corr_max = srslte_cp_synch_corr_output(&q->cp_synch, cp_offset); + float cfo = -carg(cp_corr_max) / M_PI / 2; + + /* compute cumulative moving average CFO */ + DEBUG("cp_offset_pos=%d, abs=%f, cfo=%f, mean_cfo=%f, nof_symb=%d\n", + cp_offset, cabs(cp_corr_max), cfo, q->mean_cfo, q->nof_symbols); + if (q->mean_cfo) { + q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); + } else { + q->mean_cfo = cfo; + } + + /* Correct CFO with the averaged CFO estimation */ + float correct_cfo = q->mean_cfo; + if (!q->find_cfo_i) { + correct_cfo = q->cfo_i + q->mean_cfo; + DEBUG("cfo_i disabled, correct_cfo=%d+%f=%f\n",q->cfo_i, q->mean_cfo, correct_cfo); + } + srslte_cfo_correct(&q->cfocorr, input, input, -correct_cfo / q->fft_size); + srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value); - if (peak_pos < 0) { - fprintf(stderr, "Error calling finding PSS sequence\n"); - return SRSLTE_ERROR; + if (q->find_cfo_i) { + float peak_value; + float max_peak_value = -99; + peak_pos = 0; + srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; + for (int cfo_i=0;cfo_i<3;cfo_i++) { + srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); + int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + if (peak_value > max_peak_value) { + max_peak_value = peak_value; + peak_pos = p; + q->peak_value = peak_value; + q->cfo_i = cfo_i-1; + } + } + if (q->cfo_i != 0) { + correct_cfo = q->cfo_i+q->mean_cfo; + srslte_vec_prod_ccc(input, q->cfo_i_corr[q->cfo_i<0?0:1], input, q->frame_size); + DEBUG("Compensating cfo_i=%d, total_cfo=%f\n", q->cfo_i, correct_cfo); + } + } else { + peak_pos = srslte_pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value); + if (peak_pos < 0) { + fprintf(stderr, "Error calling finding PSS sequence\n"); + return SRSLTE_ERROR; + } + if (q->max_offset<128) { + float temp[128]; + srslte_vec_sc_prod_fff(q->pss.conv_output_avg, 1e8, temp, q->max_offset); + srslte_vec_fprint_f(stdout, temp, q->max_offset); + } } q->mean_peak_value = SRSLTE_VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA); @@ -314,21 +411,6 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32 /* If peak is over threshold, compute CFO and SSS */ if (q->peak_value >= q->threshold) { - // Make sure we have enough space to estimate CFO - if (peak_pos + find_offset >= q->fft_size) { - float cfo = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]); - - /* compute cumulative moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, CFO_EMA_ALPHA); - } else { - DEBUG("No space for CFO computation. Frame starts at \n",peak_pos); - } - - /* Correct CFO with the averaged CFO estimation */ - if (q->correct_cfo) { - srslte_cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size); - } - // Try to detect SSS if (q->sss_en) { // Set an invalid N_id_1 indicating SSS is yet to be detected @@ -341,7 +423,7 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32 if (q->detect_cp) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - q->cp = srslte_sync_detect_cp(q, input, peak_pos + find_offset); + srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input, peak_pos + find_offset)); } else { DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } @@ -354,7 +436,7 @@ int srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32 } DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n", - ret, q->N_id_2, find_offset, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo); + ret, q->N_id_2, find_offset, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*correct_cfo); } else if (srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Must call srslte_sync_set_N_id_2() first!\n"); diff --git a/srslte/lib/sync/test/CMakeLists.txt b/srslte/lib/sync/test/CMakeLists.txt index 41499a37f..1af1f204f 100644 --- a/srslte/lib/sync/test/CMakeLists.txt +++ b/srslte/lib/sync/test/CMakeLists.txt @@ -45,6 +45,9 @@ ENDIF(UHD_FOUND) BuildMex(MEXNAME pss SOURCES pss_mex.c LIBRARIES srslte srslte_mex) BuildMex(MEXNAME sss SOURCES sss_mex.c LIBRARIES srslte srslte_mex) +# Build MEX for cp-based synchronization +BuildMex(MEXNAME cp_synch SOURCES cp_mex.c LIBRARIES srslte srslte_mex) + ######################################################################## # SYNC TEST ######################################################################## diff --git a/srslte/lib/sync/test/pss_mex.c b/srslte/lib/sync/test/pss_mex.c index 192e6a774..79466da8d 100644 --- a/srslte/lib/sync/test/pss_mex.c +++ b/srslte/lib/sync/test/pss_mex.c @@ -73,8 +73,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) fprintf(stderr, "Error initiating PSS\n"); exit(-1); } - if (srslte_pss_synch_set_N_id_2(&pss, cell.id%2)) { - fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%2); + if (srslte_pss_synch_set_N_id_2(&pss, cell.id%3)) { + fprintf(stderr, "Error setting N_id_2=%d\n",cell.id%3); exit(-1); } diff --git a/srslte/lib/sync/test/sync_test.c b/srslte/lib/sync/test/sync_test.c index a0ff9d715..c286e4749 100644 --- a/srslte/lib/sync/test/sync_test.c +++ b/srslte/lib/sync/test/sync_test.c @@ -115,7 +115,7 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_sync_init(&sync, FLEN, fft_size)) { + if (srslte_sync_init(&sync, FLEN, FLEN, fft_size)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } diff --git a/srslte/lib/ue/src/ue_sync.c b/srslte/lib/ue/src/ue_sync.c index 6dc73722f..80ab921e6 100644 --- a/srslte/lib/ue/src/ue_sync.c +++ b/srslte/lib/ue/src/ue_sync.c @@ -136,16 +136,16 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, /* If the cell is known, we work on a 1ms basis */ q->nof_recv_sf = 1; - q->decode_sss_on_track = false; + q->decode_sss_on_track = true; } q->frame_len = q->nof_recv_sf*q->sf_len; - if(srslte_sync_init(&q->sfind, q->frame_len, q->fft_size)) { + if(srslte_sync_init(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { fprintf(stderr, "Error initiating sync find\n"); goto clean_exit; } - if(srslte_sync_init(&q->strack, TRACK_FRAME_SIZE, q->fft_size)) { + if(srslte_sync_init(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { fprintf(stderr, "Error initiating sync track\n"); goto clean_exit; } @@ -154,12 +154,13 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, /* If the cell id is unknown, enable CP detection on find */ srslte_sync_cp_en(&q->sfind, true); srslte_sync_cp_en(&q->strack, true); - - /* Correct CFO in all cases because both states are called always. - */ - srslte_sync_correct_cfo(&q->sfind, true); - srslte_sync_correct_cfo(&q->strack, true); - + + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.9); + srslte_sync_set_cfo_ema_alpha(&q->strack, 0.4); + + srslte_sync_cfo_i_detec_en(&q->sfind, true); + srslte_sync_cfo_i_detec_en(&q->strack, true); + srslte_sync_set_threshold(&q->sfind, 1.5); q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; srslte_sync_set_threshold(&q->strack, 1.0); @@ -172,22 +173,22 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q, srslte_sync_cp_en(&q->sfind, false); srslte_sync_cp_en(&q->strack, false); + srslte_sync_cfo_i_detec_en(&q->sfind, true); + srslte_sync_cfo_i_detec_en(&q->strack, true); + + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.9); + srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); + /* 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. */ - srslte_sync_set_em_alpha(&q->sfind, 1); q->nof_avg_find_frames = 1; + srslte_sync_set_em_alpha(&q->sfind, 1); srslte_sync_set_threshold(&q->sfind, 4.0); srslte_sync_set_em_alpha(&q->strack, 0.1); srslte_sync_set_threshold(&q->strack, 1.3); - /* Correct CFO in the find state but not in the track state, since is called only - * 1 every 5 subframes. Will do it in the srslte_ue_sync_get_buffer() function. - */ - srslte_sync_correct_cfo(&q->sfind, true); - srslte_sync_correct_cfo(&q->strack, false); - } /* FIXME: Go for zerocopy only and eliminate this allocation */ @@ -298,7 +299,11 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) { q->mean_time_offset = 0; /* Goto Tracking state */ - q->state = SF_TRACK; + q->state = SF_TRACK; + + /* Initialize track state CFO */ + q->strack.mean_cfo = q->sfind.mean_cfo; + q->strack.cfo_i = q->sfind.cfo_i; } @@ -316,7 +321,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { } // Adjust time offset - q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2 - (int) q->strack.fft_size); + q->time_offset = ((int) track_idx - (int) q->strack.max_offset/2 - (int) q->strack.fft_size); if (q->time_offset) { DEBUG("Time offset adjustment: %d samples\n", q->time_offset); @@ -461,7 +466,7 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { /* track PSS/SSS around the expected PSS position */ ret = srslte_sync_find(&q->strack, input_buffer, - q->frame_len - q->sf_len/2 - q->fft_size - q->strack.frame_size/2, + q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx); if (ret < 0) { fprintf(stderr, "Error tracking correlation peak\n"); @@ -486,16 +491,17 @@ int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { } q->frame_total_cnt++; + } else { + /* Do CFO Correction if not in 0 or 5 subframes */ + if (q->correct_cfo) { + srslte_cfo_correct(&q->sfind.cfocorr, + input_buffer, + input_buffer, + -srslte_sync_get_cfo(&q->strack) / q->fft_size); + + } } - /* Do CFO Correction if not done in track and deliver the frame */ - if (!q->strack.correct_cfo && q->correct_cfo) { - srslte_cfo_correct(&q->sfind.cfocorr, - input_buffer, - input_buffer, - -srslte_sync_get_cfo(&q->strack) / q->fft_size); - - } break; }