Merged with #51

master
ismagom 10 years ago
parent 1e44b31fb3
commit fb6eb4f9d1

@ -86,6 +86,9 @@ IF(${CUHD_FIND} GREATER -1)
add_executable(cell_measurement cell_measurement.c cuhd_utils.c) add_executable(cell_measurement cell_measurement.c cuhd_utils.c)
target_link_libraries(cell_measurement cuhd lte_rrc lte_phy) target_link_libraries(cell_measurement cuhd lte_rrc lte_phy)
add_executable(cell_measurement cell_measurement.c cell_search_utils.c)
target_link_libraries(cell_measurement cuhd lte_phy)
MESSAGE(STATUS " UHD examples will be installed.") MESSAGE(STATUS " UHD examples will be installed.")
ELSE(${CUHD_FIND} GREATER -1) ELSE(${CUHD_FIND} GREATER -1)

@ -119,8 +119,8 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
int n; int n;
void *uhd; void *uhd;
ue_cell_search_t cs; ue_celldetect_t s;
ue_cell_search_result_t found_cells[3]; ue_celldetect_result_t found_cells[3];
int nof_freqs; int nof_freqs;
lte_earfcn_t channels[MAX_EARFCN]; lte_earfcn_t channels[MAX_EARFCN];
uint32_t freq; uint32_t freq;
@ -140,7 +140,22 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
for (freq=0;freq<nof_freqs;freq++) { if (ue_celldetect_init(&s)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
}
if (threshold > 0) {
ue_celldetect_set_threshold(&s, threshold);
}
if (nof_frames_total > 0) {
ue_celldetect_set_nof_frames_total(&s, nof_frames_total);
}
if (nof_frames_detected > 0) {
ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected);
}
for (freq=0;freq<nof_freqs;freq+=10) {
/* set uhd_freq */ /* set uhd_freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ); cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
@ -161,31 +176,15 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if (config.max_frames_pss) { n = find_all_cells(uhd, found_cells);
ue_cell_search_set_nof_frames_to_scan(&cs, config.max_frames_pss);
}
if (config.threshold) {
ue_cell_search_set_threshold(&cs, config.threshold);
}
INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000);
cuhd_set_rx_srate(uhd, CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
n = ue_cell_search_scan(&cs, found_cells, NULL);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error searching cell\n"); fprintf(stderr, "Error searching cell\n");
exit(-1); exit(-1);
} else if (n == 1) { } else if (n == 1) {
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
if (found_cells[i].peak > config.threshold/2) { if (found_cells[i].peak > threshold/2) {
lte_cell_t cell; if (decode_pbch(uhd, &found_cells[i], nof_frames_total, &mib)) {
cell.id = found_cells[i].cell_id; fprintf(stderr, "Error decoding PBCH\n");
cell.cp = found_cells[i].cp;
int ret = cuhd_mib_decoder(uhd, 100, &cell);
if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n");
exit(-1); exit(-1);
} }
if (ret == MIB_FOUND) { if (ret == MIB_FOUND) {

@ -0,0 +1,218 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
bool disable_plots;
int force_N_id_2;
char *uhd_args;
float uhd_freq;
float uhd_gain;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aglnvf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
/* TODO: Do something with the output data */
char data[10000];
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
prog_args_t prog_args;
lte_cell_t cell;
int64_t sf_cnt;
pbch_mib_t mib;
ue_sync_t ue_sync;
void *uhd;
parse_args(&prog_args, argc, argv);
printf("Opening UHD device...\n");
if (cuhd_open(prog_args.uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
/* Set receiver gain */
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
if (cell_search(uhd, prog_args.force_N_id_2, &cell, &mib)) {
fprintf(stderr, "Cell not found\n");
exit(-1);
}
cuhd_start_rx_stream(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
/* Initialize subframe counter */
sf_cnt = 0;
lte_fft_t fft;
chest_t chest;
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
return -1;
}
if (chest_init_LTEDL(&chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
return -1;
}
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
unsigned int nframes=0;
/* Main loop */
while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
float rssi=0, rsrp=0, rsrq=0;
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
/* Run FFT for all subframe data */
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
chest_measure_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(chest_rssi_sf(&chest, sf_symbols),rssi,nframes);
rsrq = VEC_CMA(chest_rsrq_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync)),rsrq,nframes);
rsrp = VEC_CMA(chest_rsrp_sf(&chest, ue_sync_get_sfidx(&ue_sync)),rsrp,nframes);
nframes++;
// Plot and Printf
if ((nframes%10) == 0) {
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, RSSI: %+5.2f dBm, RSRP: %+4.2f dBm, RSRQ: %4.2f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rssi*1000/4/cell.nof_prb/12/2)-prog_args.uhd_gain,
10*log10(rsrp*1000)-prog_args.uhd_gain,
10*log10(rsrq));
}
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop
ue_sync_free(&ue_sync);
cuhd_close(uhd);
printf("\nBye\n");
exit(0);
}

@ -101,7 +101,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
(symbol_idx-1)*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) (symbol_idx-1)*(symbol_sz+CP(symbol_sz, CPNORM_LEN))))
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define RE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx) #define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx)
#define RS_VSHIFT(cell_id) (cell_id%6) #define RS_VSHIFT(cell_id) (cell_id%6)

@ -76,9 +76,6 @@ typedef struct LIBLTE_API {
uint32_t m1; uint32_t m1;
float m0_value; float m0_value;
float m1_value; float m1_value;
float M_norm_avg;
float M_ext_avg;
}sync_t; }sync_t;
@ -138,6 +135,10 @@ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Sets the CP length estimation (must do it if disabled) */ /* Sets the CP length estimation (must do it if disabled) */
LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp); LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);
/* Enables/Disables SSS detection */ /* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q, LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled); bool enabled);

@ -56,9 +56,10 @@
#include "liblte/phy/common/fft.h" #include "liblte/phy/common/fft.h"
#define MIB_MAX_PORTS 4 #define MIB_NOF_PORTS 2
#define MIB_NOF_PRB 6 #define MIB_FRAME_SIZE 9600
#define MIB_FRAME_UNALIGNED -3
#define MIB_FOUND 1 #define MIB_FOUND 1
#define MIB_NOTFOUND 0 #define MIB_NOTFOUND 0

@ -35,15 +35,11 @@
typedef _Complex float cf_t; typedef _Complex float cf_t;
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
// Cumulative moving average // Cumulative moving average
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1)) #define VEC_CMA(data, average, n) ((data) + ((data) - (average)) / ((n)+1))
// Exponential moving average // Exponential moving average
#define VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average)) #define VEC_EMA(data, average, alpha) ((factor)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */ /** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, uint32_t len); LIBLTE_API int vec_acc_ii(int *x, uint32_t len);

@ -30,17 +30,6 @@ ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0)
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1) ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1)
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2) ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)
ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0 -r 50)
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1 -r 50)
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50)
########################################################################
# Downlink MEX libs
########################################################################
BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES lte_phy)
######################################################################## ########################################################################
# Uplink Channel Estimation TEST # Uplink Channel Estimation TEST
######################################################################## ########################################################################
@ -54,9 +43,3 @@ BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES lte_phy)

@ -1,253 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <complex.h>
#include "liblte/phy/phy.h"
lte_cell_t cell = {
6, // nof_prb
1, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
char *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
cell.nof_prb = atoi(argv[optind]);
break;
case 'e':
cell.cp = CPEXT;
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char **argv) {
chest_dl_t est;
precoding_t cheq;
cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL;
int i, j, n_port, sf_idx, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
parse_args(argc,argv);
if (output_matlab) {
fmatlab=fopen(output_matlab, "w");
if (!fmatlab) {
perror("fopen");
goto do_exit;
}
}
num_re = 2 * cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
output = malloc(num_re * sizeof(cf_t));
if (!output) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
goto do_exit;
}
ce = malloc(num_re * sizeof(cf_t));
if (!ce) {
perror("malloc");
goto do_exit;
}
if (cell.id == 1000) {
cid = 0;
max_cid = 504;
} else {
cid = cell.id;
max_cid = cell.id;
}
precoding_init(&cheq, num_re);
while(cid <= max_cid) {
cell.id = cid;
if (chest_dl_init(&est, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
for (sf_idx=0;sf_idx<1;sf_idx++) {
for (n_port=0;n_port<cell.nof_ports;n_port++) {
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
}
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_cs_put_sf(cell, n_port,
est.csr_signal.pilots[n_port/2][sf_idx], input);
for (i=0;i<2*CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
}
}
struct timeval t[3];
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
chest_dl_estimate_port(&est, input, ce, sf_idx, n_port);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEST: %f us\n", (float) t[0].tv_usec/100);
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
predecoding_single(&cheq, input, ce, output, num_re, 0);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEQ-ZF: %f us\n", (float) t[0].tv_usec/100);
float mse = 0;
for (i=0;i<num_re;i++) {
mse += cabsf(input[i]-output[i]);
}
mse /= num_re;
printf("MSE: %f\n", mse);
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
predecoding_single(&cheq, input, ce, output, num_re, chest_dl_get_noise_estimate(&est));
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEQ-MMSE: %f us\n", (float) t[0].tv_usec/100);
mse = 0;
for (i=0;i<num_re;i++) {
mse += cabsf(input[i]-output[i]);
}
mse /= num_re;
printf("MSE: %f\n", mse);
if (mse > 1.7) {
goto do_exit;
}
if (fmatlab) {
fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
}
}
}
chest_dl_free(&est);
cid+=10;
INFO("cid=%d\n", cid);
}
ret = 0;
do_exit:
precoding_free(&cheq);
if (output) {
free(output);
}
if (ce) {
free(ce);
}
if (input) {
free(input);
}
if (h) {
free(h);
}
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, sf_idx, n_port);
}
exit(ret);
}

@ -1,249 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE 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 Lesser General Public License for more details.
*
* A copy of the GNU Lesser 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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <complex.h>
#include "liblte/phy/phy.h"
lte_cell_t cell = {
6, // nof_prb
MAX_PORTS, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
uint8_t *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
cell.nof_prb = atoi(argv[optind]);
break;
case 'e':
cell.cp = CPEXT;
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int check_mse(float mod, float arg, int n_port) {
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) {
case 0:
if (mod > 0.029) {
return -1;
}
if (arg > 0.029) {
return -1;
}
break;
case 1:
if (mod > 0.012) {
return -1;
}
if (arg > 0.012) {
return -1;
}
break;
case 2:
case 3:
if (mod > 3.33) {
return -1;
}
if (arg > 0.63) {
return -1;
}
break;
default:
return -1;
}
return 0;
}
int main(int argc, char **argv) {
chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
float mse_mag, mse_phase;
parse_args(argc,argv);
if (output_matlab) {
fmatlab=fopen(output_matlab, "w");
if (!fmatlab) {
perror("fopen");
goto do_exit;
}
}
num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
goto do_exit;
}
ce = malloc(num_re * sizeof(cf_t));
if (!ce) {
perror("malloc");
goto do_exit;
}
if (cell.id == 1000) {
cid = 0;
max_cid = 504;
} else {
cid = cell.id;
max_cid = cell.id;
}
while(cid <= max_cid) {
cell.id = cid;
if (chest_init_LTEUL(&eq, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<cell.nof_ports;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
}
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input);
for (i=0;i<CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
}
}
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
mse_mag = mse_phase = 0;
for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
}
if (check_mse(mse_mag, mse_phase, n_port)) {
goto do_exit;
}
if (fmatlab) {
fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port);
}
}
}
chest_free(&eq);
cid+=10;
INFO("cid=%d\n", cid);
}
ret = 0;
do_exit:
if (ce) {
free(ce);
}
if (input) {
free(input);
}
if (h) {
free(h);
}
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
}
exit(ret);
}

@ -613,8 +613,11 @@ int pdsch_decode_tb(pdsch_t *q, uint8_t *data, uint32_t tbs, uint32_t nb_e,
} }
} while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop); } while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop);
q->average_nof_iterations = VEC_EMA((float) q->nof_iterations, q->average_nof_iterations, 0.2);
q->average_nof_iterations = VEC_CMA((float) q->nof_iterations,
q->average_nof_iterations,
q->average_nof_iterations_n);
q->average_nof_iterations_n++;
/* Copy data to another buffer, removing the Codeblock CRC */ /* Copy data to another buffer, removing the Codeblock CRC */
if (i < harq_process->cb_segm.C - 1) { if (i < harq_process->cb_segm.C - 1) {

@ -321,51 +321,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1);
/* Find maximum of the absolute value of the correlation */ /* Find maximum of the absolute value of the correlation */
corr_peak_pos = vec_max_fi(q->conv_output_avg, conv_output_len-1); corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len-1);
// save absolute value
q->peak_value = q->conv_output_avg[corr_peak_pos];
#ifdef PSS_RETURN_PSR
// Find second side lobe
// Find end of peak lobe to the right
int pl_ub = corr_peak_pos+1;
while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) {
pl_ub ++;
}
// Find end of peak lobe to the left
int pl_lb;
if (corr_peak_pos > 0) {
pl_lb = corr_peak_pos-1;
while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) {
pl_lb --;
}
} else {
pl_lb = 0;
}
int sl_distance_right = conv_output_len-1-pl_ub;
if (sl_distance_right < 0) {
sl_distance_right = 0;
}
int sl_distance_left = pl_lb;
int sl_right = pl_ub+vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right);
int sl_left = vec_max_fi(q->conv_output_avg, sl_distance_left);
float side_lobe_value = MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]);
if (corr_peak_value) {
*corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value;
if (*corr_peak_value < 2.0) {
DEBUG("pl_ub=%d, pl_lb=%d, sl_right: %d (%.2f), sl_left: %d (%.2f), PSR: %.2f/%.2f=%.2f\n", pl_ub, pl_lb,
sl_right, 1000000*q->conv_output_avg[sl_right],
sl_left, 1000000*q->conv_output_avg[sl_left],
1000000*q->conv_output_avg[corr_peak_pos], 1000000*side_lobe_value,*corr_peak_value
);
}
}
#else
if (corr_peak_value) { if (corr_peak_value) {
*corr_peak_value = q->conv_output_avg[corr_peak_pos]; *corr_peak_value = q->conv_output_avg[corr_peak_pos];
} }

@ -59,8 +59,8 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
bzero(q, sizeof(sync_t)); bzero(q, sizeof(sync_t));
q->detect_cp = true; q->detect_cp = true;
q->cp = CPNORM; q->normalize_en = true;
q->mean_peak_value = 0.0; q->mean_energy = 1.0;
q->sss_en = true; q->sss_en = true;
q->correct_cfo = true; q->correct_cfo = true;
q->mean_cfo = 0; q->mean_cfo = 0;
@ -175,10 +175,6 @@ void sync_set_cp(sync_t *q, lte_cp_t cp) {
q->cp = cp; q->cp = cp;
} }
void sync_set_sss_algorithm(sync_t *q, sss_alg_t alg) {
q->sss_alg = alg;
}
/* CP detection algorithm taken from: /* CP detection algorithm taken from:
* "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver" * "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
* by Jung-In Kim et al. * by Jung-In Kim et al.
@ -227,33 +223,20 @@ lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
} }
} }
/* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
* to correlate
*/
int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, lte_cp_t cp) {
int sss_idx, ret; int sss_idx, ret;
sss_synch_set_N_id_2(&q->sss, q->N_id_2); sss_synch_set_N_id_2(&q->sss, q->N_id_2);
/* Make sure we have enough room to find SSS sequence */ /* Make sure we have enough room to find SSS sequence */
sss_idx = (int) peak_pos-2*q->fft_size-CP(q->fft_size, (CP_ISNORM(q->cp)?CPNORM_LEN:CPEXT_LEN)); sss_idx = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, q->cp));
if (sss_idx < 0) { if (sss_idx < 0) {
INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos); INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos);
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos); DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos);
switch(q->sss_alg) { sss_synch_m0m1(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
case SSS_DIFF:
sss_synch_m0m1_diff(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
case SSS_PARTIAL_3:
sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
case SSS_FULL:
sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
}
q->sf_idx = sss_synch_subframe(q->m0, q->m1); q->sf_idx = sss_synch_subframe(q->m0, q->m1);
ret = sss_synch_N_id_1(&q->sss, q->m0, q->m1); ret = sss_synch_N_id_1(&q->sss, q->m0, q->m1);
@ -281,6 +264,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
float peak_unnormalized=0, energy=1;
if (q != NULL && if (q != NULL &&
input != NULL && input != NULL &&
lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_2_isvalid(q->N_id_2) &&
@ -288,68 +273,63 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
{ {
int peak_pos; int peak_pos;
ret = LIBLTE_SUCCESS;
if (peak_position) { if (peak_position) {
*peak_position = 0; *peak_position = 0;
} }
pss_synch_set_N_id_2(&q->pss, q->N_id_2); pss_synch_set_N_id_2(&q->pss, q->N_id_2);
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value); peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized);
if (peak_pos < 0) { if (peak_pos < 0) {
fprintf(stderr, "Error calling finding PSS sequence\n"); fprintf(stderr, "Error calling finding PSS sequence\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
if (q->normalize_en &&
peak_pos + find_offset >= q->fft_size)
{
/* Compute the energy of the received PSS sequence to normalize */
cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size];
energy = sqrtf(crealf(vec_dot_prod_conj_ccc(pss_ptr, pss_ptr, q->fft_size)) / (q->fft_size));
q->mean_energy = VEC_CMA(energy, q->mean_energy, q->frame_cnt);
} else {
if (q->mean_energy == 0.0) {
q->mean_energy = 1.0;
}
energy = q->mean_energy;
}
q->mean_peak_value = VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA); q->mean_peak_value = VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA);
if (peak_position) { /* Normalize and compute mean peak value */
*peak_position = (uint32_t) peak_pos; q->peak_value = peak_unnormalized/energy;
} q->mean_peak_value = VEC_CMA(q->peak_value, q->mean_peak_value, q->frame_cnt);
q->frame_cnt++;
/* If peak is over threshold, compute CFO and SSS */ /* If peak is over threshold, compute CFO and SSS */
if (q->peak_value >= q->threshold) { if (q->peak_value >= q->threshold) {
if (find_offset + peak_pos >= q->fft_size) {
// Make sure we have enough space to estimate CFO q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
if (peak_pos + find_offset >= q->fft_size) { if (q->sss_en) {
float cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]); ret = sync_sss(q, input, find_offset + peak_pos);
if (ret < 0) {
/* compute cumulative moving average CFO */ fprintf(stderr, "Error synchronizing with SSS\n");
q->mean_cfo = VEC_EMA(cfo, q->mean_cfo, CFO_EMA_ALPHA); return LIBLTE_ERROR;
} else {
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
} }
if (q->detect_cp) {
if (peak_pos + find_offset >= 2*(q->fft_size + CP_EXT(q->fft_size))) {
q->cp = sync_detect_cp(q, input, peak_pos + find_offset);
} else { } else {
INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos); ret = 1;
}
} }
} else {
// Try to detect SSS INFO("No space for CFO computation. Frame starts at \n",peak_pos);
if (q->sss_en) {
/* Correct CFO with the averaged CFO estimation */
if (q->mean_cfo && q->correct_cfo) {
cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size);
} }
// Set an invalid N_id_1 indicating SSS is yet to be detected if (peak_position) {
q->N_id_1 = 1000; *peak_position = (uint32_t) peak_pos;
if (sync_sss(q, input, find_offset + peak_pos, q->cp) < 0) {
INFO("No space for SSS processing. Frame starts at %d\n", peak_pos);
}
} }
// Return 1 (peak detected) even if we couldn't estimate CFO and SSS
ret = 1;
} else { } else {
ret = 0; ret = 0;
} }
INFO("SYNC ret=%d N_id_2=%d find_offset=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n", INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f threshold=%.2f sf_idx=%d offset=%d\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, peak_pos, peak_unnormalized,energy,q->peak_value, q->threshold, q->sf_idx, find_offset);
} else if (lte_N_id_2_isvalid(q->N_id_2)) { } else if (lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Must call sync_set_N_id_2() first!\n"); fprintf(stderr, "Must call sync_set_N_id_2() first!\n");

@ -220,7 +220,9 @@ int main(int argc, char **argv) {
mean_peak = VEC_CMA(peak_value, mean_peak, frame_cnt); mean_peak = VEC_CMA(peak_value, mean_peak, frame_cnt);
if (peak_value >= threshold) { mean_peak = VEC_CMA(x, mean_peak, frame_cnt);
if (x >= threshold) {
nof_det++; nof_det++;
if (peak_idx >= fft_size) { if (peak_idx >= fft_size) {

@ -192,7 +192,12 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
/* Get channel estimates for each port */ /* Get channel estimates for each port */
chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx); chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx);
gettimeofday(&t[2], NULL);
get_time_interval(t);
mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, mean_exec_time, frame_cnt);
frame_cnt++;
/* First decode PCFICH and obtain CFI */ /* First decode PCFICH and obtain CFI */
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,

@ -36,8 +36,14 @@
#include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/vector.h"
#define FIND_FFTSIZE 128
#define FIND_SFLEN 5*SF_LEN(FIND_FFTSIZE)
#define MIB_FIND_THRESHOLD 0.0
int ue_mib_init(ue_mib_t * q, int ue_mib_init(ue_mib_t * q,
lte_cell_t cell) uint32_t cell_id,
lte_cp_t cp)
{ {
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
@ -62,7 +68,17 @@ int ue_mib_init(ue_mib_t * q,
} }
} }
if (lte_fft_init(&q->fft, cell.cp, cell.nof_prb)) { if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) {
goto clean_exit;
}
sync_set_threshold(&q->sfind, MIB_FIND_THRESHOLD);
sync_sss_en(&q->sfind, true);
sync_set_N_id_2(&q->sfind, cell_id % 3);
sync_cp_en(&q->sfind, false);
sync_set_cp(&q->sfind, cp);
if (lte_fft_init(&q->fft, cp, cell.nof_prb)) {
fprintf(stderr, "Error initializing FFT\n"); fprintf(stderr, "Error initializing FFT\n");
goto clean_exit; goto clean_exit;
} }
@ -114,45 +130,48 @@ void ue_mib_reset(ue_mib_t * q)
int ue_mib_decode(ue_mib_t * q, cf_t *input, int ue_mib_decode(ue_mib_t * q, cf_t *input,
uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset) uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset)
{
sync_set_threshold(&q->sfind, threshold);
}
static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib)
{ {
int ret = LIBLTE_SUCCESS; int ret = LIBLTE_SUCCESS;
cf_t *ce_slot1[MAX_PORTS];
/* Run FFT for the slot symbols */ /* Run FFT for the slot symbols */
lte_fft_run_sf(&q->fft, input, q->sf_symbols); lte_fft_run_sf(&q->fft, input, q->sf_symbols);
/* Get channel estimates of slot #1 for each port */ /* Get channel estimates of slot #1 for each port */
ret = chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0); ret = chest_ce_slot(&q->chest, q->slot1_symbols, q->ce, 1);
if (ret < 0) { if (ret < 0) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
/* Reset decoder if we missed a frame */ /* Reset decoder if we missed a frame */
if (q->frame_cnt > 8) { if ((q->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) ||
INFO("Resetting PBCH decoder after %d frames\n", q->frame_cnt); q->frame_cnt > 16)
{
INFO("Resetting PBCH decoder: last trial %u, now is %u\n",
q->last_frame_trial, q->frame_cnt);
ue_mib_reset(q); ue_mib_reset(q);
} }
for (int i=0;i<MAX_PORTS;i++) {
ce_slot1[i] = &q->ce[i][SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)];
}
/* Decode PBCH */ /* Decode PBCH */
ret = pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], ret = pbch_decode(&q->pbch, q->slot1_symbols, q->ce, mib);
ce_slot1, chest_dl_get_noise_estimate(&q->chest),
bch_payload, nof_tx_ports, sfn_offset);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error decoding PBCH (%d)\n", ret); fprintf(stderr, "Error decoding PBCH\n");
} else if (ret == 1) { } else if (ret == 1) {
INFO("MIB decoded: %u\n", q->frame_cnt); INFO("MIB decoded: %u\n", q->frame_cnt/2);
ue_mib_reset(q); ue_mib_reset(q);
ret = MIB_FOUND; ret = MIB_FOUND;
} else { } else {
INFO("MIB not decoded: %u\n", q->frame_cnt); INFO("MIB not decoded: %u\n", q->frame_cnt / 2);
q->frame_cnt++; q->last_frame_trial = q->frame_cnt;
ret = MIB_NOTFOUND; ret = LIBLTE_SUCCESS;
} }
return ret; return ret;
} }
int counter1=0,counter2=0,counter3=0,counter4=0;
@ -162,73 +181,74 @@ int ue_mib_sync_init(ue_mib_sync_t *q,
int (recv_callback)(void*, void*, uint32_t), int (recv_callback)(void*, void*, uint32_t),
void *stream_handler) void *stream_handler)
{ {
lte_cell_t cell; int ret = LIBLTE_ERROR_INVALID_INPUTS;
cell.nof_ports = MIB_MAX_PORTS; uint32_t peak_idx=0;
cell.id = cell_id; uint32_t nof_input_frames;
cell.cp = cp;
cell.nof_prb = MIB_NOF_PRB;
if (ue_mib_init(&q->ue_mib, cell)) {
fprintf(stderr, "Error initiating ue_mib\n");
return LIBLTE_ERROR;
}
if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) {
fprintf(stderr, "Error initiating ue_sync\n");
ue_mib_free(&q->ue_mib);
return LIBLTE_ERROR;
}
ue_sync_decode_sss_on_track(&q->ue_sync, true);
return LIBLTE_SUCCESS;
}
void ue_mib_sync_free(ue_mib_sync_t *q) { void ue_mib_sync_free(ue_mib_sync_t *q) {
ue_mib_free(&q->ue_mib); ue_mib_free(&q->ue_mib);
ue_sync_free(&q->ue_sync); ue_sync_free(&q->ue_sync);
} }
void ue_mib_sync_reset(ue_mib_sync_t * q) { if (q != NULL &&
ue_mib_reset(&q->ue_mib); signal != NULL)
ue_sync_reset(&q->ue_sync); {
if (nsamples < MIB_FRAME_SIZE) {
fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE);
return LIBLTE_ERROR;
} }
int ue_mib_sync_decode(ue_mib_sync_t * q, ret = LIBLTE_SUCCESS;
uint32_t max_frames_timeout,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS; if (nsamples % MIB_FRAME_SIZE) {
cf_t *sf_buffer = NULL; printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE);
uint32_t nof_frames = 0; nsamples = (nsamples/MIB_FRAME_SIZE) * MIB_FRAME_SIZE;
int mib_ret = MIB_NOTFOUND; }
nof_input_frames = nsamples/MIB_FRAME_SIZE;
if (q != NULL) for (uint32_t nf=0;nf<nof_input_frames;nf++) {
{
ret = LIBLTE_SUCCESS; /* Find peak and cell id */
do { ret = sync_find(&q->sfind, signal, nf*MIB_FRAME_SIZE, &peak_idx);
mib_ret = MIB_NOTFOUND;
ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n"); fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
break; return -1;
} else if (ue_sync_get_sfidx(&q->ue_sync) == 0) { }
if (ret == 1) {
ue_mib_reset(&q->ue_mib);
mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
} else { if (ret == 0) {
INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt); counter2++;
ue_mib_reset(&q->ue_mib); } else if (ret == 1) {
counter4++;
} }
nof_frames++;
/* Check if we have space for reading the MIB and we are in Subframe #0 */
if (ret == 1 &&
nf*MIB_FRAME_SIZE + peak_idx + 960 <= nsamples &&
sync_sss_detected(&q->sfind) &&
sync_get_sf_idx(&q->sfind) == 0)
{
INFO("Trying to decode MIB\n",0);
ret = mib_decoder_run(q, &signal[nf*MIB_FRAME_SIZE+peak_idx], mib);
counter3++;
} else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) ||
(ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 > nsamples))
{
printf("Not enough space for PBCH\n",0);
ret = MIB_FRAME_UNALIGNED;
} else {
INFO("SSS not detected\n",0);
ret = 0;
} }
} while (mib_ret == MIB_NOTFOUND && ret >= 0 && nof_frames < max_frames_timeout);
if (mib_ret < 0) { counter1++;
ret = mib_ret; INFO("Total: %3d - Sync0: %3d - Sync1: %3d - Tried: %3d - Peak: %4d - Ret: %d\n",counter1,counter2,counter4, counter3, peak_idx, ret);
q->frame_cnt++;
} }
} }
return mib_ret; return mib_ret;
} }

@ -46,17 +46,8 @@ cf_t dummy[MAX_TIME_OFFSET];
#define TRACK_FRAME_SIZE 32 #define TRACK_FRAME_SIZE 32
#define FIND_NOF_AVG_FRAMES 2 #define FIND_NOF_AVG_FRAMES 2
int ue_sync_init_file(ue_sync_t *q, uint32_t nof_prb, char *file_name) { #define FIND_THRESHOLD 1.2
int ret = LIBLTE_ERROR_INVALID_INPUTS; #define TRACK_THRESHOLD 0.2
if (q != NULL &&
file_name != NULL &&
lte_nofprb_isvalid(nof_prb))
{
ret = LIBLTE_ERROR;
bzero(q, sizeof(ue_sync_t));
q->file_mode = true;
q->sf_len = SF_LEN(lte_symbol_sz(nof_prb));
if (filesource_init(&q->file_source, file_name, COMPLEX_FLOAT_BIN)) { if (filesource_init(&q->file_source, file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", file_name); fprintf(stderr, "Error opening file %s\n", file_name);
@ -217,7 +208,7 @@ float ue_sync_get_cfo(ue_sync_t *q) {
} }
float ue_sync_get_sfo(ue_sync_t *q) { float ue_sync_get_sfo(ue_sync_t *q) {
return 5000*q->mean_time_offset; return 1000*q->mean_time_offset;
} }
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
@ -276,12 +267,11 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
/* Make sure subframe idx is what we expect */ /* Make sure subframe idx is what we expect */
if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) { if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) {
if (sync_get_cell_id(&q->strack) == q->cell.id) {
INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n", INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n",
q->sf_idx, sync_get_sf_idx(&q->strack), q->sf_idx, sync_get_sf_idx(&q->strack), q->strack.m0, q->strack.m1, q->strack.m0_value, q->strack.m1_value);
q->strack.m0, q->strack.m0_value, q->strack.m1, q->strack.m1_value); /* FIXME: What should we do in this case? */
q->sf_idx = sync_get_sf_idx(&q->strack); q->sf_idx = sync_get_sf_idx(&q->strack);
} q->state = SF_TRACK;
} else { } else {
// Adjust time offset // 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.frame_size/2 - (int) q->strack.fft_size);
@ -304,7 +294,12 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
q->time_offset = 0; q->time_offset = 0;
} }
q->peak_idx = q->sf_len/2 + q->time_offset; /* compute cumulative moving average CFO */
q->cur_cfo = VEC_CMA(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt);
/* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt);
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
q->frame_ok_cnt++; q->frame_ok_cnt++;
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
} }
@ -444,13 +439,16 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
q->frame_total_cnt++; q->frame_total_cnt++;
} }
/* Do CFO Correction if not done in track and deliver the frame */ #ifdef MEASURE_EXEC_TIME
if (!q->strack.correct_cfo) { gettimeofday(&t[2], NULL);
cfo_correct(&q->sfind.cfocorr, get_time_interval(t);
q->input_buffer, q->mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
q->input_buffer, #endif
-sync_get_cfo(&q->strack) / q->fft_size);
if (ret == 1) {
ret = track_peak_ok(q, track_idx);
} else {
ret = track_peak_no(q);
} }
*sf_symbols = q->input_buffer; *sf_symbols = q->input_buffer;

@ -29,22 +29,19 @@
#include <complex.h> #include <complex.h>
#include <math.h> #include <math.h>
#ifndef _LTE_RRC_ int decode_pbch(void *uhd,
#define _LTE_RRC_ ue_celldetect_result_t *found_cell,
uint32_t nof_frames_total,
#ifdef __cplusplus pbch_mib_t *mib);
extern "C" {
#endif int find_all_cells(void *uhd,
ue_celldetect_result_t found_cell[3]);
#include "liblte/config.h"
int find_cell(void *uhd,
#include "liblte/rrc/messages/bcch.h" ue_celldetect_result_t *found_cell,
#include "liblte/rrc/messages/sib1.h" uint32_t N_id_2);
#include "liblte/rrc/messages/sib4.h"
#include "liblte/rrc/common/rrc_common.h" int cell_search(void *uhd,
int force_N_id_2,
#ifdef __cplusplus lte_cell_t *cell,
} pbch_mib_t *mib);
#endif
#endif
Loading…
Cancel
Save