Improved cell search algorithm. Using narrow correlation for cell acquisition and MIB decoding

master
ismagom 10 years ago
parent 5a032c4316
commit 243f23752d

@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support # These two can be compiled without UHD or graphics support
################################################################# #################################################################
add_executable(pdsch_ue pdsch_ue.c cell_search_utils.c) add_executable(pdsch_ue pdsch_ue.c cuhd_utils.c)
target_link_libraries(pdsch_ue lte_rrc lte_phy) target_link_libraries(pdsch_ue lte_rrc lte_phy)
add_executable(pdsch_enodeb pdsch_enodeb.c) add_executable(pdsch_enodeb pdsch_enodeb.c)
@ -81,10 +81,10 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1) IF(${CUHD_FIND} GREATER -1)
add_executable(cell_search cell_search.c cell_search_utils.c) add_executable(cell_search cell_search.c cuhd_utils.c)
target_link_libraries(cell_search lte_rrc lte_phy cuhd ) target_link_libraries(cell_search lte_rrc lte_phy cuhd )
add_executable(cell_measurement cell_measurement.c cell_search_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)
MESSAGE(STATUS " UHD examples will be installed.") MESSAGE(STATUS " UHD examples will be installed.")

@ -39,16 +39,16 @@
#include "liblte/rrc/rrc.h" #include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h" #include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h" #include "cuhd_utils.h"
#define B210_DEFAULT_GAIN 40.0 #define B210_DEFAULT_GAIN 40.0
#define B210_DEFAULT_GAIN_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40 #define B210_DEFAULT_GAIN_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40
float gain_offset = B210_DEFAULT_GAIN_CORREC; float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_detect_cfg_t cell_detect_config = { cell_search_cfg_t cell_detect_config = {
100, // nof_frames_total 50, // nof_frames_total
6.0 // early-stops cell detection if mean PSR is above this value 9.0 // early-stops cell detection if mean PSR is above this value
}; };
/********************************************************************** /**********************************************************************
@ -170,15 +170,24 @@ int main(int argc, char **argv) {
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000); printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
if (detect_and_decode_cell(&cell_detect_config, uhd, prog_args.force_N_id_2, &cell)) {
fprintf(stderr, "Cell not found\n");
exit(-1); exit(-1);
} else if (ret == 0) {
printf("Cell not found\n");
exit(0);
} }
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
return LIBLTE_ERROR;
}
INFO("Stopping UHD and flushing buffer...\n",0); INFO("Stopping UHD and flushing buffer...\n",0);
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd); cuhd_flush_buffer(uhd);
@ -191,7 +200,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating UE downlink processing module\n"); fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1); exit(-1);
} }
if (ue_mib_init(&ue_mib, cell, false)) { if (ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initaiting UE MIB decoder\n"); fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1); exit(-1);
} }
@ -240,9 +249,7 @@ int main(int argc, char **argv) {
case DECODE_MIB: case DECODE_MIB:
if (ue_sync_get_sfidx(&ue_sync) == 0) { if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch); pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode_aligned_frame(&ue_mib, n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
sf_buffer, bch_payload_unpacked,
NULL, &sfn_offset);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n"); fprintf(stderr, "Error decoding UE MIB\n");
exit(-1); exit(-1);

@ -37,7 +37,7 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
#include "cell_search_utils.h" #include "cuhd_utils.h"
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
@ -55,7 +55,7 @@
int band = -1; int band = -1;
int earfcn_start=-1, earfcn_end = -1; int earfcn_start=-1, earfcn_end = -1;
cell_detect_cfg_t config = {50, 1.1}; cell_search_cfg_t config = {50, 1.1};
float uhd_gain = 60.0; float uhd_gain = 60.0;
@ -111,15 +111,19 @@ void parse_args(int argc, char **argv) {
} }
} }
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 main(int argc, char **argv) {
int n; int n;
void *uhd; void *uhd;
ue_celldetect_result_t found_cells[3]; ue_cell_search_t cs;
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;
uint8_t bch_payload[BCH_PAYLOAD_LEN];
uint32_t nof_tx_ports;
parse_args(argc, argv); parse_args(argc, argv);
@ -150,21 +154,44 @@ int main(int argc, char **argv) {
if (VERBOSE_ISINFO()) { if (VERBOSE_ISINFO()) {
printf("\n"); printf("\n");
} }
bzero(found_cells, 3*sizeof(ue_cell_search_result_t));
if (ue_cell_search_init(&cs, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1);
}
if (config.nof_frames_total) {
ue_cell_search_set_nof_frames_to_scan(&cs, config.nof_frames_total);
}
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 = detect_all_cells(&config, uhd, found_cells); 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) {
if (n == CS_CELL_DETECTED) {
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 > config.threshold/2) {
if (decode_pbch(uhd, &found_cells[i], config.nof_frames_total, bch_payload, &nof_tx_ports, NULL)) { 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);
} else { }
printf("Cell found with %d ports. Decoded MIB: \n", nof_tx_ports); if (ret == MIB_FOUND) {
vec_fprint_hex(stdout, bch_payload, BCH_PAYLOAD_LEN); printf("Found CELL ID %d. %d PRB, %d ports\n",
cell.id, cell.nof_prb, cell.nof_ports);
} }
} }
} }

@ -1,284 +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 "liblte/phy/phy.h"
#include "liblte/rrc/rrc.h"
#include "cell_search_utils.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int decode_pbch(void *uhd, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total,
uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset)
{
ue_mib_t uemib;
int n;
int ret = LIBLTE_ERROR;
uint32_t nof_frames = 0;
uint32_t flen = MIB_FRAME_SIZE_SEARCH;
cf_t *buffer = vec_malloc(sizeof(cf_t) * flen);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
if (ue_mib_init_1_92(&uemib, found_cell->cell_id, found_cell->cp)) {
fprintf(stderr, "Error initiating PBCH decoder\n");
goto free_and_exit;
}
INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0);
cuhd_set_rx_srate(uhd, 1920000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
DEBUG("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
n = ue_mib_sync_and_decode_1_92(&uemib, buffer, flen);
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling ue_mib_decode()\n");
goto free_and_exit;
}
if (n == MIB_FRAME_UNALIGNED) {
INFO("Realigning frame\n",0);
// Receive some randon number of samples to try to resynchronise the frame.
if (cuhd_recv(uhd, buffer, 1500, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
bzero(buffer, flen * sizeof(cf_t));
}
nof_frames++;
} while (n != MIB_FOUND && nof_frames < 2*nof_frames_total);
if (n == MIB_FOUND) {
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
ue_mib_get_payload(&uemib, bch_payload, nof_tx_ports, sfn_offset);
ret = LIBLTE_SUCCESS;
} else {
ret = LIBLTE_ERROR;
}
free_and_exit:
free(buffer);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
ue_mib_free(&uemib);
return ret;
}
int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *found_cell, uint32_t N_id_2)
{
int ret = LIBLTE_ERROR;
ue_celldetect_t cd;
cf_t *buffer = vec_malloc(sizeof(cf_t) * CS_FLEN);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
if (ue_celldetect_init(&cd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
goto free_and_exit;
}
if (config->nof_frames_total) {
ue_celldetect_set_nof_frames_total(&cd, config->nof_frames_total);
}
if (config->threshold) {
ue_celldetect_set_threshold(&cd, 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);
uint32_t flen = CS_FLEN;
int n;
bzero(found_cell, sizeof(ue_celldetect_result_t));
ue_celldetect_set_N_id_2(&cd, N_id_2);
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
DEBUG("Scanning cell at N_id_2=%d\n",N_id_2);
n = ue_celldetect_scan(&cd, buffer, flen);
switch(n) {
case CS_FRAME_UNALIGNED:
INFO("Realigning frame\n",0);
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
break;
case CS_CELL_DETECTED:
ue_celldetect_get_cell(&cd, found_cell);
if (found_cell->peak > 0) {
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %.0f%%\n",
found_cell->cell_id,
lte_cp_string(found_cell->cp),
found_cell->peak, found_cell->mode*100);
}
ret = 1;
INFO("Cell found at N_id_2=%d\n",N_id_2);
break;
case CS_CELL_NOT_DETECTED:
ret = 0;
printf("No cell found at N_id_2=%d. Mean PSR: %.2f\n",N_id_2, sync_get_peak_value(&cd.sfind));
break;
case LIBLTE_ERROR:
case LIBLTE_ERROR_INVALID_INPUTS:
ret = LIBLTE_ERROR;
fprintf(stderr, "Error calling cellsearch_scan()\n");
goto free_and_exit;
}
} while(n == 0 || n == CS_FRAME_UNALIGNED);
free_and_exit:
free(buffer);
ue_celldetect_free(&cd);
INFO("Stopping receiver...\n", 0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
return ret;
}
int detect_all_cells(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t found_cell[3])
{
uint32_t N_id_2;
int ret;
int nof_detected_cells = 0;
for (N_id_2=0;N_id_2<3;N_id_2++) {
ret = detect_cell(config, uhd, &found_cell[N_id_2], N_id_2);
if (ret == 1) {
nof_detected_cells++;
} else if (ret == LIBLTE_ERROR) {
return LIBLTE_ERROR;
}
}
return nof_detected_cells;
}
int detect_and_decode_cell(cell_detect_cfg_t *config, void *uhd, int force_N_id_2, lte_cell_t *cell)
{
int ret;
uint32_t nof_tx_ports;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
ue_celldetect_result_t found_cells[3];
bzero(found_cells, 3*sizeof(ue_celldetect_result_t));
if (force_N_id_2 >= 0) {
ret = detect_cell(config, uhd, &found_cells[force_N_id_2], force_N_id_2);
} else {
ret = detect_all_cells(config, uhd, found_cells);
}
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
int max_peak_cell = 0;
float max_peak_value = -1.0;
if (ret > 0) {
if (force_N_id_2 >= 0) {
max_peak_cell = force_N_id_2;
} else {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > max_peak_value) {
max_peak_value = found_cells[i].peak;
max_peak_cell = i;
}
}
}
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", found_cells[max_peak_cell].cell_id, max_peak_cell);
if (decode_pbch(uhd, &found_cells[max_peak_cell], 400, bch_payload, &nof_tx_ports, NULL)) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id);
return LIBLTE_ERROR;
}
} else {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_ERROR;
}
cell->cp = found_cells[max_peak_cell].cp;
cell->id = found_cells[max_peak_cell].cell_id;
cell->nof_ports = nof_tx_ports;
bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL);
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell->nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
return LIBLTE_SUCCESS;
}
#endif

@ -0,0 +1,171 @@
/**
*
* \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 "liblte/phy/phy.h"
#include "liblte/rrc/rrc.h"
#include "cuhd_utils.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int cuhd_recv_wrapper_cs(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
/** This function is simply a wrapper to the ue_cell_search module for cuhd devices
* Return 1 if the MIB is decoded, 0 if not or -1 on error.
*/
int cuhd_mib_decoder(void *uhd, uint32_t max_nof_frames, lte_cell_t *cell) {
int ret = LIBLTE_ERROR;
ue_mib_sync_t ue_mib;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
if (ue_mib_sync_init(&ue_mib, cell->id, cell->cp, cuhd_recv_wrapper_cs, uhd)) {
fprintf(stderr, "Error initiating ue_mib_sync\n");
goto clean_exit;
}
int srate = lte_sampling_freq_hz(MIB_NOF_PRB);
INFO("Setting sampling frequency %.2f MHz for PSS search\n", (float) srate/1000000);
cuhd_set_rx_srate(uhd, (float) srate);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
/* Find and decody MIB */
ret = ue_mib_sync_decode(&ue_mib, max_nof_frames, bch_payload, &cell->nof_ports, NULL);
if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n");
goto clean_exit;
}
if (ret == 1) {
bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL);
}
clean_exit:
cuhd_stop_rx_stream(uhd);
ue_mib_sync_free(&ue_mib);
return ret;
}
/** This function is simply a wrapper to the ue_cell_search module for cuhd devices
*/
int cuhd_cell_search(void *uhd, cell_search_cfg_t *config,
int force_N_id_2, lte_cell_t *cell)
{
int ret = LIBLTE_ERROR;
ue_cell_search_t cs;
ue_cell_search_result_t found_cells[3];
bzero(found_cells, 3*sizeof(ue_cell_search_result_t));
if (ue_cell_search_init(&cs, cuhd_recv_wrapper_cs, uhd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
return LIBLTE_ERROR;
}
if (config->nof_frames_total) {
ue_cell_search_set_nof_frames_to_scan(&cs, config->nof_frames_total);
}
if (config->threshold) {
ue_cell_search_set_threshold(&cs, config->threshold);
}
INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000000);
cuhd_set_rx_srate(uhd, CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
if (force_N_id_2 >= 0) {
ret = ue_cell_search_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = ue_cell_search_scan(&cs, found_cells, &max_peak_cell);
}
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
return LIBLTE_ERROR;
} else if (ret == 0) {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_SUCCESS;
}
// Save result
if (cell) {
cell->id = found_cells[max_peak_cell].cell_id;
cell->cp = found_cells[max_peak_cell].cp;
}
cuhd_stop_rx_stream(uhd);
ue_cell_search_free(&cs);
return ret;
}
/* Finds a cell and decodes MIB from the PBCH.
* Returns 1 if the cell is found and MIB is decoded successfully.
* 0 if no cell was found or MIB could not be decoded,
* -1 on error
*/
int cuhd_search_and_decode_mib(void *uhd, cell_search_cfg_t *config, int force_N_id_2, lte_cell_t *cell)
{
int ret = LIBLTE_ERROR;
printf("Searching for cell...\n");
ret = cuhd_cell_search(uhd, config, force_N_id_2, cell);
if (ret > 0) {
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3);
ret = cuhd_mib_decoder(uhd, 50, cell);
if (ret < 0) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id);
return LIBLTE_ERROR;
}
}
return ret;
}
#endif

@ -31,25 +31,20 @@
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
uint32_t nof_frames_total; // maximum number of 5ms frames to capture uint32_t nof_frames_total; // maximum number of 5ms frames to capture
float threshold; // early-stops cell detection if mean PSR is above this value float threshold; // early-stops cell detection if mean PSR is above this value
}cell_detect_cfg_t; }cell_search_cfg_t;
int decode_pbch(void *uhd, int cuhd_mib_decoder(void *uhd,
ue_celldetect_result_t *found_cell, uint32_t max_nof_frames,
uint32_t nof_frames_total, lte_cell_t *cell);
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports, int cuhd_cell_search(void *uhd,
uint32_t *sfn_offset); cell_search_cfg_t *config,
int force_N_id_2,
int detect_all_cells(cell_detect_cfg_t *config, lte_cell_t *cell);
void *uhd,
ue_celldetect_result_t found_cell[3]); int cuhd_search_and_decode_mib(void *uhd,
cell_search_cfg_t *config,
int detect_cell(cell_detect_cfg_t *config, int force_N_id_2,
void *uhd, lte_cell_t *cell);
ue_celldetect_result_t *found_cell,
uint32_t N_id_2);
int detect_and_decode_cell(cell_detect_cfg_t *config,
void *uhd,
int force_N_id_2,
lte_cell_t *cell);

@ -39,7 +39,7 @@
#include "liblte/rrc/rrc.h" #include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h" #include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h" #include "cuhd_utils.h"
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
void init_plots(); void init_plots();
@ -53,7 +53,7 @@ void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs);
float gain_offset = B210_DEFAULT_GAIN_CORREC; float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_detect_cfg_t cell_detect_config = { cell_search_cfg_t cell_detect_config = {
100, // nof_frames_total 100, // nof_frames_total
4.0 // threshold 4.0 // threshold
}; };
@ -188,10 +188,24 @@ int main(int argc, char **argv) {
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000); printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
if (detect_and_decode_cell(&cell_detect_config, uhd, prog_args.force_N_id_2, &cell)) { ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
fprintf(stderr, "Cell not found\n"); if (ret < 0) {
fprintf(stderr, "Error searching for cell\n");
exit(-1); exit(-1);
} else if (ret == 0) {
printf("Cell not found\n");
exit(0);
} }
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
return LIBLTE_ERROR;
}
INFO("Stopping UHD and flushing buffer...\r",0); INFO("Stopping UHD and flushing buffer...\r",0);
cuhd_stop_rx_stream(uhd); cuhd_stop_rx_stream(uhd);
@ -205,7 +219,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating UE downlink processing module\n"); fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1); exit(-1);
} }
if (ue_mib_init(&ue_mib, cell, false)) { if (ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initaiting UE MIB decoder\n"); fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1); exit(-1);
} }
@ -247,9 +261,7 @@ int main(int argc, char **argv) {
case DECODE_MIB: case DECODE_MIB:
if (ue_sync_get_sfidx(&ue_sync) == 0) { if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch); pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode_aligned_frame(&ue_mib, n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
sf_buffer, bch_payload_unpacked,
NULL, &sfn_offset);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n"); fprintf(stderr, "Error decoding UE MIB\n");
exit(-1); exit(-1);
@ -393,7 +405,10 @@ void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs) {
plot_real_setNewData(&poutfft, tmp_plot, nof_re); plot_real_setNewData(&poutfft, tmp_plot, nof_re);
plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(q->cell.nof_prb,0)); plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(q->cell.nof_prb,0));
int max = vec_max_fi(qs->strack.pss.conv_output_avg, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1); int max = vec_max_fi(qs->strack.pss.conv_output_avg, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1);
vec_sc_prod_fff(qs->strack.pss.conv_output_avg, 1/qs->strack.pss.conv_output_avg[max], tmp_plot2, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1); vec_sc_prod_fff(qs->strack.pss.conv_output_avg,
1/qs->strack.pss.conv_output_avg[max],
tmp_plot2,
qs->strack.pss.frame_size+qs->strack.pss.fft_size-1);
plot_real_setNewData(&p_sync, tmp_plot2, qs->strack.pss.frame_size); plot_real_setNewData(&p_sync, tmp_plot2, qs->strack.pss.frame_size);
plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols); plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);

@ -60,6 +60,8 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define PRNTI 0xFFFE #define PRNTI 0xFFFE
#define MRNTI 0xFFFD #define MRNTI 0xFFFD
#define CELL_ID_UNKNOWN 1000
#define MAX_NSYMB 7 #define MAX_NSYMB 7
#define MAX_PRB 110 #define MAX_PRB 110

@ -95,7 +95,7 @@
#include "liblte/phy/ue/ue_sync.h" #include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h" #include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/ue/ue_celldetect.h" #include "liblte/phy/ue/ue_cell_search.h"
#include "liblte/phy/ue/ue_dl.h" #include "liblte/phy/ue/ue_dl.h"
#include "liblte/phy/scrambling/scrambling.h" #include "liblte/phy/scrambling/scrambling.h"

@ -0,0 +1,118 @@
/**
*
* \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/.
*
*/
#ifndef UE_CELLSEARCH_
#define UE_CELLSEARCH_
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
/************************************************************
*
* This object is a wrapper to the ue_sync object. It receives
* several synchronized frames and obtains the most common cell_id
* and cp length.
*
* The I/O stream device sampling frequency must be set to 1.92 MHz (CS_SAMP_FREQ constant)
* before calling to ue_cell_search_scan() functions.
*
************************************************************/
/**
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 500
#define CS_DEFAULT_MAXFRAMES_DETECTED 50
#define CS_DEFAULT_NOFFRAMES_TOTAL 50
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
#define CS_NOF_PRB 6
#define CS_SAMP_FREQ 1920000.0
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
float mode;
} ue_cell_search_result_t;
typedef struct LIBLTE_API {
ue_sync_t ue_sync;
uint32_t max_frames;
uint32_t nof_frames_to_scan; // number of 5 ms frames to scan
float detect_threshold; // early-stops scan if mean PSR above this threshold
uint32_t *mode_ntimes;
uint8_t *mode_counted;
ue_cell_search_result_t *candidates;
} ue_cell_search_t;
LIBLTE_API int ue_cell_search_init(ue_cell_search_t *q,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API int ue_cell_search_init_max(ue_cell_search_t *q,
uint32_t max_frames_total,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API void ue_cell_search_free(ue_cell_search_t *q);
LIBLTE_API int ue_cell_search_scan_N_id_2(ue_cell_search_t *q,
uint32_t N_id_2,
ue_cell_search_result_t *found_cell);
LIBLTE_API int ue_cell_search_scan(ue_cell_search_t * q,
ue_cell_search_result_t found_cells[3],
uint32_t *max_N_id_2);
LIBLTE_API int ue_cell_search_set_nof_frames_to_scan(ue_cell_search_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_cell_search_set_threshold(ue_cell_search_t *q,
float threshold);
#endif // SYNC_FRAME_

@ -1,132 +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/.
*
*/
#ifndef UE_CELLSEARCH_
#define UE_CELLSEARCH_
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
/************************************************************
*
* This object scans a signal for LTE cells using the known PSS
* and SSS sequences.
*
* The function ue_celldetect_scan() shall be called multiple times,
* each passing a number of samples multiple of 4800, sampled at 960 KHz
* (that is, 5 ms of samples).
*
* The function returns 0 until a signal is found nof_frames_detected times or
* after nof_frames_total with no signal detected.
*
* See ue_cell_detect.c for an example.
*
************************************************************/
/**
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 500
#define CS_DEFAULT_MAXFRAMES_DETECTED 50
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
#define CS_FRAME_UNALIGNED -3
#define CS_CELL_DETECTED 2
#define CS_CELL_NOT_DETECTED 3
#define CS_FFTSIZE 128
#define CS_SAMP_FREQ (960000*(CS_FFTSIZE/64))
#define CS_FLEN (4800*(CS_FFTSIZE/64))
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
float mode;
} ue_celldetect_result_t;
typedef struct LIBLTE_API {
sync_t sfind;
uint32_t max_frames_total;
uint32_t nof_frames_total; // number of 5 ms frames to scan
float detect_threshold; // early-stops scan if mean PSR above this threshold
uint32_t current_nof_detected;
uint32_t current_nof_total;
uint32_t *mode_ntimes;
uint8_t *mode_counted;
ue_celldetect_result_t *candidates;
} ue_celldetect_t;
LIBLTE_API int ue_celldetect_init(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_init_max(ue_celldetect_t *q,
uint32_t max_frames_total);
LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q,
cf_t *signal,
uint32_t nsamples);
LIBLTE_API int ue_celldetect_set_N_id_2(ue_celldetect_t *q,
uint32_t N_id_2);
LIBLTE_API void ue_celldetect_get_cell(ue_celldetect_t * q,
ue_celldetect_result_t *found_cell);
LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_celldetect_set_threshold(ue_celldetect_t *q,
float threshold);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
#endif // SYNC_FRAME_

@ -49,7 +49,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "liblte/config.h" #include "liblte/config.h"
#include "liblte/phy/sync/sync.h" #include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/sync/cfo.h" #include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest_dl.h" #include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pbch.h"
@ -57,10 +57,8 @@
#define MIB_MAX_PORTS 4 #define MIB_MAX_PORTS 4
#define MIB_FRAME_SIZE_SEARCH 9600 #define MIB_NOF_PRB 6
#define MIB_FFT_SIZE 128
#define MIB_FRAME_UNALIGNED -3
#define MIB_FOUND 1 #define MIB_FOUND 1
#define MIB_NOTFOUND 0 #define MIB_NOTFOUND 0
@ -70,7 +68,6 @@ typedef struct LIBLTE_API {
cf_t *sf_symbols; cf_t *sf_symbols;
cf_t *ce[MIB_MAX_PORTS]; cf_t *ce[MIB_MAX_PORTS];
cfo_t cfocorr;
lte_fft_t fft; lte_fft_t fft;
chest_dl_t chest; chest_dl_t chest;
pbch_t pbch; pbch_t pbch;
@ -80,43 +77,45 @@ typedef struct LIBLTE_API {
uint32_t sfn_offset; uint32_t sfn_offset;
uint32_t frame_cnt; uint32_t frame_cnt;
uint32_t last_frame_trial;
} ue_mib_t; } ue_mib_t;
LIBLTE_API int ue_mib_init_1_92(ue_mib_t *q,
uint32_t cell_id,
lte_cp_t cp);
LIBLTE_API int ue_mib_init(ue_mib_t *q, LIBLTE_API int ue_mib_init(ue_mib_t *q,
lte_cell_t cell, lte_cell_t cell);
bool do_sync);
LIBLTE_API void ue_mib_free(ue_mib_t *q); LIBLTE_API void ue_mib_free(ue_mib_t *q);
LIBLTE_API void ue_mib_reset(ue_mib_t *q); LIBLTE_API void ue_mib_reset(ue_mib_t * q);
LIBLTE_API int ue_mib_sync_and_decode_1_92(ue_mib_t *q, LIBLTE_API int ue_mib_decode(ue_mib_t * q,
cf_t *signal, cf_t *input,
uint32_t nsamples); uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset);
LIBLTE_API int ue_mib_decode_aligned_frame(ue_mib_t * q,
cf_t *input,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset);
LIBLTE_API void ue_mib_get_payload(ue_mib_t *q, /* This interface uses ue_mib and ue_sync to first get synchronized subframes
uint8_t bch_payload[BCH_PAYLOAD_LEN], * and then decode MIB
uint32_t *nof_tx_ports, */
uint32_t *sfn_offset); typedef struct {
ue_mib_t ue_mib;
ue_sync_t ue_sync;
} ue_mib_sync_t;
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q, LIBLTE_API int ue_mib_sync_init(ue_mib_sync_t *q,
float threshold); uint32_t cell_id,
lte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API void ue_mib_reset(ue_mib_t *q); LIBLTE_API void ue_mib_sync_free(ue_mib_sync_t *q);
LIBLTE_API void ue_mib_sync_reset(ue_mib_sync_t * q);
LIBLTE_API 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);

@ -66,6 +66,13 @@ typedef struct LIBLTE_API {
cf_t *input_buffer; cf_t *input_buffer;
uint32_t frame_len;
uint32_t fft_size;
uint32_t nof_recv_sf; // Number of subframes received each call to ue_sync_get_buffer
uint32_t nof_avg_find_frames;
uint32_t frame_find_cnt;
uint32_t sf_len;
/* These count half frames (5ms) */ /* These count half frames (5ms) */
uint64_t frame_ok_cnt; uint64_t frame_ok_cnt;
uint32_t frame_no_cnt; uint32_t frame_no_cnt;
@ -82,6 +89,7 @@ typedef struct LIBLTE_API {
uint32_t peak_idx; uint32_t peak_idx;
int time_offset; int time_offset;
float mean_time_offset; float mean_time_offset;
#ifdef MEASURE_EXEC_TIME #ifdef MEASURE_EXEC_TIME
float mean_exec_time; float mean_exec_time;
#endif #endif
@ -89,9 +97,9 @@ typedef struct LIBLTE_API {
LIBLTE_API int ue_sync_init(ue_sync_t *q, LIBLTE_API int ue_sync_init(ue_sync_t *q,
lte_cell_t cell, lte_cell_t cell,
int (recv_callback)(void*, void*, uint32_t), int (recv_callback)(void*, void*, uint32_t),
void *stream_handler); void *stream_handler);
LIBLTE_API void ue_sync_free(ue_sync_t *q); LIBLTE_API void ue_sync_free(ue_sync_t *q);
@ -102,6 +110,9 @@ LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q,
LIBLTE_API void ue_sync_reset(ue_sync_t *q); LIBLTE_API void ue_sync_reset(ue_sync_t *q);
LIBLTE_API void ue_sync_set_N_id_2(ue_sync_t *q,
uint32_t N_id_2);
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q,
bool enabled); bool enabled);

@ -138,7 +138,9 @@ int predecoding_single(precoding_t *q, cf_t *y, cf_t *h, cf_t *x, int nof_symbol
/* ZF/MMSE STBC equalizer x=y(H'H+n0·I)^(-1)H' (ZF is n0=0.0) /* ZF/MMSE STBC equalizer x=y(H'H+n0·I)^(-1)H' (ZF is n0=0.0)
*/ */
int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols, float noise_estimate) { int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS],
int nof_ports, int nof_symbols, float noise_estimate)
{
int i; int i;
if (nof_ports == 2) { if (nof_ports == 2) {
@ -171,8 +173,7 @@ int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[M
// (H'H + n0) // (H'H + n0)
vec_sc_add_fff(modhh, noise_estimate, modhh, nof_symbols/2); vec_sc_add_fff(modhh, noise_estimate, modhh, nof_symbols/2);
} }
//vec_sc_prod_fff(modhh, 1.0/sqrt(2), modhh, nof_symbols/2);
// x[0] = r0·h0*/(|h0|+|h1|)+r1*·h1/(|h0|+|h1|) // x[0] = r0·h0*/(|h0|+|h1|)+r1*·h1/(|h0|+|h1|)
vec_prod_conj_ccc(r0,h0,q->tmp1, nof_symbols/2); vec_prod_conj_ccc(r0,h0,q->tmp1, nof_symbols/2);
vec_prod_conj_ccc(h1,r1,q->tmp2, nof_symbols/2); vec_prod_conj_ccc(h1,r1,q->tmp2, nof_symbols/2);

@ -382,10 +382,6 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], float
demod_soft_demodulate(&q->demod, q->pbch_d, demod_soft_demodulate(&q->demod, q->pbch_d,
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
if (nant == 2) {
vec_save_file("d",q->pbch_d, q->nof_symbols*sizeof(cf_t));
}
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered. * We know they are ordered.

@ -46,9 +46,6 @@
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9) #define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72) #define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
#define MIN(a,b) ((a>b)?b:a)
static void set_cfi(pdcch_t *q, uint32_t cfi) { static void set_cfi(pdcch_t *q, uint32_t cfi) {
if (cfi > 0 && cfi < 4) { if (cfi > 0 && cfi < 4) {
q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9;
@ -420,7 +417,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float n
} }
/* demodulate symbols */ /* demodulate symbols */
demod_soft_sigma_set(&q->demod, sqrtf(2/q->cell.nof_ports)); demod_soft_sigma_set(&q->demod, 1.0);
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols); demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols);
/* descramble */ /* descramble */

@ -702,12 +702,12 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_
layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports, layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports,
nof_symbols / q->cell.nof_ports); nof_symbols / q->cell.nof_ports);
} }
/* demodulate symbols /* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization * thus we don't need tot set it in the LLRs normalization
*/ */
demod_soft_sigma_set(&q->demod, 1);//q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); demod_soft_sigma_set(&q->demod, sqrt(q->mod[harq_process->mcs.mod - 1].nbits_x_symbol/2));
demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]);
demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols);

@ -121,18 +121,22 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) {
fprintf(stderr, "Error allocating memory\n"); fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit; goto clean_and_exit;
} }
bzero(q->conv_output, sizeof(cf_t) * buffer_size);
q->conv_output_avg = vec_malloc(buffer_size * sizeof(float)); q->conv_output_avg = vec_malloc(buffer_size * sizeof(float));
if (!q->conv_output_avg) { if (!q->conv_output_avg) {
fprintf(stderr, "Error allocating memory\n"); fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit; goto clean_and_exit;
} }
bzero(q->conv_output_avg, sizeof(float) * buffer_size);
#ifdef PSS_ACCUMULATE_ABS #ifdef PSS_ACCUMULATE_ABS
q->conv_output_abs = vec_malloc(buffer_size * sizeof(float)); q->conv_output_abs = vec_malloc(buffer_size * sizeof(float));
if (!q->conv_output_abs) { if (!q->conv_output_abs) {
fprintf(stderr, "Error allocating memory\n"); fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit; goto clean_and_exit;
} }
bzero(q->conv_output_abs, sizeof(float) * buffer_size);
#endif #endif
for (N_id_2=0;N_id_2<3;N_id_2++) { for (N_id_2=0;N_id_2<3;N_id_2++) {
q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t)); q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->pss_signal_freq[N_id_2]) { if (!q->pss_signal_freq[N_id_2]) {
@ -286,22 +290,22 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
/* Correlate input with PSS sequence */ /* Correlate input with PSS sequence */
if (q->frame_size >= q->fft_size) { if (q->frame_size >= q->fft_size) {
#ifdef CONVOLUTION_FFT #ifdef CONVOLUTION_FFT
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input,
q->pss_signal_freq[q->N_id_2], q->conv_output); q->pss_signal_freq[q->N_id_2], q->conv_output);
#else #else
conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size);
#endif #endif
} else { } else {
for (int i=0;i<q->frame_size;i++) { for (int i=q->fft_size;i<q->fft_size+q->frame_size-1;i++) {
q->conv_output[i] = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], &input[i], q->fft_size); q->conv_output[i] = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], &input[i-q->fft_size], q->fft_size);
} }
conv_output_len = q->frame_size; conv_output_len = q->fft_size+q->frame_size-1;
} }
@ -351,7 +355,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
*corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value;
if (*corr_peak_value < 2.0) { if (*corr_peak_value < 2.0) {
INFO("pl_ub=%d, pl_lb=%d, sl_right: %d (%.2f), sl_left: %d (%.2f), PSR: %.2f/%.2f=%.2f\n", pl_ub, pl_lb, 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_right, 1000000*q->conv_output_avg[sl_right],
sl_left, 1000000*q->conv_output_avg[sl_left], sl_left, 1000000*q->conv_output_avg[sl_left],
1000000*q->conv_output_avg[corr_peak_pos], 1000000*side_lobe_value,*corr_peak_value 1000000*q->conv_output_avg[corr_peak_pos], 1000000*side_lobe_value,*corr_peak_value

@ -143,11 +143,21 @@ int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) {
if (m0==m1 || m0 > 29 || m1 > 29) { if (m0==m1 || m0 > 29 || m1 > 29) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
int N_id_1;
if (m1 > m0) { if (m1 > m0) {
return q->N_id_1_table[m0][m1 - 1]; N_id_1 = q->N_id_1_table[m0][m1 - 1];
} else { } else {
return q->N_id_1_table[m1][m0 - 1]; N_id_1 = q->N_id_1_table[m1][m0 - 1];
} }
if (N_id_1 == 0) {
if (m0 == 0 && m1 == 1) {
return N_id_1;
} else {
return LIBLTE_ERROR;
}
} else {
return N_id_1;
}
} }
/** High-level API */ /** High-level API */

@ -59,9 +59,11 @@ 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->mean_peak_value = 0.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->N_id_2 = 1000; q->N_id_2 = 1000;
q->N_id_1 = 1000; q->N_id_1 = 1000;
q->fft_size = fft_size; q->fft_size = fft_size;
@ -120,8 +122,7 @@ int sync_get_cell_id(sync_t *q) {
if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) {
return q->N_id_1*3 + q->N_id_2; return q->N_id_1*3 + q->N_id_2;
} else { } else {
fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); return -1;
return LIBLTE_ERROR;
} }
} }
@ -200,16 +201,18 @@ lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
M_norm += R_norm/C_norm; M_norm += R_norm/C_norm;
} }
q->M_norm_avg = VEC_EMA(M_norm, q->M_norm_avg, CP_EMA_ALPHA); q->M_norm_avg = VEC_EMA(M_norm/2, q->M_norm_avg, CP_EMA_ALPHA);
for (int i=0;i<2;i++) { for (int i=0;i<2;i++) {
R_ext = crealf(vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len)); R_ext = crealf(vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len));
C_ext = cp_ext_len * vec_avg_power_cf(input_cp_ext, cp_ext_len); C_ext = cp_ext_len * vec_avg_power_cf(input_cp_ext, cp_ext_len);
input_cp_ext += q->fft_size+cp_ext_len; input_cp_ext += q->fft_size+cp_ext_len;
M_ext += R_ext/C_ext; if (C_ext > 0) {
M_ext += R_ext/C_ext;
}
} }
q->M_ext_avg = VEC_EMA(M_ext, q->M_ext_avg, CP_EMA_ALPHA); q->M_ext_avg = VEC_EMA(M_ext/2, q->M_ext_avg, CP_EMA_ALPHA);
if (q->M_norm_avg > q->M_ext_avg) { if (q->M_norm_avg > q->M_ext_avg) {
return CPNORM; return CPNORM;
@ -227,26 +230,18 @@ 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 /* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space
* to correlate * to correlate
*/ */
int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { 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);
if (q->detect_cp) {
if (peak_pos >= 2*(q->fft_size + CP_EXT(q->fft_size))) {
q->cp = sync_detect_cp(q, input, peak_pos);
} else {
INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos);
return LIBLTE_ERROR;
}
}
/* 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, (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);
switch(q->sss_alg) { switch(q->sss_alg) {
case SSS_DIFF: case SSS_DIFF:
@ -325,7 +320,15 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
} else { } else {
INFO("No space for CFO computation. Frame starts at \n",peak_pos); 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 // Try to detect SSS
if (q->sss_en) { if (q->sss_en) {
/* Correct CFO with the averaged CFO estimation */ /* Correct CFO with the averaged CFO estimation */
@ -336,7 +339,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
// Set an invalid N_id_1 indicating SSS is yet to be detected // Set an invalid N_id_1 indicating SSS is yet to be detected
q->N_id_1 = 1000; q->N_id_1 = 1000;
if (sync_sss(q, input, find_offset + peak_pos) < 0) { 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); INFO("No space for SSS processing. Frame starts at %d\n", peak_pos);
} }
} }
@ -346,8 +349,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
ret = 0; ret = 0;
} }
INFO("SYNC ret=%d N_id_2=%d frame_size=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\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, q->frame_size, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo); ret, q->N_id_2, find_offset, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*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");

@ -245,14 +245,17 @@ int main(int argc, char **argv) {
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error2++; sss_error2++;
} }
INFO("Partial N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1));
sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++; sss_error3++;
} }
INFO("Diff N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1));
sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error1++; sss_error1++;
} }
INFO("Full N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1));
} }
// Estimate CP // Estimate CP

@ -121,7 +121,8 @@ int main(int argc, char **argv) {
} }
/* Set a very high threshold to make sure the correlation is ok */ /* Set a very high threshold to make sure the correlation is ok */
sync_set_threshold(&sync, 1.4); sync_set_threshold(&sync, 5.0);
sync_set_sss_algorithm(&sync, SSS_PARTIAL_3);
if (cell_id == -1) { if (cell_id == -1) {
cid = 0; cid = 0;

@ -0,0 +1,275 @@
/**
*
* \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 <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <unistd.h>
#include "liblte/phy/ue/ue_cell_search.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
float tmp_pss_corr[32*10000];
float tmp_sss_corr[31*10000];
int ue_cell_search_init(ue_cell_search_t * q, int (recv_callback)(void*, void*, uint32_t), void *stream_handler)
{
return ue_cell_search_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, recv_callback, stream_handler);
}
int ue_cell_search_init_max(ue_cell_search_t * q, uint32_t max_frames,
int (recv_callback)(void*, void*, uint32_t), void *stream_handler)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = LIBLTE_ERROR;
lte_cell_t cell;
bzero(q, sizeof(ue_cell_search_t));
bzero(&cell, sizeof(lte_cell_t));
cell.id = CELL_ID_UNKNOWN;
cell.nof_prb = CS_NOF_PRB;
if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) {
fprintf(stderr, "Error initiating ue_sync\n");
goto clean_exit;
}
q->candidates = calloc(sizeof(ue_cell_search_result_t), max_frames);
if (!q->candidates) {
perror("malloc");
goto clean_exit;
}
q->mode_ntimes = calloc(sizeof(uint32_t), max_frames);
if (!q->mode_ntimes) {
perror("malloc");
goto clean_exit;
}
q->mode_counted = calloc(sizeof(uint8_t), max_frames);
if (!q->mode_counted) {
perror("malloc");
goto clean_exit;
}
q->max_frames = max_frames;
q->nof_frames_to_scan = CS_DEFAULT_NOFFRAMES_TOTAL;
ret = LIBLTE_SUCCESS;
}
clean_exit:
if (ret == LIBLTE_ERROR) {
ue_cell_search_free(q);
}
return ret;
}
void ue_cell_search_free(ue_cell_search_t * q)
{
if (q->candidates) {
free(q->candidates);
}
if (q->mode_counted) {
free(q->mode_counted);
}
if (q->mode_ntimes) {
free(q->mode_ntimes);
}
ue_sync_free(&q->ue_sync);
bzero(q, sizeof(ue_cell_search_t));
}
void ue_cell_search_set_threshold(ue_cell_search_t * q, float threshold)
{
q->detect_threshold = threshold;
}
int ue_cell_search_set_nof_frames_to_scan(ue_cell_search_t * q, uint32_t nof_frames)
{
if (nof_frames <= q->max_frames) {
q->nof_frames_to_scan = nof_frames;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR;
}
}
/* Decide the most likely cell based on the mode */
static void get_cell(ue_cell_search_t * q, uint32_t nof_detected_frames, ue_cell_search_result_t *found_cell)
{
uint32_t i, j;
bzero(q->mode_counted, nof_detected_frames);
bzero(q->mode_ntimes, sizeof(uint32_t) * nof_detected_frames);
/* First find mode of CELL IDs */
for (i = 0; i < nof_detected_frames; i++) {
uint32_t cnt = 1;
for (j=i+1;j<nof_detected_frames;j++) {
if (q->candidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) {
q->mode_counted[j]=1;
cnt++;
}
}
q->mode_ntimes[i] = cnt;
}
uint32_t max_times=0, mode_pos=0;
for (i=0;i<nof_detected_frames;i++) {
if (q->mode_ntimes[i] > max_times) {
max_times = q->mode_ntimes[i];
mode_pos = i;
}
}
found_cell->cell_id = q->candidates[mode_pos].cell_id;
/* Now in all these cell IDs, find most frequent CP */
uint32_t nof_normal = 0;
for (i=0;i<nof_detected_frames;i++) {
if (q->candidates[i].cell_id == found_cell->cell_id) {
if (CP_ISNORM(q->candidates[i].cp)) {
nof_normal++;
}
}
}
if (nof_normal > q->mode_ntimes[mode_pos]/2) {
found_cell->cp = CPNORM;
} else {
found_cell->cp = CPEXT;
}
found_cell->mode = (float) q->mode_ntimes[mode_pos]/nof_detected_frames;
found_cell->peak = q->candidates[nof_detected_frames-1].peak;
}
/** Finds up to 3 cells, one per each N_id_2=0,1,2 and stores ID and CP in the structure pointed by found_cell.
* Each position in found_cell corresponds to a different N_id_2.
* Saves in the pointer max_N_id_2 the N_id_2 index of the cell with the highest PSR
* Returns the number of found cells or a negative number if error
*/
int ue_cell_search_scan(ue_cell_search_t * q, ue_cell_search_result_t found_cells[3], uint32_t *max_N_id_2)
{
int ret = 0;
float max_peak_value = -1.0;
uint32_t nof_detected_cells = 0;
for (uint32_t N_id_2=0;N_id_2<3 && ret >= 0;N_id_2++) {
ret = ue_cell_search_scan_N_id_2(q, N_id_2, &found_cells[N_id_2]);
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
return ret;
}
nof_detected_cells += ret;
if (max_N_id_2) {
if (found_cells[N_id_2].peak > max_peak_value) {
max_peak_value = found_cells[N_id_2].peak;
*max_N_id_2 = N_id_2;
}
}
}
return nof_detected_cells;
}
/** Finds a cell for a given N_id_2 and stores ID and CP in the structure pointed by found_cell.
* Returns 1 if the cell is found, 0 if not or -1 on error
*/
int ue_cell_search_scan_N_id_2(ue_cell_search_t * q, uint32_t N_id_2, ue_cell_search_result_t *found_cell)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
cf_t *sf_buffer = NULL;
uint32_t nof_detected_frames = 0;
uint32_t nof_scanned_frames = 0;
if (q != NULL)
{
ret = LIBLTE_SUCCESS;
ue_sync_set_N_id_2(&q->ue_sync, N_id_2);
do {
ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
break;
} else if (ret == 1) {
/* This means a peak was found and ue_sync is now in tracking state */
ret = sync_get_cell_id(&q->ue_sync.strack);
if (ret >= 0) {
/* Save cell id, cp and peak */
q->candidates[nof_detected_frames].cell_id = (uint32_t) ret;
q->candidates[nof_detected_frames].cp = sync_get_cp(&q->ue_sync.strack);
q->candidates[nof_detected_frames].peak = sync_get_peak_value(&q->ue_sync.strack);
INFO
("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n",
nof_detected_frames, nof_scanned_frames, q->nof_frames_to_scan,
q->candidates[nof_detected_frames].peak, q->candidates[nof_detected_frames].cell_id,
lte_cp_string(q->candidates[nof_detected_frames].cp));
memcpy(&tmp_pss_corr[nof_detected_frames*32],
&q->ue_sync.strack.pss.conv_output_avg[128], 32*sizeof(float));
memcpy(&tmp_sss_corr[nof_detected_frames*31],
&q->ue_sync.strack.sss.corr_output_m0, 31*sizeof(float));
nof_detected_frames++;
}
} else if (ret == 0) {
/* This means a peak is not yet found and ue_sync is in find state
* Do nothing, just wait and increase nof_scanned_frames counter.
*/
}
nof_scanned_frames++;
} while ((sync_get_peak_value(&q->ue_sync.strack) < q->detect_threshold ||
nof_detected_frames < 4) &&
nof_scanned_frames < q->nof_frames_to_scan);
/*
vec_save_file("sss_corr",tmp_sss_corr, nof_detected_frames*sizeof(float)*31);
vec_save_file("track_corr",tmp_pss_corr, nof_detected_frames*sizeof(float)*32);
vec_save_file("find_corr",q->ue_sync.sfind.pss.conv_output_avg,
sizeof(float)*(9600+127));
*/
/* In either case, check if the mean PSR is above the minimum threshold */
if (nof_detected_frames > 0) {
ret = 1; // A cell has been found.
if (found_cell) {
get_cell(q, nof_detected_frames, found_cell);
printf("Found CELL PHYID: %d, CP: %s, PSR: %.1f, Reliability: %.0f \%\n",
found_cell->cell_id, lte_cp_string(found_cell->cp),
found_cell->peak, 100*found_cell->mode);
}
} else {
ret = 0; // A cell was not found.
}
}
return ret;
}

@ -1,260 +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 <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <unistd.h>
#include "liblte/phy/ue/ue_celldetect.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
#define CS_CELL_DETECT_THRESHOLD 1.2
#define CS_SFLEN 5*SF_LEN(CS_FFTSIZE)
int ue_celldetect_init(ue_celldetect_t * q) {
return ue_celldetect_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL);
}
int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
ret = LIBLTE_ERROR;
bzero(q, sizeof(ue_celldetect_t));
q->candidates = calloc(sizeof(ue_celldetect_result_t), max_frames_total);
if (!q->candidates) {
perror("malloc");
goto clean_exit;
}
if (sync_init(&q->sfind, CS_SFLEN, CS_FFTSIZE)) {
goto clean_exit;
}
q->mode_ntimes = calloc(sizeof(uint32_t), max_frames_total);
if (!q->mode_ntimes) {
perror("malloc");
goto clean_exit;
}
q->mode_counted = calloc(sizeof(uint8_t), max_frames_total);
if (!q->mode_counted) {
perror("malloc");
goto clean_exit;
}
/* Accept all peaks because search space is 5 ms and there is always a peak */
sync_set_threshold(&q->sfind, 1.0);
sync_sss_en(&q->sfind, true);
sync_set_sss_algorithm(&q->sfind, SSS_PARTIAL_3);
sync_set_em_alpha(&q->sfind, 0.01);
q->max_frames_total = max_frames_total;
q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL;
ue_celldetect_reset(q);
ret = LIBLTE_SUCCESS;
}
clean_exit:
if (ret == LIBLTE_ERROR) {
ue_celldetect_free(q);
}
return ret;
}
void ue_celldetect_free(ue_celldetect_t * q)
{
if (q->candidates) {
free(q->candidates);
}
if (q->mode_counted) {
free(q->mode_counted);
}
if (q->mode_ntimes) {
free(q->mode_ntimes);
}
sync_free(&q->sfind);
bzero(q, sizeof(ue_celldetect_t));
}
void ue_celldetect_reset(ue_celldetect_t * q)
{
q->current_nof_detected = 0;
q->current_nof_total = 0;
}
void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold)
{
q->detect_threshold = threshold;
}
int ue_celldetect_set_nof_frames_total(ue_celldetect_t * q, uint32_t nof_frames)
{
if (nof_frames <= q->max_frames_total) {
q->nof_frames_total = nof_frames;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR;
}
}
/* Decide the most likely cell based on the mode */
void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell)
{
uint32_t i, j;
if (!q->current_nof_detected) {
return;
}
bzero(q->mode_counted, q->current_nof_detected);
bzero(q->mode_ntimes, sizeof(uint32_t) * q->current_nof_detected);
/* First find mode of CELL IDs */
for (i = 0; i < q->current_nof_detected; i++) {
uint32_t cnt = 1;
for (j=i+1;j<q->current_nof_detected;j++) {
if (q->candidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) {
q->mode_counted[j]=1;
cnt++;
}
}
q->mode_ntimes[i] = cnt;
}
uint32_t max_times=0, mode_pos=0;
for (i=0;i<q->current_nof_detected;i++) {
if (q->mode_ntimes[i] > max_times) {
max_times = q->mode_ntimes[i];
mode_pos = i;
}
}
found_cell->cell_id = q->candidates[mode_pos].cell_id;
/* Now in all these cell IDs, find most frequent CP */
uint32_t nof_normal = 0;
for (i=0;i<q->current_nof_detected;i++) {
if (q->candidates[i].cell_id == found_cell->cell_id) {
if (CP_ISNORM(q->candidates[i].cp)) {
nof_normal++;
}
}
}
if (nof_normal > q->mode_ntimes[mode_pos]/2) {
found_cell->cp = CPNORM;
} else {
found_cell->cp = CPEXT;
}
found_cell->mode = (float) q->mode_ntimes[mode_pos]/q->current_nof_detected;
found_cell->peak = q->candidates[q->current_nof_detected-1].peak;
q->current_nof_detected = q->current_nof_total = 0;
}
int ue_celldetect_set_N_id_2(ue_celldetect_t *q, uint32_t N_id_2) {
return sync_set_N_id_2(&q->sfind, N_id_2);
}
int ue_celldetect_scan(ue_celldetect_t * q,
cf_t *signal,
uint32_t nsamples)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t peak_idx;
uint32_t nof_input_frames;
if (q != NULL &&
signal != NULL &&
nsamples >= CS_FLEN)
{
ret = LIBLTE_SUCCESS;
if (nsamples % CS_FLEN) {
printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", CS_FLEN);
nsamples = (nsamples/CS_FLEN) * CS_FLEN;
}
nof_input_frames = nsamples/CS_FLEN;
for (uint32_t nf=0;nf<nof_input_frames;nf++) {
INFO("[%3d/%3d]: Searching cells with N_id_2=%d. %d frames\n",
q->current_nof_detected, q->current_nof_total, q->sfind.N_id_2, nof_input_frames);
/* Find peak and cell id */
ret = sync_find(&q->sfind, &signal[nf*CS_FLEN], 0, &peak_idx);
if (ret < 0) {
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
return LIBLTE_ERROR;
}
/* Process the peak result */
if (ret == 1) {
if (sync_sss_detected(&q->sfind)) {
ret = sync_get_cell_id(&q->sfind);
if (ret >= 0) {
/* Save cell id, cp and peak */
q->candidates[q->current_nof_detected].cell_id = (uint32_t) ret;
q->candidates[q->current_nof_detected].cp = sync_get_cp(&q->sfind);
q->candidates[q->current_nof_detected].peak = sync_get_peak_value(&q->sfind);
}
INFO
("[%3d/%3d]: Found peak at %4d, value %.3f, Cell_id: %d CP: %s\n",
q->current_nof_detected, q->current_nof_total, peak_idx,
q->candidates[q->current_nof_detected].peak, q->candidates[q->current_nof_detected].cell_id,
lte_cp_string(q->candidates[q->current_nof_detected].cp));
q->current_nof_detected++;
} else {
/* If peak position does not allow to read SSS, return error -3 */
return CS_FRAME_UNALIGNED;
}
}
q->current_nof_total++;
/* Decide cell ID and CP if we detected up to nof_frames_detected */
if (sync_get_peak_value(&q->sfind) > q->detect_threshold) {
ret = CS_CELL_DETECTED;
} else if (q->current_nof_total == q->nof_frames_total) {
if (sync_get_peak_value(&q->sfind) > CS_CELL_DETECT_THRESHOLD) {
ret = CS_CELL_DETECTED;
} else {
ret = CS_CELL_NOT_DETECTED;
q->current_nof_detected = q->current_nof_total = 0;
}
} else {
ret = 0;
}
}
}
return ret;
}

@ -36,21 +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"
int ue_mib_init_1_92(ue_mib_t * q, int ue_mib_init(ue_mib_t * q,
uint32_t cell_id, lte_cell_t cell)
lte_cp_t cp)
{
lte_cell_t cell;
cell.nof_ports = MIB_MAX_PORTS;
cell.nof_prb = 6;
cell.id = cell_id;
cell.cp = cp;
return ue_mib_init(q, cell, true);
}
int ue_mib_init(ue_mib_t * q,
lte_cell_t cell,
bool do_sync)
{ {
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
@ -58,8 +45,7 @@ int ue_mib_init_1_92(ue_mib_t * q,
cell.nof_ports <= MIB_MAX_PORTS) cell.nof_ports <= MIB_MAX_PORTS)
{ {
ret = LIBLTE_ERROR; ret = LIBLTE_ERROR;
bzero(q, sizeof(ue_mib_t)); bzero(q, sizeof(ue_mib_t));
q->sf_symbols = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); q->sf_symbols = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
@ -76,23 +62,6 @@ int ue_mib_init_1_92(ue_mib_t * q,
} }
} }
if (do_sync) {
if (sync_init(&q->sfind, 5*SF_LEN_PRB(cell.nof_prb), lte_symbol_sz(cell.nof_prb))) {
goto clean_exit;
}
sync_set_threshold(&q->sfind, 1.0); // Because we are capturing 5 ms frames and there is always peak
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, cell.cp);
}
if (cfo_init(&q->cfocorr, 5*SF_LEN_PRB(cell.nof_prb))) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
if (lte_fft_init(&q->fft, cell.cp, cell.nof_prb)) { if (lte_fft_init(&q->fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initializing FFT\n"); fprintf(stderr, "Error initializing FFT\n");
goto clean_exit; goto clean_exit;
@ -127,7 +96,6 @@ void ue_mib_free(ue_mib_t * q)
free(q->ce[i]); free(q->ce[i]);
} }
} }
cfo_free(&q->cfocorr);
sync_free(&q->sfind); sync_free(&q->sfind);
chest_dl_free(&q->chest); chest_dl_free(&q->chest);
pbch_free(&q->pbch); pbch_free(&q->pbch);
@ -140,19 +108,12 @@ void ue_mib_free(ue_mib_t * q)
void ue_mib_reset(ue_mib_t * q) void ue_mib_reset(ue_mib_t * q)
{ {
q->frame_cnt = 0; q->frame_cnt = 0;
q->last_frame_trial = 0;
pbch_decode_reset(&q->pbch); pbch_decode_reset(&q->pbch);
} }
void ue_mib_set_threshold(ue_mib_t * q, float threshold) 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)
sync_set_threshold(&q->sfind, threshold);
}
int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset)
{ {
int ret = LIBLTE_SUCCESS; int ret = LIBLTE_SUCCESS;
cf_t *ce_slot1[MAX_PORTS]; cf_t *ce_slot1[MAX_PORTS];
@ -166,11 +127,8 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
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 > 16) {
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);
} }
@ -185,102 +143,90 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error decoding PBCH (%d)\n", ret); 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;
} }
void ue_mib_get_payload(ue_mib_t *q,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports, int ue_mib_sync_init(ue_mib_sync_t *q,
uint32_t *sfn_offset) uint32_t cell_id,
lte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler)
{ {
memcpy(bch_payload, q->bch_payload, sizeof(uint8_t) * BCH_PAYLOAD_LEN); lte_cell_t cell;
if (nof_tx_ports) { cell.nof_ports = MIB_MAX_PORTS;
*nof_tx_ports = q->nof_tx_ports; 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 (sfn_offset) { if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) {
*sfn_offset = q->sfn_offset; 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;
} }
int ue_mib_sync_and_decode_1_92(ue_mib_t * q, void ue_mib_sync_free(ue_mib_sync_t *q) {
cf_t *signal, ue_mib_free(&q->ue_mib);
uint32_t nsamples) ue_sync_free(&q->ue_sync);
}
void ue_mib_sync_reset(ue_mib_sync_t * q) {
ue_mib_reset(&q->ue_mib);
ue_sync_reset(&q->ue_sync);
}
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; int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t peak_idx=0; cf_t *sf_buffer = NULL;
uint32_t nof_input_frames; uint32_t nof_frames = 0;
int mib_ret;
if (q != NULL && if (q != NULL)
signal != NULL)
{ {
if (nsamples < MIB_FRAME_SIZE_SEARCH) { ret = LIBLTE_SUCCESS;
fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE_SEARCH); do {
return LIBLTE_ERROR; mib_ret = MIB_NOTFOUND;
} ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
ret = LIBLTE_SUCCESS;
if (nsamples % MIB_FRAME_SIZE_SEARCH) {
printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE_SEARCH);
nsamples = (nsamples/MIB_FRAME_SIZE_SEARCH) * MIB_FRAME_SIZE_SEARCH;
}
nof_input_frames = nsamples/MIB_FRAME_SIZE_SEARCH;
for (int nf=0;nf<nof_input_frames;nf++) {
/* Find peak and cell id */
ret = sync_find(&q->sfind, signal, nf*MIB_FRAME_SIZE_SEARCH, &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) {
/* Check if we have space for reading the MIB and we are in Subframe #0 */ mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
if (ret == 1)
{
if (sync_sss_detected(&q->sfind))
{
if (sync_get_sf_idx(&q->sfind) == 0)
{
if (nf*MIB_FRAME_SIZE_SEARCH + peak_idx + MIB_FRAME_SIZE_SEARCH/10 <= nsamples &&
nf*MIB_FRAME_SIZE_SEARCH + peak_idx > MIB_FRAME_SIZE_SEARCH/10)
{
// PSS and SSS detected and we have space to decode the PBCH.
INFO("Trying to decode PBCH\n",0);
ret = ue_mib_decode_aligned_frame(q,
&signal[nf*MIB_FRAME_SIZE_SEARCH+peak_idx-MIB_FRAME_SIZE_SEARCH/10],
q->bch_payload, &q->nof_tx_ports, &q->sfn_offset);
} else {
printf("Not enough space for PBCH: PSS signal is at offset %d\n",peak_idx);
ret = MIB_FRAME_UNALIGNED;
}
} else {
// Wait for subframe 0
ret = 0;
}
} else { } else {
INFO("SSS not detected\n",0); INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
ret = 0; // wait to detect it ue_mib_reset(&q->ue_mib);
} }
} else { nof_frames++;
INFO("PSS not detected\n",0);
ret = 0; // wait to detect it?
} }
q->frame_cnt++; } while (mib_ret == MIB_NOTFOUND && ret >= 0 && nof_frames < max_frames_timeout);
} if (mib_ret < 0) {
ret = mib_ret;
}
} }
return ret; return mib_ret;
} }

@ -40,17 +40,9 @@
#define MAX_TIME_OFFSET 128 #define MAX_TIME_OFFSET 128
cf_t dummy[MAX_TIME_OFFSET]; cf_t dummy[MAX_TIME_OFFSET];
#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb)
#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE)
#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define FIND_THRESHOLD 4.0
#define TRACK_THRESHOLD 2.0
#define TRACK_MAX_LOST 10 #define TRACK_MAX_LOST 10
#define TRACK_FRAME_SIZE 32 #define TRACK_FRAME_SIZE 32
#define FIND_NOF_AVG_FRAMES 4
int ue_sync_init(ue_sync_t *q, int ue_sync_init(ue_sync_t *q,
lte_cell_t cell, lte_cell_t cell,
@ -59,43 +51,85 @@ int ue_sync_init(ue_sync_t *q,
{ {
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
stream_handler != NULL && stream_handler != NULL &&
lte_cell_isvalid(&cell) && lte_nofprb_isvalid(cell.nof_prb) &&
recv_callback != NULL) recv_callback != NULL)
{ {
ret = LIBLTE_ERROR; ret = LIBLTE_ERROR;
bzero(q, sizeof(ue_sync_t)); bzero(q, sizeof(ue_sync_t));
q->decode_sss_on_track = false;
q->stream = stream_handler; q->stream = stream_handler;
q->recv_callback = recv_callback; q->recv_callback = recv_callback;
q->cell = cell; q->cell = cell;
q->fft_size = lte_symbol_sz(q->cell.nof_prb);
if(sync_init(&q->sfind, CURRENT_SFLEN, CURRENT_FFTSIZE)) { q->sf_len = SF_LEN(q->fft_size);
if (cell.id == 1000) {
/* If the cell is unkown, decode SSS on track state */
q->decode_sss_on_track = true;
/* If the cell is unkown, we search PSS/SSS in 5 ms */
q->nof_recv_sf = 5;
} else {
q->decode_sss_on_track = false;
/* If the cell is known, we work on a 1ms basis */
q->nof_recv_sf = 1;
}
q->frame_len = q->nof_recv_sf*q->sf_len;
if(sync_init(&q->sfind, q->frame_len, q->fft_size)) {
fprintf(stderr, "Error initiating sync find\n"); fprintf(stderr, "Error initiating sync find\n");
goto clean_exit; goto clean_exit;
} }
if(sync_init(&q->strack, TRACK_FRAME_SIZE, CURRENT_FFTSIZE)) { if(sync_init(&q->strack, TRACK_FRAME_SIZE, q->fft_size)) {
fprintf(stderr, "Error initiating sync track\n"); fprintf(stderr, "Error initiating sync track\n");
goto clean_exit; goto clean_exit;
} }
sync_set_N_id_2(&q->sfind, cell.id%3); if (cell.id == 1000) {
sync_set_threshold(&q->sfind, FIND_THRESHOLD); /* If the cell id is unknown, enable CP detection on find */
q->sfind.cp = cell.cp; sync_cp_en(&q->sfind, true);
sync_cp_en(&q->sfind, false); sync_cp_en(&q->strack, true);
sync_correct_cfo(&q->sfind, true);
sync_set_em_alpha(&q->sfind, 1); /* Correct CFO in all cases because both states are called always.
*/
sync_set_N_id_2(&q->strack, cell.id%3); sync_correct_cfo(&q->sfind, true);
sync_set_threshold(&q->strack, TRACK_THRESHOLD); sync_correct_cfo(&q->strack, true);
q->strack.cp = cell.cp;
sync_cp_en(&q->strack, false); sync_set_threshold(&q->sfind, 1.1);
sync_correct_cfo(&q->strack, false); sync_set_em_alpha(&q->sfind, 0.01);
q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES;
q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t)); sync_set_threshold(&q->strack, 2.0);
} else {
sync_set_N_id_2(&q->sfind, cell.id%3);
sync_set_N_id_2(&q->strack, cell.id%3);
q->sfind.cp = cell.cp;
q->strack.cp = cell.cp;
sync_cp_en(&q->sfind, false);
sync_cp_en(&q->strack, false);
/* In find phase and if the cell is known, do not average pss correlation
* because we only capture 1 subframe and do not know where the peak is.
*/
sync_set_em_alpha(&q->sfind, 1);
q->nof_avg_find_frames = 1;
sync_set_threshold(&q->sfind, 2.0);
sync_set_threshold(&q->strack, 6.0);
/* Correct CFO in the find state but not in the track state, since is called only
* 1 every 5 subframes. Will do it in the ue_sync_get_buffer() function.
*/
sync_correct_cfo(&q->sfind, true);
sync_correct_cfo(&q->strack, false);
}
q->input_buffer = vec_malloc(2*q->frame_len * sizeof(cf_t));
if (!q->input_buffer) { if (!q->input_buffer) {
perror("malloc"); perror("malloc");
goto clean_exit; goto clean_exit;
@ -114,7 +148,7 @@ clean_exit:
} }
uint32_t ue_sync_sf_len(ue_sync_t *q) { uint32_t ue_sync_sf_len(ue_sync_t *q) {
return CURRENT_SFLEN; return q->frame_len;
} }
void ue_sync_free(ue_sync_t *q) { void ue_sync_free(ue_sync_t *q) {
@ -150,33 +184,45 @@ void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
q->decode_sss_on_track = enabled; q->decode_sss_on_track = enabled;
} }
void ue_sync_set_N_id_2(ue_sync_t *q, uint32_t N_id_2) {
ue_sync_reset(q);
sync_set_N_id_2(&q->strack, N_id_2);
sync_set_N_id_2(&q->sfind, N_id_2);
}
static int find_peak_ok(ue_sync_t *q) { static int find_peak_ok(ue_sync_t *q) {
/* Receive the rest of the next subframe */
if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+CURRENT_SFLEN/2) < 0) { if (sync_sss_detected(&q->sfind)) {
return LIBLTE_ERROR; /* Get the subframe index (0 or 5) */
q->sf_idx = sync_get_sf_idx(&q->sfind) + q->nof_recv_sf;
} else {
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
} }
if (sync_sss_detected(&q->sfind)) { q->frame_find_cnt++;
INFO("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n",
q->frame_find_cnt, q->peak_idx,
sync_get_last_peak_value(&q->sfind), q->cell.id, lte_cp_string(q->cell.cp));
if (q->frame_find_cnt >= q->nof_avg_find_frames || q->peak_idx < 2*q->fft_size) {
INFO("Realigning frame, reading %d samples\n", q->peak_idx+q->sf_len/2);
/* Receive the rest of the subframe so that we are subframe aligned*/
if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+q->sf_len/2) < 0) {
return LIBLTE_ERROR;
}
/* Get the subframe index (0 or 5) */
q->sf_idx = sync_get_sf_idx(&q->sfind) + 1;
/* Reset variables */ /* Reset variables */
q->frame_ok_cnt = 0; q->frame_ok_cnt = 0;
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
q->frame_total_cnt = 0; q->frame_total_cnt = 0;
q->frame_find_cnt = 0;
/* Goto Tracking state */ /* Goto Tracking state */
q->state = SF_TRACK; q->state = SF_TRACK;
}
INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n",
q->peak_idx, sync_get_last_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
} else {
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
}
return 0; return 0;
} }
@ -191,7 +237,12 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
q->sf_idx = sync_get_sf_idx(&q->strack); q->sf_idx = sync_get_sf_idx(&q->strack);
} }
} else { } else {
q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2); // Adjust time offset
q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2 - (int) q->strack.fft_size);
if (q->time_offset) {
INFO("Time offset adjustment: %d samples\n", q->time_offset);
}
/* If the PSS peak is beyond the frame (we sample too slowly), /* If the PSS peak is beyond the frame (we sample too slowly),
discard the offseted samples to align next frame */ discard the offseted samples to align next frame */
@ -205,7 +256,7 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
/* compute cumulative moving average time offset */ /* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt); q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; q->peak_idx = q->sf_len/2 + q->time_offset;
q->frame_ok_cnt++; q->frame_ok_cnt++;
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
} }
@ -218,7 +269,7 @@ int track_peak_no(ue_sync_t *q) {
/* if we missed too many PSS go back to FIND */ /* if we missed too many PSS go back to FIND */
q->frame_no_cnt++; q->frame_no_cnt++;
if (q->frame_no_cnt >= TRACK_MAX_LOST) { if (q->frame_no_cnt >= TRACK_MAX_LOST) {
printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); INFO("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt);
q->state = SF_FIND; q->state = SF_FIND;
} else { } else {
INFO("Tracking peak not found. Peak %.3f, %d lost\n", INFO("Tracking peak not found. Peak %.3f, %d lost\n",
@ -237,11 +288,8 @@ static int receive_samples(ue_sync_t *q) {
q->time_offset = -q->time_offset; q->time_offset = -q->time_offset;
} }
/* copy last part of the last subframe (use move since there could be overlapping) */ /* Get N subframes from the USRP getting more samples and keeping the previous samples, if any */
//memcpy(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], q->frame_len - q->time_offset) < 0) {
/* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */
if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
@ -251,6 +299,8 @@ static int receive_samples(ue_sync_t *q) {
return LIBLTE_SUCCESS; return LIBLTE_SUCCESS;
} }
bool first_track = true;
int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t track_idx; uint32_t track_idx;
@ -275,25 +325,14 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
if (ret == 1) { if (ret == 1) {
ret = find_peak_ok(q); ret = find_peak_ok(q);
} else if (q->peak_idx != 0) { }
uint32_t rlen;
if (q->peak_idx < CURRENT_SFLEN/2) {
rlen = CURRENT_SFLEN/2-q->peak_idx;
} else {
rlen = q->peak_idx;
}
if (q->recv_callback(q->stream, q->input_buffer, rlen) < 0) {
fprintf(stderr, "Error calling recv callback function\n");
return LIBLTE_ERROR;
}
}
break; break;
case SF_TRACK: case SF_TRACK:
ret = 1; ret = 1;
sync_sss_en(&q->strack, q->decode_sss_on_track); sync_sss_en(&q->strack, q->decode_sss_on_track);
q->sf_idx = (q->sf_idx + 1) % 10; q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10;
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */ /* Every SF idx 0 and 5, find peak around known position q->peak_idx */
if (q->sf_idx == 0 || q->sf_idx == 5) { if (q->sf_idx == 0 || q->sf_idx == 5) {
@ -305,8 +344,10 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
track_idx = 0; track_idx = 0;
/* track pss around the middle of the subframe, where the PSS is */ /* track PSS/SSS around the expected PSS position */
ret = sync_find(&q->strack, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE-q->strack.frame_size/2, &track_idx); ret = sync_find(&q->strack, q->input_buffer,
q->frame_len - q->sf_len/2 - q->fft_size - q->strack.frame_size/2,
&track_idx);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error tracking correlation peak\n"); fprintf(stderr, "Error tracking correlation peak\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
@ -329,11 +370,13 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
return LIBLTE_SUCCESS; return LIBLTE_SUCCESS;
} }
q->frame_total_cnt++; q->frame_total_cnt++;
} }
/* Do CFO Correction and deliver the frame */ /* Do CFO Correction if not done in track and deliver the frame */
cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / CURRENT_FFTSIZE); if (!q->strack.correct_cfo) {
cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / q->fft_size);
}
*sf_symbols = q->input_buffer; *sf_symbols = q->input_buffer;
break; break;
@ -350,6 +393,7 @@ void ue_sync_reset(ue_sync_t *q) {
q->frame_total_cnt = 0; q->frame_total_cnt = 0;
q->mean_time_offset = 0.0; q->mean_time_offset = 0.0;
q->time_offset = 0; q->time_offset = 0;
q->frame_find_cnt = 0;
#ifdef MEASURE_EXEC_TIME #ifdef MEASURE_EXEC_TIME
q->mean_exec_time = 0; q->mean_exec_time = 0;
#endif #endif

Loading…
Cancel
Save