mirror of https://github.com/PentHertz/srsLTE.git
Improved cell search algorithm. Using narrow correlation for cell acquisition and MIB decoding
This commit is contained in:
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
|
||||
#################################################################
|
||||
|
||||
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)
|
||||
|
||||
add_executable(pdsch_enodeb pdsch_enodeb.c)
|
||||
|
@ -81,10 +81,10 @@ ENDIF(${GRAPHICS_FIND} EQUAL -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 )
|
||||
|
||||
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)
|
||||
|
||||
MESSAGE(STATUS " UHD examples will be installed.")
|
||||
|
|
|
@ -39,16 +39,16 @@
|
|||
#include "liblte/rrc/rrc.h"
|
||||
#include "liblte/phy/phy.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_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40
|
||||
|
||||
float gain_offset = B210_DEFAULT_GAIN_CORREC;
|
||||
|
||||
cell_detect_cfg_t cell_detect_config = {
|
||||
100, // nof_frames_total
|
||||
6.0 // early-stops cell detection if mean PSR is above this value
|
||||
cell_search_cfg_t cell_detect_config = {
|
||||
50, // nof_frames_total
|
||||
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);
|
||||
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)) {
|
||||
fprintf(stderr, "Cell not found\n");
|
||||
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");
|
||||
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);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
@ -191,7 +200,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
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");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -240,9 +249,7 @@ int main(int argc, char **argv) {
|
|||
case DECODE_MIB:
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 0) {
|
||||
pbch_decode_reset(&ue_mib.pbch);
|
||||
n = ue_mib_decode_aligned_frame(&ue_mib,
|
||||
sf_buffer, bch_payload_unpacked,
|
||||
NULL, &sfn_offset);
|
||||
n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE MIB\n");
|
||||
exit(-1);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#include "cell_search_utils.h"
|
||||
#include "cuhd_utils.h"
|
||||
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
|
@ -55,7 +55,7 @@
|
|||
int band = -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;
|
||||
|
@ -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 n;
|
||||
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;
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
uint32_t freq;
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN];
|
||||
uint32_t nof_tx_ports;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
|
@ -150,21 +154,44 @@ int main(int argc, char **argv) {
|
|||
if (VERBOSE_ISINFO()) {
|
||||
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);
|
||||
}
|
||||
|
||||
n = detect_all_cells(&config, uhd, found_cells);
|
||||
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 = ue_cell_search_scan(&cs, found_cells, NULL);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error searching cell\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (n == CS_CELL_DETECTED) {
|
||||
} else if (n == 1) {
|
||||
for (int i=0;i<3;i++) {
|
||||
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)) {
|
||||
fprintf(stderr, "Error decoding PBCH\n");
|
||||
lte_cell_t cell;
|
||||
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);
|
||||
} else {
|
||||
printf("Cell found with %d ports. Decoded MIB: \n", nof_tx_ports);
|
||||
vec_fprint_hex(stdout, bch_payload, BCH_PAYLOAD_LEN);
|
||||
}
|
||||
if (ret == MIB_FOUND) {
|
||||
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 {
|
||||
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
|
||||
}cell_detect_cfg_t;
|
||||
}cell_search_cfg_t;
|
||||
|
||||
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);
|
||||
int cuhd_mib_decoder(void *uhd,
|
||||
uint32_t max_nof_frames,
|
||||
lte_cell_t *cell);
|
||||
|
||||
int detect_all_cells(cell_detect_cfg_t *config,
|
||||
void *uhd,
|
||||
ue_celldetect_result_t found_cell[3]);
|
||||
int cuhd_cell_search(void *uhd,
|
||||
cell_search_cfg_t *config,
|
||||
int force_N_id_2,
|
||||
lte_cell_t *cell);
|
||||
|
||||
int cuhd_search_and_decode_mib(void *uhd,
|
||||
cell_search_cfg_t *config,
|
||||
int force_N_id_2,
|
||||
lte_cell_t *cell);
|
||||
|
||||
int detect_cell(cell_detect_cfg_t *config,
|
||||
void *uhd,
|
||||
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/phy/phy.h"
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#include "cell_search_utils.h"
|
||||
#include "cuhd_utils.h"
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
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;
|
||||
|
||||
|
||||
cell_detect_cfg_t cell_detect_config = {
|
||||
cell_search_cfg_t cell_detect_config = {
|
||||
100, // nof_frames_total
|
||||
4.0 // threshold
|
||||
};
|
||||
|
@ -188,10 +188,24 @@ int main(int argc, char **argv) {
|
|||
cuhd_rx_wait_lo_locked(uhd);
|
||||
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)) {
|
||||
fprintf(stderr, "Cell not found\n");
|
||||
ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error searching for cell\n");
|
||||
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);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
|
@ -205,7 +219,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
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");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -247,9 +261,7 @@ int main(int argc, char **argv) {
|
|||
case DECODE_MIB:
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 0) {
|
||||
pbch_decode_reset(&ue_mib.pbch);
|
||||
n = ue_mib_decode_aligned_frame(&ue_mib,
|
||||
sf_buffer, bch_payload_unpacked,
|
||||
NULL, &sfn_offset);
|
||||
n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE MIB\n");
|
||||
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(&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);
|
||||
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_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);
|
||||
|
|
|
@ -60,6 +60,8 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
|
|||
#define PRNTI 0xFFFE
|
||||
#define MRNTI 0xFFFD
|
||||
|
||||
#define CELL_ID_UNKNOWN 1000
|
||||
|
||||
#define MAX_NSYMB 7
|
||||
|
||||
#define MAX_PRB 110
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
|
||||
#include "liblte/phy/ue/ue_sync.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/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 "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/ch_estimation/chest_dl.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
|
@ -57,10 +57,8 @@
|
|||
|
||||
|
||||
#define MIB_MAX_PORTS 4
|
||||
#define MIB_FRAME_SIZE_SEARCH 9600
|
||||
#define MIB_FFT_SIZE 128
|
||||
#define MIB_NOF_PRB 6
|
||||
|
||||
#define MIB_FRAME_UNALIGNED -3
|
||||
#define MIB_FOUND 1
|
||||
#define MIB_NOTFOUND 0
|
||||
|
||||
|
@ -70,7 +68,6 @@ typedef struct LIBLTE_API {
|
|||
cf_t *sf_symbols;
|
||||
cf_t *ce[MIB_MAX_PORTS];
|
||||
|
||||
cfo_t cfocorr;
|
||||
lte_fft_t fft;
|
||||
chest_dl_t chest;
|
||||
pbch_t pbch;
|
||||
|
@ -80,43 +77,45 @@ typedef struct LIBLTE_API {
|
|||
uint32_t sfn_offset;
|
||||
|
||||
uint32_t frame_cnt;
|
||||
uint32_t last_frame_trial;
|
||||
} 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,
|
||||
lte_cell_t cell,
|
||||
bool do_sync);
|
||||
lte_cell_t cell);
|
||||
|
||||
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,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples);
|
||||
|
||||
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,
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN],
|
||||
uint32_t *nof_tx_ports,
|
||||
uint32_t *sfn_offset);
|
||||
|
||||
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
|
||||
LIBLTE_API 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);
|
||||
|
||||
|
||||
/* This interface uses ue_mib and ue_sync to first get synchronized subframes
|
||||
* and then decode MIB
|
||||
*/
|
||||
typedef struct {
|
||||
ue_mib_t ue_mib;
|
||||
ue_sync_t ue_sync;
|
||||
} ue_mib_sync_t;
|
||||
|
||||
LIBLTE_API int ue_mib_sync_init(ue_mib_sync_t *q,
|
||||
uint32_t cell_id,
|
||||
lte_cp_t cp,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
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;
|
||||
|
||||
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) */
|
||||
uint64_t frame_ok_cnt;
|
||||
uint32_t frame_no_cnt;
|
||||
|
@ -82,6 +89,7 @@ typedef struct LIBLTE_API {
|
|||
uint32_t peak_idx;
|
||||
int time_offset;
|
||||
float mean_time_offset;
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
float mean_exec_time;
|
||||
#endif
|
||||
|
@ -89,9 +97,9 @@ typedef struct LIBLTE_API {
|
|||
|
||||
|
||||
LIBLTE_API int ue_sync_init(ue_sync_t *q,
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
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_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,
|
||||
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)
|
||||
*/
|
||||
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;
|
||||
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)
|
||||
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|)
|
||||
vec_prod_conj_ccc(r0,h0,q->tmp1, 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,
|
||||
&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
|
||||
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
|
||||
* We know they are ordered.
|
||||
|
|
|
@ -46,9 +46,6 @@
|
|||
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
|
||||
#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) {
|
||||
if (cfi > 0 && cfi < 4) {
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
|
||||
/* demodulate symbols
|
||||
* 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
|
||||
*/
|
||||
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_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");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
bzero(q->conv_output, sizeof(cf_t) * buffer_size);
|
||||
q->conv_output_avg = vec_malloc(buffer_size * sizeof(float));
|
||||
if (!q->conv_output_avg) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
bzero(q->conv_output_avg, sizeof(float) * buffer_size);
|
||||
#ifdef PSS_ACCUMULATE_ABS
|
||||
q->conv_output_abs = vec_malloc(buffer_size * sizeof(float));
|
||||
if (!q->conv_output_abs) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
bzero(q->conv_output_abs, sizeof(float) * buffer_size);
|
||||
#endif
|
||||
|
||||
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));
|
||||
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");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
|
||||
|
||||
/* Correlate input with PSS sequence */
|
||||
if (q->frame_size >= q->fft_size) {
|
||||
#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,
|
||||
q->pss_signal_freq[q->N_id_2], q->conv_output);
|
||||
#else
|
||||
conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size);
|
||||
#endif
|
||||
} else {
|
||||
for (int i=0;i<q->frame_size;i++) {
|
||||
q->conv_output[i] = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], &input[i], q->fft_size);
|
||||
}
|
||||
conv_output_len = q->frame_size;
|
||||
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->fft_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;
|
||||
|
||||
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_left, 1000000*q->conv_output_avg[sl_left],
|
||||
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) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
int N_id_1;
|
||||
if (m1 > m0) {
|
||||
return q->N_id_1_table[m0][m1 - 1];
|
||||
N_id_1 = q->N_id_1_table[m0][m1 - 1];
|
||||
} 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 */
|
||||
|
|
|
@ -59,9 +59,11 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
|
|||
|
||||
bzero(q, sizeof(sync_t));
|
||||
q->detect_cp = true;
|
||||
q->cp = CPNORM;
|
||||
q->mean_peak_value = 0.0;
|
||||
q->sss_en = true;
|
||||
q->correct_cfo = true;
|
||||
q->mean_cfo = 0;
|
||||
q->N_id_2 = 1000;
|
||||
q->N_id_1 = 1000;
|
||||
q->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)) {
|
||||
return q->N_id_1*3 + q->N_id_2;
|
||||
} else {
|
||||
fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n");
|
||||
return LIBLTE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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);
|
||||
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) {
|
||||
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
|
||||
* 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;
|
||||
|
||||
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 */
|
||||
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) {
|
||||
INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos);
|
||||
|
||||
switch(q->sss_alg) {
|
||||
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 {
|
||||
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
|
||||
}
|
||||
|
||||
|
||||
if (q->detect_cp) {
|
||||
if (peak_pos + find_offset >= 2*(q->fft_size + CP_EXT(q->fft_size))) {
|
||||
q->cp = sync_detect_cp(q, input, peak_pos + find_offset);
|
||||
} else {
|
||||
INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to detect SSS
|
||||
if (q->sss_en) {
|
||||
/* Correct CFO with the averaged CFO estimation */
|
||||
|
@ -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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -346,8 +349,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
|
|||
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",
|
||||
ret, q->N_id_2, q->frame_size, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo);
|
||||
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, 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)) {
|
||||
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) {
|
||||
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);
|
||||
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
|
||||
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);
|
||||
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
|
||||
sss_error1++;
|
||||
}
|
||||
INFO("Full N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1));
|
||||
}
|
||||
|
||||
// Estimate CP
|
||||
|
|
|
@ -121,7 +121,8 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
/* 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) {
|
||||
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/vector.h"
|
||||
|
||||
int ue_mib_init_1_92(ue_mib_t * q,
|
||||
uint32_t cell_id,
|
||||
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 ue_mib_init(ue_mib_t * q,
|
||||
lte_cell_t cell)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
ret = LIBLTE_ERROR;
|
||||
bzero(q, sizeof(ue_mib_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)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
goto clean_exit;
|
||||
|
@ -127,7 +96,6 @@ void ue_mib_free(ue_mib_t * q)
|
|||
free(q->ce[i]);
|
||||
}
|
||||
}
|
||||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->sfind);
|
||||
chest_dl_free(&q->chest);
|
||||
pbch_free(&q->pbch);
|
||||
|
@ -140,19 +108,12 @@ void ue_mib_free(ue_mib_t * q)
|
|||
|
||||
void ue_mib_reset(ue_mib_t * q)
|
||||
{
|
||||
q->frame_cnt = 0;
|
||||
q->last_frame_trial = 0;
|
||||
|
||||
q->frame_cnt = 0;
|
||||
pbch_decode_reset(&q->pbch);
|
||||
}
|
||||
|
||||
void ue_mib_set_threshold(ue_mib_t * q, float threshold)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
int ret = LIBLTE_SUCCESS;
|
||||
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;
|
||||
}
|
||||
/* Reset decoder if we missed a frame */
|
||||
if ((q->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) ||
|
||||
q->frame_cnt > 16)
|
||||
{
|
||||
INFO("Resetting PBCH decoder: last trial %u, now is %u\n",
|
||||
q->last_frame_trial, q->frame_cnt);
|
||||
if (q->frame_cnt > 16) {
|
||||
INFO("Resetting PBCH decoder after %d frames\n", q->frame_cnt);
|
||||
ue_mib_reset(q);
|
||||
}
|
||||
|
||||
|
@ -185,102 +143,90 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
|
|||
if (ret < 0) {
|
||||
fprintf(stderr, "Error decoding PBCH (%d)\n", ret);
|
||||
} 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);
|
||||
ret = MIB_FOUND;
|
||||
} else {
|
||||
INFO("MIB not decoded: %u\n", q->frame_cnt / 2);
|
||||
q->last_frame_trial = q->frame_cnt;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
INFO("MIB not decoded: %u\n", q->frame_cnt);
|
||||
q->frame_cnt++;
|
||||
ret = MIB_NOTFOUND;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_mib_get_payload(ue_mib_t *q,
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN],
|
||||
uint32_t *nof_tx_ports,
|
||||
uint32_t *sfn_offset)
|
||||
|
||||
|
||||
int ue_mib_sync_init(ue_mib_sync_t *q,
|
||||
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);
|
||||
if (nof_tx_ports) {
|
||||
*nof_tx_ports = q->nof_tx_ports;
|
||||
lte_cell_t cell;
|
||||
cell.nof_ports = MIB_MAX_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) {
|
||||
*sfn_offset = q->sfn_offset;
|
||||
if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
ue_mib_free(&q->ue_mib);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
ue_sync_decode_sss_on_track(&q->ue_sync, true);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int ue_mib_sync_and_decode_1_92(ue_mib_t * q,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples)
|
||||
void ue_mib_sync_free(ue_mib_sync_t *q) {
|
||||
ue_mib_free(&q->ue_mib);
|
||||
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;
|
||||
uint32_t peak_idx=0;
|
||||
uint32_t nof_input_frames;
|
||||
cf_t *sf_buffer = NULL;
|
||||
uint32_t nof_frames = 0;
|
||||
int mib_ret;
|
||||
|
||||
|
||||
if (q != NULL &&
|
||||
signal != NULL)
|
||||
if (q != NULL)
|
||||
{
|
||||
if (nsamples < MIB_FRAME_SIZE_SEARCH) {
|
||||
fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE_SEARCH);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = LIBLTE_SUCCESS;
|
||||
do {
|
||||
mib_ret = MIB_NOTFOUND;
|
||||
ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if we have space for reading the MIB and we are in Subframe #0 */
|
||||
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;
|
||||
}
|
||||
fprintf(stderr, "Error calling ue_sync_work()\n");
|
||||
break;
|
||||
} else if (ue_sync_get_sfidx(&q->ue_sync) == 0) {
|
||||
if (ret == 1) {
|
||||
mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset);
|
||||
} else {
|
||||
INFO("SSS not detected\n",0);
|
||||
ret = 0; // wait to detect it
|
||||
INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt);
|
||||
ue_mib_reset(&q->ue_mib);
|
||||
}
|
||||
} else {
|
||||
INFO("PSS not detected\n",0);
|
||||
ret = 0; // wait to detect it?
|
||||
nof_frames++;
|
||||
}
|
||||
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
|
||||
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_FRAME_SIZE 32
|
||||
|
||||
#define FIND_NOF_AVG_FRAMES 4
|
||||
|
||||
int ue_sync_init(ue_sync_t *q,
|
||||
lte_cell_t cell,
|
||||
|
@ -59,43 +51,85 @@ int ue_sync_init(ue_sync_t *q,
|
|||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
stream_handler != NULL &&
|
||||
lte_cell_isvalid(&cell) &&
|
||||
recv_callback != NULL)
|
||||
if (q != NULL &&
|
||||
stream_handler != NULL &&
|
||||
lte_nofprb_isvalid(cell.nof_prb) &&
|
||||
recv_callback != NULL)
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(ue_sync_t));
|
||||
|
||||
q->decode_sss_on_track = false;
|
||||
q->stream = stream_handler;
|
||||
q->recv_callback = recv_callback;
|
||||
q->cell = cell;
|
||||
|
||||
if(sync_init(&q->sfind, CURRENT_SFLEN, CURRENT_FFTSIZE)) {
|
||||
q->fft_size = lte_symbol_sz(q->cell.nof_prb);
|
||||
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");
|
||||
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");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
sync_set_N_id_2(&q->sfind, cell.id%3);
|
||||
sync_set_threshold(&q->sfind, FIND_THRESHOLD);
|
||||
q->sfind.cp = cell.cp;
|
||||
sync_cp_en(&q->sfind, false);
|
||||
sync_correct_cfo(&q->sfind, true);
|
||||
sync_set_em_alpha(&q->sfind, 1);
|
||||
if (cell.id == 1000) {
|
||||
/* If the cell id is unknown, enable CP detection on find */
|
||||
sync_cp_en(&q->sfind, true);
|
||||
sync_cp_en(&q->strack, true);
|
||||
|
||||
/* Correct CFO in all cases because both states are called always.
|
||||
*/
|
||||
sync_correct_cfo(&q->sfind, true);
|
||||
sync_correct_cfo(&q->strack, true);
|
||||
|
||||
sync_set_threshold(&q->sfind, 1.1);
|
||||
sync_set_em_alpha(&q->sfind, 0.01);
|
||||
q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES;
|
||||
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);
|
||||
|
||||
sync_set_N_id_2(&q->strack, cell.id%3);
|
||||
sync_set_threshold(&q->strack, TRACK_THRESHOLD);
|
||||
q->strack.cp = cell.cp;
|
||||
sync_cp_en(&q->strack, false);
|
||||
sync_correct_cfo(&q->strack, false);
|
||||
|
||||
q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t));
|
||||
/* 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) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
|
@ -114,7 +148,7 @@ clean_exit:
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -150,33 +184,45 @@ void ue_sync_decode_sss_on_track(ue_sync_t *q, bool 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) {
|
||||
|
||||
/* Receive the rest of the next subframe */
|
||||
if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+CURRENT_SFLEN/2) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
|
||||
if (sync_sss_detected(&q->sfind)) {
|
||||
/* 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 */
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_cnt = 0;
|
||||
q->frame_find_cnt = 0;
|
||||
|
||||
/* Goto Tracking state */
|
||||
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);
|
||||
q->state = SF_TRACK;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
} 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),
|
||||
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 */
|
||||
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_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 */
|
||||
q->frame_no_cnt++;
|
||||
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;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
/* copy last part of the last subframe (use move since there could be overlapping) */
|
||||
//memcpy(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t));
|
||||
|
||||
/* 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) {
|
||||
/* Get N subframes 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], q->frame_len - q->time_offset) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -251,6 +299,8 @@ static int receive_samples(ue_sync_t *q) {
|
|||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
bool first_track = true;
|
||||
|
||||
int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t track_idx;
|
||||
|
@ -275,25 +325,14 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
|||
|
||||
if (ret == 1) {
|
||||
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;
|
||||
case SF_TRACK:
|
||||
ret = 1;
|
||||
|
||||
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 */
|
||||
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 pss around the middle of the subframe, where the PSS is */
|
||||
ret = sync_find(&q->strack, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE-q->strack.frame_size/2, &track_idx);
|
||||
/* track PSS/SSS around the expected PSS position */
|
||||
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) {
|
||||
fprintf(stderr, "Error tracking correlation peak\n");
|
||||
return LIBLTE_ERROR;
|
||||
|
@ -329,11 +370,13 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
|||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
q->frame_total_cnt++;
|
||||
q->frame_total_cnt++;
|
||||
}
|
||||
|
||||
/* Do CFO Correction and deliver the frame */
|
||||
cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / CURRENT_FFTSIZE);
|
||||
/* Do CFO Correction if not done in track and deliver the frame */
|
||||
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;
|
||||
|
||||
break;
|
||||
|
@ -350,6 +393,7 @@ void ue_sync_reset(ue_sync_t *q) {
|
|||
q->frame_total_cnt = 0;
|
||||
q->mean_time_offset = 0.0;
|
||||
q->time_offset = 0;
|
||||
q->frame_find_cnt = 0;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
q->mean_exec_time = 0;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue