mirror of https://github.com/PentHertz/srsLTE.git
Added CP-based autocorrelation CFO estimation. Added integer CFO estimation/correction. Improved overall synchronization performance
This commit is contained in:
parent
fc96b7f3e8
commit
83aba931e3
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -25,8 +25,56 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;i<max_offset;i++) {
|
||||
q->corr[i] = 0;
|
||||
cf_t *inputPtr = input;
|
||||
for (int n=0;n<nof_symbols;n++) {
|
||||
uint32_t cplen = (n%7)?cp_len:cp_len+1;
|
||||
q->corr[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
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
@ -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;t<q->frame_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");
|
||||
|
|
|
@ -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
|
||||
########################################################################
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue