mirror of https://github.com/pvnis/srsRAN_4G.git
Improved cell search algorithm. Using narrow correlation for cell acquisition and MIB decoding
parent
5a032c4316
commit
243f23752d
@ -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
|
@ -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_
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue