mirror of https://github.com/PentHertz/srsLTE.git
Fixed merge conflicts with ismagom fork
This commit is contained in:
parent
4a9164b900
commit
ee4c80d340
|
@ -86,9 +86,6 @@ 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_celldetect_t s;
|
ue_cell_search_t cs;
|
||||||
ue_celldetect_result_t found_cells[3];
|
ue_cell_search_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,22 +140,7 @@ int main(int argc, char **argv) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ue_celldetect_init(&s)) {
|
for (freq=0;freq<nof_freqs;freq++) {
|
||||||
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);
|
||||||
|
@ -176,15 +161,31 @@ int main(int argc, char **argv) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
n = find_all_cells(uhd, found_cells);
|
if (config.max_frames_pss) {
|
||||||
|
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 > threshold/2) {
|
if (found_cells[i].peak > config.threshold/2) {
|
||||||
if (decode_pbch(uhd, &found_cells[i], nof_frames_total, &mib)) {
|
lte_cell_t cell;
|
||||||
fprintf(stderr, "Error decoding PBCH\n");
|
cell.id = found_cells[i].cell_id;
|
||||||
|
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) {
|
||||||
|
|
|
@ -1,218 +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 <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 SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx)
|
#define RE_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,6 +76,9 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,10 +138,6 @@ 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,10 +56,9 @@
|
||||||
#include "liblte/phy/common/fft.h"
|
#include "liblte/phy/common/fft.h"
|
||||||
|
|
||||||
|
|
||||||
#define MIB_NOF_PORTS 2
|
#define MIB_MAX_PORTS 4
|
||||||
#define MIB_FRAME_SIZE 9600
|
#define MIB_NOF_PRB 6
|
||||||
|
|
||||||
#define MIB_FRAME_UNALIGNED -3
|
|
||||||
#define MIB_FOUND 1
|
#define MIB_FOUND 1
|
||||||
#define MIB_NOTFOUND 0
|
#define MIB_NOTFOUND 0
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,15 @@
|
||||||
|
|
||||||
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) ((data) + ((data) - (average)) / ((n)+1))
|
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1))
|
||||||
|
|
||||||
// Exponential moving average
|
// Exponential moving average
|
||||||
#define VEC_EMA(data, average, alpha) ((factor)*(data)+(1-alpha)*(average))
|
#define VEC_EMA(data, average, alpha) ((alpha)*(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,6 +30,17 @@ 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
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -43,3 +54,9 @@ ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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);
|
||||||
|
}
|
|
@ -0,0 +1,249 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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,11 +613,8 @@ 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,7 +321,51 @@ 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_abs_ci(q->conv_output, conv_output_len-1);
|
corr_peak_pos = vec_max_fi(q->conv_output_avg, 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->normalize_en = true;
|
q->cp = CPNORM;
|
||||||
q->mean_energy = 1.0;
|
q->mean_peak_value = 0.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,6 +175,10 @@ 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.
|
||||||
|
@ -223,20 +227,33 @@ lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sync_sss(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
|
||||||
|
* 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, q->cp));
|
sss_idx = (int) peak_pos-2*q->fft_size-CP(q->fft_size, (CP_ISNORM(q->cp)?CPNORM_LEN:CPEXT_LEN));
|
||||||
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);
|
||||||
|
|
||||||
sss_synch_m0m1(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
|
switch(q->sss_alg) {
|
||||||
|
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);
|
||||||
|
@ -264,8 +281,6 @@ 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) &&
|
||||||
|
@ -273,63 +288,68 @@ 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], &peak_unnormalized);
|
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value);
|
||||||
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);
|
||||||
|
|
||||||
/* Normalize and compute mean peak value */
|
|
||||||
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 (q->peak_value >= q->threshold) {
|
|
||||||
if (find_offset + peak_pos >= q->fft_size) {
|
|
||||||
q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
|
|
||||||
if (q->sss_en) {
|
|
||||||
ret = sync_sss(q, input, find_offset + peak_pos);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Error synchronizing with SSS\n");
|
|
||||||
return LIBLTE_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peak_position) {
|
if (peak_position) {
|
||||||
*peak_position = (uint32_t) peak_pos;
|
*peak_position = (uint32_t) peak_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
|
||||||
|
|
||||||
|
/* compute cumulative moving average CFO */
|
||||||
|
q->mean_cfo = VEC_EMA(cfo, q->mean_cfo, CFO_EMA_ALPHA);
|
||||||
|
} 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 {
|
||||||
|
INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to detect SSS
|
||||||
|
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
|
||||||
|
q->N_id_1 = 1000;
|
||||||
|
|
||||||
|
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 pos=%d peak=%.2f/%.2f=%.2f threshold=%.2f sf_idx=%d offset=%d\n",
|
INFO("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, peak_pos, peak_unnormalized,energy,q->peak_value, q->threshold, q->sf_idx, find_offset);
|
ret, q->N_id_2, find_offset, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo);
|
||||||
|
|
||||||
} 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,9 +220,7 @@ 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);
|
||||||
|
|
||||||
mean_peak = VEC_CMA(x, mean_peak, frame_cnt);
|
if (peak_value >= threshold) {
|
||||||
|
|
||||||
if (x >= threshold) {
|
|
||||||
nof_det++;
|
nof_det++;
|
||||||
|
|
||||||
if (peak_idx >= fft_size) {
|
if (peak_idx >= fft_size) {
|
||||||
|
|
|
@ -192,12 +192,7 @@ 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_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx);
|
chest_dl_estimate(&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,14 +36,8 @@
|
||||||
#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,
|
||||||
uint32_t cell_id,
|
lte_cell_t cell)
|
||||||
lte_cp_t cp)
|
|
||||||
{
|
{
|
||||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
|
||||||
|
@ -68,17 +62,7 @@ int ue_mib_init(ue_mib_t * q,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) {
|
if (lte_fft_init(&q->fft, cell.cp, cell.nof_prb)) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -130,48 +114,45 @@ 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_ce_slot(&q->chest, q->slot1_symbols, q->ce, 1);
|
ret = chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0);
|
||||||
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->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) ||
|
if (q->frame_cnt > 8) {
|
||||||
q->frame_cnt > 16)
|
INFO("Resetting PBCH decoder after %d frames\n", q->frame_cnt);
|
||||||
{
|
|
||||||
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->slot1_symbols, q->ce, mib);
|
ret = pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)],
|
||||||
|
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\n");
|
fprintf(stderr, "Error decoding PBCH (%d)\n", ret);
|
||||||
} else if (ret == 1) {
|
} else if (ret == 1) {
|
||||||
INFO("MIB decoded: %u\n", q->frame_cnt/2);
|
INFO("MIB decoded: %u\n", q->frame_cnt);
|
||||||
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 / 2);
|
INFO("MIB not decoded: %u\n", q->frame_cnt);
|
||||||
q->last_frame_trial = q->frame_cnt;
|
q->frame_cnt++;
|
||||||
ret = LIBLTE_SUCCESS;
|
ret = MIB_NOTFOUND;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
int counter1=0,counter2=0,counter3=0,counter4=0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,74 +162,73 @@ 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)
|
||||||
{
|
{
|
||||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
lte_cell_t cell;
|
||||||
uint32_t peak_idx=0;
|
cell.nof_ports = MIB_MAX_PORTS;
|
||||||
uint32_t nof_input_frames;
|
cell.id = cell_id;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q != NULL &&
|
void ue_mib_sync_reset(ue_mib_sync_t * q) {
|
||||||
signal != NULL)
|
ue_mib_reset(&q->ue_mib);
|
||||||
{
|
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,
|
||||||
|
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;
|
||||||
|
cf_t *sf_buffer = NULL;
|
||||||
|
uint32_t nof_frames = 0;
|
||||||
|
int mib_ret = MIB_NOTFOUND;
|
||||||
|
|
||||||
|
if (q != NULL)
|
||||||
|
{
|
||||||
ret = LIBLTE_SUCCESS;
|
ret = LIBLTE_SUCCESS;
|
||||||
|
do {
|
||||||
if (nsamples % MIB_FRAME_SIZE) {
|
mib_ret = MIB_NOTFOUND;
|
||||||
printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE);
|
ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
|
||||||
nsamples = (nsamples/MIB_FRAME_SIZE) * MIB_FRAME_SIZE;
|
|
||||||
}
|
|
||||||
nof_input_frames = nsamples/MIB_FRAME_SIZE;
|
|
||||||
|
|
||||||
for (uint32_t nf=0;nf<nof_input_frames;nf++) {
|
|
||||||
|
|
||||||
/* Find peak and cell id */
|
|
||||||
ret = sync_find(&q->sfind, signal, nf*MIB_FRAME_SIZE, &peak_idx);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
fprintf(stderr, "Error calling ue_sync_work()\n");
|
||||||
return -1;
|
break;
|
||||||
}
|
} 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);
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
counter2++;
|
|
||||||
} else if (ret == 1) {
|
|
||||||
counter4++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 {
|
} else {
|
||||||
INFO("SSS not detected\n",0);
|
INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
|
||||||
ret = 0;
|
ue_mib_reset(&q->ue_mib);
|
||||||
}
|
}
|
||||||
|
nof_frames++;
|
||||||
counter1++;
|
}
|
||||||
INFO("Total: %3d - Sync0: %3d - Sync1: %3d - Tried: %3d - Peak: %4d - Ret: %d\n",counter1,counter2,counter4, counter3, peak_idx, ret);
|
} while (mib_ret == MIB_NOTFOUND && ret >= 0 && nof_frames < max_frames_timeout);
|
||||||
|
if (mib_ret < 0) {
|
||||||
q->frame_cnt++;
|
ret = mib_ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mib_ret;
|
return mib_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,17 @@ 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
|
||||||
|
|
||||||
#define FIND_THRESHOLD 1.2
|
int ue_sync_init_file(ue_sync_t *q, uint32_t nof_prb, char *file_name) {
|
||||||
#define TRACK_THRESHOLD 0.2
|
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
|
||||||
|
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);
|
||||||
|
@ -208,7 +217,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 1000*q->mean_time_offset;
|
return 5000*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) {
|
||||||
|
@ -267,11 +276,12 @@ 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->strack.m0, q->strack.m1, q->strack.m0_value, q->strack.m1_value);
|
q->sf_idx, sync_get_sf_idx(&q->strack),
|
||||||
/* FIXME: What should we do in this case? */
|
q->strack.m0, q->strack.m0_value, q->strack.m1, q->strack.m1_value);
|
||||||
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);
|
||||||
|
@ -294,12 +304,7 @@ static int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
|
||||||
q->time_offset = 0;
|
q->time_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compute cumulative moving average CFO */
|
q->peak_idx = q->sf_len/2 + q->time_offset;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -439,16 +444,13 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||||
q->frame_total_cnt++;
|
q->frame_total_cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MEASURE_EXEC_TIME
|
/* Do CFO Correction if not done in track and deliver the frame */
|
||||||
gettimeofday(&t[2], NULL);
|
if (!q->strack.correct_cfo) {
|
||||||
get_time_interval(t);
|
cfo_correct(&q->sfind.cfocorr,
|
||||||
q->mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
|
q->input_buffer,
|
||||||
#endif
|
q->input_buffer,
|
||||||
|
-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,19 +29,22 @@
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
int decode_pbch(void *uhd,
|
#ifndef _LTE_RRC_
|
||||||
ue_celldetect_result_t *found_cell,
|
#define _LTE_RRC_
|
||||||
uint32_t nof_frames_total,
|
|
||||||
pbch_mib_t *mib);
|
|
||||||
|
|
||||||
int find_all_cells(void *uhd,
|
#ifdef __cplusplus
|
||||||
ue_celldetect_result_t found_cell[3]);
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
int find_cell(void *uhd,
|
#include "liblte/config.h"
|
||||||
ue_celldetect_result_t *found_cell,
|
|
||||||
uint32_t N_id_2);
|
|
||||||
|
|
||||||
int cell_search(void *uhd,
|
#include "liblte/rrc/messages/bcch.h"
|
||||||
int force_N_id_2,
|
#include "liblte/rrc/messages/sib1.h"
|
||||||
lte_cell_t *cell,
|
#include "liblte/rrc/messages/sib4.h"
|
||||||
pbch_mib_t *mib);
|
#include "liblte/rrc/common/rrc_common.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -26,16 +26,9 @@
|
||||||
ADD_EXECUTABLE(bcch_bch_test bcch_bch_test.c)
|
ADD_EXECUTABLE(bcch_bch_test bcch_bch_test.c)
|
||||||
TARGET_LINK_LIBRARIES(bcch_bch_test lte_rrc)
|
TARGET_LINK_LIBRARIES(bcch_bch_test lte_rrc)
|
||||||
|
|
||||||
ADD_EXECUTABLE(ue_celldetect_mib_test ue_celldetect_mib_test.c)
|
ADD_TEST(bcch_bch_test_1 bcch_bch_test)
|
||||||
TARGET_LINK_LIBRARIES(ue_celldetect_mib_test lte_phy cuhd)
|
|
||||||
|
|
||||||
IF(${GRAPHICS_FIND} EQUAL -1)
|
|
||||||
SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
|
|
||||||
ELSE(${GRAPHICS_FIND} EQUAL -1)
|
|
||||||
target_link_libraries(ue_sync_usrp graphics)
|
|
||||||
ENDIF(${GRAPHICS_FIND} EQUAL -1)
|
|
||||||
|
|
||||||
ENDIF(${CUHD_FIND} GREATER -1)
|
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(bcch_dlsch_test bcch_dlsch_test.c)
|
||||||
|
TARGET_LINK_LIBRARIES(bcch_dlsch_test lte_rrc lte_phy)
|
||||||
|
|
||||||
ADD_TEST(bcch_dlsch_test_1 bcch_dlsch_test)
|
ADD_TEST(bcch_dlsch_test_1 bcch_dlsch_test)
|
||||||
|
|
Loading…
Reference in New Issue