Merge branch 'improve_cfo'

master
ismagom 9 years ago
commit db1ceae5e3

@ -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,7 +3,7 @@ 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));

@ -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;

@ -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
}

@ -0,0 +1,55 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef CP_
#define CP_
#include <stdint.h>
#include <complex.h>
#include "srslte/config.h"
typedef struct {
cf_t *corr;
uint32_t symbol_sz;
} srslte_cp_synch_t;
SRSLTE_API int srslte_cp_synch_init(srslte_cp_synch_t *q,
uint32_t symbol_sz);
SRSLTE_API void srslte_cp_synch_free(srslte_cp_synch_t *q);
SRSLTE_API 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);
SRSLTE_API cf_t srslte_cp_synch_corr_output(srslte_cp_synch_t *q,
uint32_t offset);
#endif // CP_

@ -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_

@ -342,7 +342,6 @@ int srslte_pusch_cfg(srslte_pusch_t *q,
if (cfg->grant.n_prb_tilde[ns] == k0_srs + nrb_srs || // If PUSCH is contiguous on the right-hand side of SRS
cfg->grant.n_prb_tilde[ns] + cfg->grant.L_prb == k0_srs) // If SRS is contiguous on the left-hand side of PUSCH
{
printf("Not shortened because are continuous, k0_srs=%d, L_srs=%d, n_prb=%d, L_prb=%d\n", k0_srs, nrb_srs, cfg->grant.n_prb_tilde[ns], cfg->grant.L_prb);
q->shortened = false;
}
}

@ -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 */
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) {
@ -101,7 +106,6 @@ int srslte_pss_synch_init_fft(srslte_pss_synch_t *q, uint32_t frame_size, uint32
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,11 +362,9 @@ 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,
sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value);
}
}
#else
if (corr_peak_value) {
*corr_peak_value = q->conv_output_avg[corr_peak_pos];
@ -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;
if (srslte_pss_synch_init_fft(&q->pss, frame_size, fft_size)) {
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;
}
}
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,13 +346,62 @@ 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);
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);
if (peak_position) {
@ -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
########################################################################

@ -0,0 +1,94 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 The srsLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include "srslte/srslte.h"
#include "srslte/mex/mexutils.h"
/** MEX function to be called from MATLAB to test the channel estimator
*/
#define ENBCFG prhs[0]
#define INPUT prhs[1]
#define NOF_INPUTS 2
void help()
{
mexErrMsgTxt
("[offset,corr] = srslte_cp_synch(enbConfig, inputSignal)\n\n");
}
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
srslte_cell_t cell;
srslte_cp_synch_t cp_synch;
cf_t *input_symbols;
int frame_len;
if (nrhs != NOF_INPUTS) {
help();
return;
}
if (mexutils_read_cell(ENBCFG, &cell)) {
help();
return;
}
/** Allocate input buffers */
frame_len = mexutils_read_cf(INPUT, &input_symbols);
if (frame_len < 0) {
mexErrMsgTxt("Error reading input symbols\n");
return;
}
uint32_t symbol_sz = srslte_symbol_sz(cell.nof_prb);
if (srslte_cp_synch_init(&cp_synch, symbol_sz)) {
fprintf(stderr, "Error initiating CP\n");
return;
}
uint32_t cp_len = SRSLTE_CP_LEN_NORM(1, symbol_sz);
uint32_t nsymbols = frame_len/(symbol_sz+cp_len)-1;
uint32_t peak_idx = srslte_cp_synch(&cp_synch, input_symbols, symbol_sz, nsymbols, cp_len);
if (nlhs >= 1) {
plhs[0] = mxCreateDoubleScalar(peak_idx);
}
if (nlhs >= 2) {
mexutils_write_cf(cp_synch.corr, &plhs[1], symbol_sz, 1);
}
srslte_cp_synch_free(&cp_synch);
free(input_symbols);
return;
}

@ -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;
}
@ -155,10 +155,11 @@ int srslte_ue_sync_init(srslte_ue_sync_t *q,
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;
@ -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 */
@ -299,6 +300,10 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer) {
/* Goto Tracking state */
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++;
}
/* Do CFO Correction if not done in track and deliver the frame */
if (!q->strack.correct_cfo && q->correct_cfo) {
} 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);
}
}
break;
}

Loading…
Cancel
Save