mirror of https://github.com/pvnis/srsRAN_4G.git
Merged with master
commit
53a6ccd06b
@ -0,0 +1,157 @@
|
||||
/**
|
||||
*
|
||||
* \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"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
|
||||
{
|
||||
ue_mib_t uemib;
|
||||
int n;
|
||||
|
||||
bzero(mib, sizeof(pbch_mib_t));
|
||||
|
||||
uint32_t nof_frames = 0;
|
||||
uint32_t flen = MIB_FRAME_SIZE;
|
||||
|
||||
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
|
||||
fprintf(stderr, "Error initiating PBCH decoder\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
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");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
|
||||
|
||||
n = ue_mib_decode(&uemib, buffer, flen, mib);
|
||||
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling ue_mib_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (n == MIB_FRAME_UNALIGNED) {
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
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);
|
||||
pbch_mib_fprint(stdout, mib, found_cell->cell_id);
|
||||
} else {
|
||||
printf("\nCould not decode MIB\n");
|
||||
}
|
||||
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
ue_mib_free(&uemib);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3])
|
||||
{
|
||||
int n;
|
||||
|
||||
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
|
||||
cuhd_set_rx_srate(uhd, 960000.0);
|
||||
INFO("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
uint32_t nof_scanned_cells = 0;
|
||||
uint32_t flen = 4800;
|
||||
int nof_detected_cells = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]);
|
||||
switch(n) {
|
||||
case CS_FRAME_UNALIGNED:
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
return LIBLTE_ERROR;
|
||||
case CS_CELL_DETECTED:
|
||||
nof_detected_cells++;
|
||||
if (found_cell[nof_scanned_cells].peak > 0) {
|
||||
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
|
||||
found_cell[nof_scanned_cells].cell_id,
|
||||
lte_cp_string(found_cell[nof_scanned_cells].cp),
|
||||
found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode,
|
||||
s->nof_frames_detected);
|
||||
}
|
||||
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case CS_CELL_NOT_DETECTED:
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case LIBLTE_ERROR:
|
||||
case LIBLTE_ERROR_INVALID_INPUTS:
|
||||
fprintf(stderr, "Error calling cellsearch_scan()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
} while(nof_scanned_cells < 3);
|
||||
|
||||
INFO("Stopping receiver...\n", 0);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
return nof_detected_cells;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
|
||||
int decode_pbch(void *uhd,
|
||||
cf_t *buffer,
|
||||
ue_celldetect_result_t *found_cell,
|
||||
uint32_t nof_frames_total,
|
||||
pbch_mib_t *mib);
|
||||
|
||||
int find_cell(void *uhd,
|
||||
ue_celldetect_t *s,
|
||||
cf_t *buffer,
|
||||
ue_celldetect_result_t found_cell[3]);
|
@ -0,0 +1,131 @@
|
||||
/**
|
||||
*
|
||||
* \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.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 300
|
||||
#define CS_DEFAULT_MAXFRAMES_DETECTED 30
|
||||
|
||||
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
|
||||
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
|
||||
|
||||
#define CS_FIND_THRESHOLD 0.6
|
||||
|
||||
#define CS_FRAME_UNALIGNED -3
|
||||
#define CS_CELL_DETECTED 2
|
||||
#define CS_CELL_NOT_DETECTED 1
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
uint32_t cell_id;
|
||||
lte_cp_t cp;
|
||||
float peak;
|
||||
uint32_t mode;
|
||||
} ue_celldetect_result_t;
|
||||
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t sfind;
|
||||
uint32_t max_frames_total;
|
||||
uint32_t max_frames_detected;
|
||||
uint32_t nof_frames_total;
|
||||
uint32_t nof_frames_detected;
|
||||
|
||||
uint32_t current_nof_detected;
|
||||
uint32_t current_nof_total;
|
||||
|
||||
uint32_t current_N_id_2;
|
||||
|
||||
uint32_t *mode_ntimes;
|
||||
char *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,
|
||||
uint32_t max_frames_detected);
|
||||
|
||||
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,
|
||||
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 int ue_celldetect_set_nof_frames_detected(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,109 @@
|
||||
/**
|
||||
*
|
||||
* \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_MIB_
|
||||
#define UE_MIB_
|
||||
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* This object decodes the MIB from the PBCH of an LTE signal.
|
||||
*
|
||||
* The function ue_mib_decode() shall be called multiple times,
|
||||
* each passing a number of samples multiple of 19200, sampled at 1.92 MHz
|
||||
* (that is, 10 ms of samples).
|
||||
*
|
||||
* The function uses the sync_t object to find the PSS sequence and
|
||||
* decode the PBCH to obtain the MIB.
|
||||
*
|
||||
* The function returns 0 until the MIB is decoded.
|
||||
*
|
||||
* See ue_cell_detect.c for an example.
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
#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.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
|
||||
#define MIB_FIND_THRESHOLD 0.6
|
||||
|
||||
#define MIB_NOF_PORTS 2
|
||||
|
||||
#define MIB_FRAME_SIZE 9600
|
||||
|
||||
#define MIB_FRAME_UNALIGNED -3
|
||||
#define MIB_FOUND 1
|
||||
#define MIB_NOTFOUND 0
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t sfind;
|
||||
|
||||
uint32_t cell_id;
|
||||
|
||||
cf_t *slot1_symbols;
|
||||
cf_t *ce[MIB_NOF_PORTS];
|
||||
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
pbch_t pbch;
|
||||
|
||||
uint32_t frame_cnt;
|
||||
uint32_t last_frame_trial;
|
||||
} ue_mib_t;
|
||||
|
||||
|
||||
LIBLTE_API int ue_mib_init(ue_mib_t *q,
|
||||
uint32_t cell_id,
|
||||
lte_cp_t cp);
|
||||
|
||||
LIBLTE_API void ue_mib_free(ue_mib_t *q);
|
||||
|
||||
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
|
||||
|
||||
LIBLTE_API int ue_mib_decode(ue_mib_t *q,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples,
|
||||
pbch_mib_t *mib);
|
||||
|
||||
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -1,629 +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/phch/ue_sync.h"
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#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, q->cell.cp)
|
||||
|
||||
#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 MAXIMUM_SFLEN SF_LEN(2048, CPNORM)
|
||||
#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM)
|
||||
|
||||
static int mib_decoder_initialize(ue_sync_t *q);
|
||||
static void mib_decoder_free(ue_sync_t *q);
|
||||
|
||||
|
||||
static void update_threshold(ue_sync_t *q) {
|
||||
int symbol_sz = lte_symbol_sz(q->cell.nof_prb);
|
||||
if (symbol_sz > 0) {
|
||||
switch (symbol_sz) {
|
||||
case 128:
|
||||
sync_set_threshold(&q->s, 10000, 1000);
|
||||
break;
|
||||
case 256:
|
||||
sync_set_threshold(&q->s, 20000, 2000);
|
||||
break;
|
||||
case 512:
|
||||
sync_set_threshold(&q->s, 30000, 3000);
|
||||
break;
|
||||
case 1024:
|
||||
sync_set_threshold(&q->s, 40000, 4000);
|
||||
break;
|
||||
case 2048:
|
||||
sync_set_threshold(&q->s, 50000, 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ue_sync_init(ue_sync_t *q,
|
||||
double (set_rate_callback)(void*, double),
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
stream_handler != NULL &&
|
||||
set_rate_callback != NULL &&
|
||||
recv_callback != NULL)
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(ue_sync_t));
|
||||
|
||||
ue_sync_reset(q);
|
||||
|
||||
q->cell.nof_prb = SYNC_PBCH_NOF_PRB;
|
||||
q->cell.nof_ports = SYNC_PBCH_NOF_PORTS;
|
||||
q->cell.id = 0;
|
||||
q->cell.cp = CPNORM;
|
||||
|
||||
q->pbch_decoded = false;
|
||||
q->pbch_initialized = false;
|
||||
q->pbch_decoder_enabled = true;
|
||||
q->pbch_decode_always = false;
|
||||
q->decode_sss_on_track = false;
|
||||
q->change_srate = true;
|
||||
q->nof_mib_decodes = DEFAULT_NOF_MIB_DECODES;
|
||||
q->stream = stream_handler;
|
||||
q->recv_callback = recv_callback;
|
||||
q->set_rate_callback = set_rate_callback;
|
||||
|
||||
INFO("Setting sampling frequency 1.92 MHz\n",0);
|
||||
q->set_rate_callback(q->stream, 1920000.0);
|
||||
|
||||
if (agc_init(&q->agc)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
sync_pss_det_absolute(&q->s);
|
||||
|
||||
if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t));
|
||||
if (!q->input_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->receive_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t));
|
||||
if (!q->receive_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t));
|
||||
if (!q->sf_symbols) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
for (int i=0;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
q->ce[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t));
|
||||
if (!q->ce[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
update_threshold(q);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
ue_sync_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_free(ue_sync_t *q) {
|
||||
if (q->input_buffer) {
|
||||
free(q->input_buffer);
|
||||
}
|
||||
if (q->receive_buffer) {
|
||||
free(q->receive_buffer);
|
||||
}
|
||||
if (q->sf_symbols) {
|
||||
free(q->sf_symbols);
|
||||
}
|
||||
for (int i=0;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
}
|
||||
mib_decoder_free(q);
|
||||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->s);
|
||||
agc_free(&q->agc);
|
||||
}
|
||||
|
||||
lte_cell_t ue_sync_get_cell(ue_sync_t *q) {
|
||||
return q->cell;
|
||||
}
|
||||
|
||||
pbch_mib_t ue_sync_get_mib(ue_sync_t *q) {
|
||||
return q->mib;
|
||||
}
|
||||
|
||||
uint32_t ue_sync_peak_idx(ue_sync_t *q) {
|
||||
return q->peak_idx;
|
||||
}
|
||||
|
||||
ue_sync_state_t ue_sync_get_state(ue_sync_t *q) {
|
||||
return q->state;
|
||||
}
|
||||
|
||||
void ue_sync_change_srate(ue_sync_t *q, bool enabled) {
|
||||
q->change_srate = enabled;
|
||||
}
|
||||
|
||||
static int update_srate(ue_sync_t *q) {
|
||||
struct timeval t[3];
|
||||
|
||||
gettimeofday(&t[1], NULL);
|
||||
if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
|
||||
fprintf(stderr, "Error realloc'ing SYNC\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
|
||||
if (q->nof_mib_decodes > 1) {
|
||||
mib_decoder_free(q);
|
||||
if (mib_decoder_initialize(q)) {
|
||||
fprintf(stderr, "Error reinitializing MIB decoder\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally set the new sampling rate
|
||||
q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb));
|
||||
|
||||
update_threshold(q);
|
||||
|
||||
ue_sync_reset(q);
|
||||
INFO("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Threshold=%.2f/%.2f Texec=%d us\n",
|
||||
(float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000,
|
||||
CURRENT_FFTSIZE, CURRENT_SFLEN, q->s.find_threshold, q->s.track_threshold, (int) t[0].tv_usec);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t ue_sync_get_sfidx(ue_sync_t *q) {
|
||||
return q->sf_idx;
|
||||
}
|
||||
|
||||
float ue_sync_get_cfo(ue_sync_t *q) {
|
||||
return 15000 * q->cur_cfo;
|
||||
}
|
||||
|
||||
float ue_sync_get_sfo(ue_sync_t *q) {
|
||||
return 1000*q->mean_time_offset/5;
|
||||
}
|
||||
|
||||
bool ue_sync_is_mib_decoded(ue_sync_t *q) {
|
||||
return q->pbch_decoded;
|
||||
}
|
||||
|
||||
void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) {
|
||||
q->pbch_decoder_enabled = enabled;
|
||||
}
|
||||
|
||||
void ue_sync_pbch_always(ue_sync_t *q, bool enabled) {
|
||||
q->pbch_decode_always = enabled;
|
||||
}
|
||||
|
||||
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
|
||||
q->decode_sss_on_track = enabled;
|
||||
}
|
||||
|
||||
void ue_sync_set_nof_pbch_decodes(ue_sync_t *q, uint32_t nof_pbch_decodes) {
|
||||
q->nof_mib_decodes = nof_pbch_decodes;
|
||||
}
|
||||
|
||||
static int mib_decoder_initialize(ue_sync_t *q) {
|
||||
|
||||
if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init_LTEDL(&q->chest, q->cell)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
return -1;
|
||||
}
|
||||
if (pbch_init(&q->pbch, q->cell)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
q->pbch_initialized = 1;
|
||||
DEBUG("PBCH initiated cell_id=%d\n", q->cell.id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mib_decoder_free(ue_sync_t *q) {
|
||||
chest_free(&q->chest);
|
||||
pbch_free(&q->pbch);
|
||||
lte_fft_free(&q->fft);
|
||||
}
|
||||
|
||||
static int mib_decoder_run(ue_sync_t *q) {
|
||||
int ret;
|
||||
|
||||
/* Run FFT for the second slot */
|
||||
lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols);
|
||||
|
||||
/* Get channel estimates of slot #1 for each port */
|
||||
chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0);
|
||||
|
||||
if (q->pbch_last_trial &&
|
||||
(q->frame_total_cnt - q->pbch_last_trial > 2))
|
||||
{
|
||||
pbch_decode_reset(&q->pbch);
|
||||
INFO("Resetting PBCH decoder: last trial %d, now is %d\n",
|
||||
q->pbch_last_trial, q->frame_total_cnt);
|
||||
q->pbch_last_trial = 0;
|
||||
}
|
||||
|
||||
if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) {
|
||||
q->frame_number = q->mib.sfn;
|
||||
q->cell.nof_ports = q->mib.nof_ports;
|
||||
|
||||
if (!q->pbch_decoded) {
|
||||
printf("\n\nMIB decoded:\n");
|
||||
pbch_mib_fprint(stdout, &q->mib, q->cell.id);
|
||||
|
||||
if (q->cell.nof_prb != q->mib.nof_prb) {
|
||||
q->cell.nof_prb = q->mib.nof_prb;
|
||||
if (q->change_srate) {
|
||||
ret = update_srate(q);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn);
|
||||
}
|
||||
q->pbch_decoded++;
|
||||
|
||||
pbch_decode_reset(&q->pbch);
|
||||
|
||||
} else {
|
||||
INFO("MIB not decoded: %d\n", q->frame_total_cnt/2);
|
||||
q->pbch_last_trial = q->frame_total_cnt;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_peak_ok(ue_sync_t *q) {
|
||||
int ret;
|
||||
|
||||
if (q->peak_idx < CURRENT_SFLEN) {
|
||||
/* Receive the rest of the next subframe */
|
||||
if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sync_sss_detected(&q->s)) {
|
||||
ret = sync_get_cell_id(&q->s);
|
||||
if (ret >= 0) {
|
||||
q->cell.id = (uint32_t) ret;
|
||||
q->cell.cp = sync_get_cp(&q->s);
|
||||
}
|
||||
|
||||
/* Get the subframe index (0 or 5) */
|
||||
q->sf_idx = sync_get_slot_id(&q->s)/2;
|
||||
|
||||
/* Reset variables */
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_cnt = 0;
|
||||
|
||||
/* Goto Tracking state */
|
||||
q->state = SF_TRACK;
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n",
|
||||
q->peak_idx, sync_get_peak_value(&q->s), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
|
||||
|
||||
if (q->peak_idx < CURRENT_SFLEN) {
|
||||
q->sf_idx++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
|
||||
int ret = LIBLTE_SUCCESS;
|
||||
|
||||
/* Make sure subframe idx is what we expect */
|
||||
if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) {
|
||||
INFO("\nWarning: Expected SF idx %d but got %d!\n",
|
||||
q->sf_idx, sync_get_slot_id(&q->s)/2);
|
||||
q->sf_idx = sync_get_slot_id(&q->s)/2;
|
||||
} else {
|
||||
q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE);
|
||||
|
||||
/* If the PSS peak is beyond the frame (we sample too slowly),
|
||||
discard the offseted samples to align next frame */
|
||||
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
|
||||
ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset);
|
||||
} else {
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
/* compute cumulative moving average CFO */
|
||||
q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), q->cur_cfo, q->frame_ok_cnt);
|
||||
|
||||
/* compute cumulative moving average time offset */
|
||||
q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt);
|
||||
|
||||
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
|
||||
q->frame_ok_cnt++;
|
||||
q->frame_no_cnt = 0;
|
||||
|
||||
|
||||
if (ret >= LIBLTE_SUCCESS) {
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
q->state = SF_FIND;
|
||||
} else {
|
||||
INFO("Tracking peak not found. Peak %.3f, %d lost\n", sync_get_peak_value(&q->s), (int) q->frame_no_cnt);
|
||||
}
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
static int receive_samples(ue_sync_t *q) {
|
||||
|
||||
if (q->cell.nof_prb >= 6 && q->cell.nof_prb <= 100) {
|
||||
/* A negative time offset means there are samples in our buffer for the next subframe,
|
||||
because we are sampling too fast.
|
||||
*/
|
||||
if (q->time_offset < 0) {
|
||||
q->time_offset = -q->time_offset;
|
||||
}
|
||||
/* copy last part of the last subframe (use move since there could be overlapping) */
|
||||
memcpy(q->receive_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->receive_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* reset time offset */
|
||||
q->time_offset = 0;
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
}
|
||||
|
||||
int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t track_idx;
|
||||
struct timeval t[3];
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
q->input_buffer != NULL)
|
||||
{
|
||||
|
||||
if (receive_samples(q)) {
|
||||
fprintf(stderr, "Error receiving samples\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
agc_process(&q->agc, q->receive_buffer, q->input_buffer, CURRENT_SFLEN);
|
||||
|
||||
switch (q->state) {
|
||||
case SF_AGC:
|
||||
q->frame_total_cnt++;
|
||||
if (q->frame_total_cnt >= AGC_NOF_FRAMES) {
|
||||
q->state = SF_FIND;
|
||||
q->frame_total_cnt = 0;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case SF_FIND:
|
||||
q->s.sss_en = true;
|
||||
|
||||
/* Find peak and cell id */
|
||||
ret = sync_find(&q->s, q->input_buffer, &q->peak_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("Find PAR=%.2f\n", sync_get_peak_value(&q->s));
|
||||
|
||||
if (ret == 1) {
|
||||
ret = find_peak_ok(q);
|
||||
/* Initialize PBCH decoder */
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
if (!q->pbch_initialized && q->pbch_decoder_enabled) {
|
||||
ret = mib_decoder_initialize(q);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error initializing MIB decoder\n");
|
||||
}
|
||||
}
|
||||
} else if (ret < 0) {
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error processing find peak \n");
|
||||
}
|
||||
}
|
||||
} 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->receive_buffer, rlen) < 0) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SF_TRACK:
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
q->s.sss_en = q->decode_sss_on_track;
|
||||
|
||||
q->sf_idx = (q->sf_idx + 1) % 10;
|
||||
|
||||
DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt);
|
||||
|
||||
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */
|
||||
if (q->sf_idx == 0 || q->sf_idx == 5) {
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[1], NULL);
|
||||
#endif
|
||||
|
||||
track_idx = 0;
|
||||
|
||||
/* track pss around the middle of the subframe, where the PSS is */
|
||||
ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error tracking correlation peak\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
|
||||
#endif
|
||||
|
||||
if (ret == 1) {
|
||||
ret = track_peak_ok(q, track_idx);
|
||||
} else {
|
||||
ret = track_peak_no(q);
|
||||
}
|
||||
|
||||
INFO("TRACK %3d: Value=%.3f SF=%d Track_idx=%d Offset=%d CFO: %f\n",
|
||||
(int) q->frame_total_cnt, sync_get_peak_value(&q->s), q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s));
|
||||
|
||||
q->frame_total_cnt++;
|
||||
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
fprintf(stderr, "Error processing tracking peak\n");
|
||||
q->state = SF_FIND;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do CFO Correction and deliver the frame */
|
||||
cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE);
|
||||
*sf_symbols = q->input_buffer;
|
||||
|
||||
/* At subframe 0, try to decode PBCH if not yet decoded */
|
||||
if (q->sf_idx == 0) {
|
||||
if(q->pbch_decoder_enabled &&
|
||||
(q->pbch_decoded < q->nof_mib_decodes || q->pbch_decode_always))
|
||||
{
|
||||
mib_decoder_run(q);
|
||||
} else {
|
||||
q->mib.sfn = (q->mib.sfn + 1) % 1024;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
if (q->pbch_decoder_enabled) {
|
||||
if (q->pbch_decoded >= q->nof_mib_decodes) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEBUG("UE SYNC returns %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_reset(ue_sync_t *q) {
|
||||
q->state = SF_AGC;
|
||||
|
||||
q->pbch_last_trial = 0;
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_cnt = 0;
|
||||
q->cur_cfo = 0;
|
||||
q->mean_time_offset = 0;
|
||||
q->time_offset = 0;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
q->mean_exec_time = 0;
|
||||
#endif
|
||||
|
||||
pbch_decode_reset(&q->pbch);
|
||||
}
|
||||
|
@ -0,0 +1,208 @@
|
||||
/**
|
||||
*
|
||||
* \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 <time.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
uint32_t N_id_2 = 100;
|
||||
char *uhd_args="";
|
||||
float uhd_gain=40.0, uhd_freq=-1.0;
|
||||
int nof_frames = -1;
|
||||
uint32_t fft_size=64;
|
||||
float threshold = 0.4;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agtvnp] -f rx_frequency_hz -i N_id_2\n", prog);
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD Gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-n nof_frames [Default %d]\n", nof_frames);
|
||||
printf("\t-s symbol_sz [Default %d]\n", fft_size);
|
||||
printf("\t-t threshold [Default %.2f]\n", threshold);
|
||||
printf("\t-v verbose\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agtvsfi")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'i':
|
||||
N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
fft_size = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (N_id_2 > 2 || uhd_freq < 0) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cf_t *buffer;
|
||||
int frame_cnt, n;
|
||||
void *uhd;
|
||||
pss_synch_t pss;
|
||||
int32_t flen;
|
||||
int peak_idx, last_peak;
|
||||
float peak_value;
|
||||
float mean_peak;
|
||||
uint32_t nof_det, nof_nodet, nof_nopeak, nof_nopeakdet;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
flen = 4800*(fft_size/64);
|
||||
|
||||
buffer = malloc(sizeof(cf_t) * flen);
|
||||
if (!buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pss_synch_init_fft(&pss, flen, fft_size)) {
|
||||
fprintf(stderr, "Error initiating PSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pss_synch_set_N_id_2(&pss, N_id_2)) {
|
||||
fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
printf("Set RX rate: %.2f MHz\n", cuhd_set_rx_srate(uhd, flen*2*100) / 1000000);
|
||||
printf("Set RX gain: %.1f dB\n", cuhd_set_rx_gain(uhd, uhd_gain));
|
||||
printf("Set RX freq: %.2f MHz\n", cuhd_set_rx_freq(uhd, uhd_freq) / 1000000);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
printf("Frame length %d samples\n", flen);
|
||||
printf("PSS detection threshold: %.2f\n", threshold);
|
||||
|
||||
nof_det = nof_nodet = nof_nopeak = nof_nopeakdet = 0;
|
||||
frame_cnt = 0;
|
||||
last_peak = 0;
|
||||
mean_peak = 0;
|
||||
while(frame_cnt < nof_frames || nof_frames == -1) {
|
||||
n = cuhd_recv(uhd, buffer, flen, 1);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error receiving samples\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
peak_idx = pss_synch_find_pss(&pss, buffer, &peak_value);
|
||||
if (peak_idx < 0) {
|
||||
fprintf(stderr, "Error finding PSS peak\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
float y = sqrtf(crealf(vec_dot_prod_conj_ccc(&buffer[peak_idx-fft_size],
|
||||
&buffer[peak_idx-fft_size],
|
||||
fft_size)) /
|
||||
fft_size);
|
||||
float x = peak_value/y;
|
||||
|
||||
mean_peak = EXPAVERAGE(x, mean_peak, frame_cnt);
|
||||
|
||||
if (x >= threshold) {
|
||||
nof_det++;
|
||||
} else {
|
||||
nof_nodet++;
|
||||
}
|
||||
|
||||
if (frame_cnt > 100) {
|
||||
if (abs(last_peak-peak_idx) > 10) {
|
||||
if (x >= threshold) {
|
||||
nof_nopeakdet++;
|
||||
} else {
|
||||
if (nof_nodet > 0) {
|
||||
nof_nodet--;
|
||||
}
|
||||
}
|
||||
nof_nopeak++;
|
||||
}
|
||||
}
|
||||
|
||||
frame_cnt++;
|
||||
|
||||
printf("[%5d]: Pos: %5d, En: %.4f Val: %.3f MeanVal: %.3f, Det: %.3f, No-Det: %.3f, NoPeak: %.3f, NoPeakDet: %.3f\r",
|
||||
frame_cnt,
|
||||
peak_idx, y, x, mean_peak,
|
||||
(float) nof_det/frame_cnt, (float) nof_nodet/frame_cnt,
|
||||
(float) nof_nopeak/frame_cnt, (float) nof_nopeakdet/nof_nopeak);
|
||||
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
last_peak = peak_idx;
|
||||
|
||||
}
|
||||
|
||||
pss_synch_free(&pss);
|
||||
free(buffer);
|
||||
cuhd_close(uhd);
|
||||
|
||||
printf("Ok\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -0,0 +1,268 @@
|
||||
/**
|
||||
*
|
||||
* \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 FIND_FFTSIZE 64
|
||||
#define FIND_SFLEN 5*SF_LEN(FIND_FFTSIZE)
|
||||
|
||||
int ue_celldetect_init(ue_celldetect_t * q) {
|
||||
return ue_celldetect_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, CS_DEFAULT_MAXFRAMES_DETECTED);
|
||||
}
|
||||
|
||||
int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total, uint32_t max_frames_detected) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(ue_celldetect_t));
|
||||
|
||||
q->candidates = malloc(sizeof(ue_celldetect_result_t) * max_frames_detected);
|
||||
if (!q->candidates) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
q->mode_ntimes = malloc(sizeof(uint32_t) * max_frames_detected);
|
||||
if (!q->mode_ntimes) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
q->mode_counted = malloc(sizeof(char) * max_frames_detected);
|
||||
if (!q->mode_counted) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
sync_set_threshold(&q->sfind, CS_FIND_THRESHOLD);
|
||||
sync_sss_en(&q->sfind, true);
|
||||
|
||||
q->max_frames_total = max_frames_total;
|
||||
q->max_frames_detected = max_frames_detected;
|
||||
q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL;
|
||||
q->nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void ue_celldetect_reset(ue_celldetect_t * q)
|
||||
{
|
||||
q->current_nof_detected = 0;
|
||||
q->current_nof_total = 0;
|
||||
q->current_N_id_2 = 0;
|
||||
}
|
||||
|
||||
void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold)
|
||||
{
|
||||
sync_set_threshold(&q->sfind, 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;
|
||||
}
|
||||
}
|
||||
|
||||
int ue_celldetect_set_nof_frames_detected(ue_celldetect_t * q, uint32_t nof_frames)
|
||||
{
|
||||
if (nof_frames <= q->max_frames_detected) {
|
||||
q->nof_frames_detected = nof_frames;
|
||||
return LIBLTE_SUCCESS;
|
||||
} else {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide the most likely cell based on the mode */
|
||||
void decide_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
bzero(q->mode_counted, q->nof_frames_detected);
|
||||
bzero(q->mode_ntimes, sizeof(uint32_t) * q->nof_frames_detected);
|
||||
|
||||
/* First find mode of CELL IDs */
|
||||
for (i = 0; i < q->nof_frames_detected; i++) {
|
||||
uint32_t cnt = 1;
|
||||
for (j=i+1;j<q->nof_frames_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->nof_frames_detected;i++) {
|
||||
if (q->mode_ntimes[i] > 0) {
|
||||
DEBUG("ntimes[%d]=%d (CID: %d)\n",i,q->mode_ntimes[i],q->candidates[i].cell_id);
|
||||
}
|
||||
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;
|
||||
found_cell->peak = 0;
|
||||
for (i=0;i<q->nof_frames_detected;i++) {
|
||||
if (q->candidates[i].cell_id == found_cell->cell_id) {
|
||||
if (CP_ISNORM(q->candidates[i].cp)) {
|
||||
nof_normal++;
|
||||
}
|
||||
found_cell->peak += q->candidates[i].peak/q->mode_ntimes[mode_pos];
|
||||
}
|
||||
}
|
||||
if (nof_normal > q->mode_ntimes[mode_pos]/2) {
|
||||
found_cell->cp = CPNORM;
|
||||
} else {
|
||||
found_cell->cp = CPEXT;
|
||||
}
|
||||
found_cell->mode = q->mode_ntimes[mode_pos];
|
||||
}
|
||||
|
||||
int ue_celldetect_scan(ue_celldetect_t * q,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples,
|
||||
ue_celldetect_result_t *found_cell)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t peak_idx;
|
||||
uint32_t nof_input_frames;
|
||||
|
||||
|
||||
if (q != NULL &&
|
||||
signal != NULL &&
|
||||
nsamples >= 4800)
|
||||
{
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
if (nsamples % 4800) {
|
||||
printf("Warning: nsamples must be a multiple of 4800. Some samples will be ignored\n");
|
||||
nsamples = (nsamples/4800) * 4800;
|
||||
}
|
||||
nof_input_frames = nsamples/4800;
|
||||
|
||||
for (uint32_t nf=0;nf<nof_input_frames;nf++) {
|
||||
sync_set_N_id_2(&q->sfind, q->current_N_id_2);
|
||||
|
||||
DEBUG("[%3d/%3d]: Searching cells with N_id_2=%d. %d frames\n",
|
||||
q->current_nof_detected, q->current_nof_total, q->current_N_id_2, nof_input_frames);
|
||||
|
||||
/* Find peak and cell id */
|
||||
ret = sync_find(&q->sfind, &signal[nf*4800], 0, &peak_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If peak position does not allow to read SSS, return error -3 */
|
||||
if (ret == LIBLTE_SUCCESS && peak_idx != 0) {
|
||||
return CS_FRAME_UNALIGNED;
|
||||
}
|
||||
|
||||
/* 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_last_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++;
|
||||
}
|
||||
}
|
||||
q->current_nof_total++;
|
||||
|
||||
/* Decide cell ID and CP if we detected up to nof_frames_detected */
|
||||
if (q->current_nof_detected == q->nof_frames_detected) {
|
||||
decide_cell(q, found_cell);
|
||||
q->current_N_id_2++;
|
||||
q->current_nof_detected = q->current_nof_total = 0;
|
||||
ret = CS_CELL_DETECTED;
|
||||
/* Or go to the next N_id_2 if we didn't detect the cell */
|
||||
} else if (q->current_nof_total == q->nof_frames_total) {
|
||||
q->current_N_id_2++;
|
||||
q->current_nof_detected = q->current_nof_total = 0;
|
||||
ret = CS_CELL_NOT_DETECTED;
|
||||
}
|
||||
if (q->current_N_id_2 == 3) {
|
||||
q->current_N_id_2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
/**
|
||||
*
|
||||
* \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_mib.h"
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#define FIND_FFTSIZE 128
|
||||
#define FIND_SFLEN 10*SF_LEN(FIND_FFTSIZE)
|
||||
|
||||
int ue_mib_init(ue_mib_t * q,
|
||||
uint32_t cell_id,
|
||||
lte_cp_t cp)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL) {
|
||||
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
lte_cell_t cell;
|
||||
cell.nof_ports = MIB_NOF_PORTS;
|
||||
cell.nof_prb = 6;
|
||||
cell.id = cell_id;
|
||||
cell.cp = cp;
|
||||
|
||||
q->cell_id = cell_id;
|
||||
|
||||
bzero(q, sizeof(ue_mib_t));
|
||||
|
||||
q->slot1_symbols = malloc(SLOT_LEN_RE(6, cp) * sizeof(cf_t));
|
||||
if (!q->slot1_symbols) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
for (int i=0;i<MIB_NOF_PORTS;i++) {
|
||||
q->ce[i] = malloc(SLOT_LEN_RE(6, cp) * sizeof(cf_t));
|
||||
if (!q->ce[i]) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
sync_set_threshold(&q->sfind, MIB_FIND_THRESHOLD);
|
||||
sync_sss_en(&q->sfind, true);
|
||||
sync_set_N_id_2(&q->sfind, cell_id % 3);
|
||||
|
||||
if (lte_fft_init(&q->fft, cp, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (chest_init_LTEDL(&q->chest, cell)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (pbch_init(&q->pbch, cell)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
ue_mib_reset(q);
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
ue_mib_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_mib_free(ue_mib_t * q)
|
||||
{
|
||||
if (q->slot1_symbols) {
|
||||
free(q->slot1_symbols);
|
||||
}
|
||||
for (int i=0;i<MIB_NOF_PORTS;i++) {
|
||||
if (q->ce[i]) {
|
||||
free(q->ce[i]);
|
||||
}
|
||||
}
|
||||
sync_free(&q->sfind);
|
||||
chest_free(&q->chest);
|
||||
pbch_free(&q->pbch);
|
||||
lte_fft_free(&q->fft);
|
||||
}
|
||||
|
||||
|
||||
void ue_mib_reset(ue_mib_t * q)
|
||||
{
|
||||
q->frame_cnt = 0;
|
||||
q->last_frame_trial = 0;
|
||||
|
||||
pbch_decode_reset(&q->pbch);
|
||||
}
|
||||
|
||||
void ue_mib_set_threshold(ue_mib_t * q, float threshold)
|
||||
{
|
||||
sync_set_threshold(&q->sfind, threshold);
|
||||
}
|
||||
|
||||
static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Run FFT for the slot symbols */
|
||||
lte_fft_run_slot(&q->fft, input, q->slot1_symbols);
|
||||
|
||||
/* Get channel estimates of slot #1 for each port */
|
||||
ret = chest_ce_slot(&q->chest, q->slot1_symbols, q->ce, 1);
|
||||
if (ret == LIBLTE_SUCCESS) {
|
||||
|
||||
/* Reset decoder if we missed a frame */
|
||||
if ((q->last_frame_trial && (q->frame_cnt - q->last_frame_trial > 2)) ||
|
||||
q->frame_cnt > 10)
|
||||
{
|
||||
ue_mib_reset(q);
|
||||
INFO("Resetting PBCH decoder: last trial %u, now is %u\n",
|
||||
q->last_frame_trial, q->frame_cnt);
|
||||
}
|
||||
|
||||
/* Decode PBCH */
|
||||
ret = pbch_decode(&q->pbch, q->slot1_symbols, q->ce, mib);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error decoding PBCH\n");
|
||||
} else if (ret == 1) {
|
||||
INFO("MIB decoded: %u\n", q->frame_cnt/2);
|
||||
ue_mib_reset(q);
|
||||
ret = 1;
|
||||
} else {
|
||||
INFO("MIB not decoded: %u\n", q->frame_cnt / 2);
|
||||
q->last_frame_trial = q->frame_cnt;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ue_mib_decode(ue_mib_t * q,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples,
|
||||
pbch_mib_t *mib)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t peak_idx;
|
||||
uint32_t nof_input_frames;
|
||||
|
||||
|
||||
if (q != NULL &&
|
||||
signal != NULL)
|
||||
{
|
||||
ret = LIBLTE_SUCCESS;
|
||||
|
||||
if (nsamples % MIB_FRAME_SIZE) {
|
||||
printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE);
|
||||
nsamples = (nsamples/MIB_FRAME_SIZE) * MIB_FRAME_SIZE;
|
||||
}
|
||||
nof_input_frames = nsamples/MIB_FRAME_SIZE;
|
||||
|
||||
for (uint32_t nf=0;nf<nof_input_frames;nf++) {
|
||||
|
||||
/* Find peak and cell id */
|
||||
ret = sync_find(&q->sfind, signal, nf*MIB_FRAME_SIZE, &peak_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If peak position does not allow to read SSS, return error -3 */
|
||||
if (ret == 1 &&
|
||||
nf*MIB_FRAME_SIZE + peak_idx + 960 <= nsamples &&
|
||||
sync_sss_detected(&q->sfind) &&
|
||||
sync_get_sf_idx(&q->sfind) == 0)
|
||||
{
|
||||
|
||||
ret = mib_decoder_run(q, &signal[nf*MIB_FRAME_SIZE+peak_idx], mib);
|
||||
|
||||
} else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) ||
|
||||
(ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 > nsamples))
|
||||
{
|
||||
ret = MIB_FRAME_UNALIGNED;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
q->frame_cnt++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,353 @@
|
||||
/**
|
||||
*
|
||||
* \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_sync.h"
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#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 1.0
|
||||
#define TRACK_THRESHOLD 0.2
|
||||
|
||||
|
||||
int ue_sync_init(ue_sync_t *q,
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler)
|
||||
{
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
||||
if (q != NULL &&
|
||||
stream_handler != NULL &&
|
||||
lte_cell_isvalid(&cell) &&
|
||||
recv_callback != NULL)
|
||||
{
|
||||
ret = LIBLTE_ERROR;
|
||||
|
||||
bzero(q, sizeof(ue_sync_t));
|
||||
|
||||
ue_sync_reset(q);
|
||||
|
||||
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)) {
|
||||
fprintf(stderr, "Error initiating sync find\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
|
||||
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_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);
|
||||
|
||||
if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t));
|
||||
if (!q->input_buffer) {
|
||||
perror("malloc");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
ue_sync_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_free(ue_sync_t *q) {
|
||||
if (q->input_buffer) {
|
||||
free(q->input_buffer);
|
||||
}
|
||||
cfo_free(&q->cfocorr);
|
||||
sync_free(&q->sfind);
|
||||
sync_free(&q->strack);
|
||||
}
|
||||
|
||||
uint32_t ue_sync_peak_idx(ue_sync_t *q) {
|
||||
return q->peak_idx;
|
||||
}
|
||||
|
||||
ue_sync_state_t ue_sync_get_state(ue_sync_t *q) {
|
||||
return q->state;
|
||||
}
|
||||
uint32_t ue_sync_get_sfidx(ue_sync_t *q) {
|
||||
return q->sf_idx;
|
||||
}
|
||||
|
||||
float ue_sync_get_cfo(ue_sync_t *q) {
|
||||
return 15000 * q->cur_cfo;
|
||||
}
|
||||
|
||||
float ue_sync_get_sfo(ue_sync_t *q) {
|
||||
return 1000*q->mean_time_offset/5;
|
||||
}
|
||||
|
||||
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
|
||||
q->decode_sss_on_track = enabled;
|
||||
}
|
||||
|
||||
|
||||
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) + 1;
|
||||
|
||||
/* Reset variables */
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_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_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
|
||||
|
||||
} else {
|
||||
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
|
||||
|
||||
/* Make sure subframe idx is what we expect */
|
||||
if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) {
|
||||
INFO("Warning: Expected SF idx %d but got %d!\n",
|
||||
q->sf_idx, sync_get_sf_idx(&q->strack));
|
||||
q->sf_idx = sync_get_sf_idx(&q->strack);
|
||||
q->state = SF_TRACK;
|
||||
} else {
|
||||
q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE);
|
||||
|
||||
/* If the PSS peak is beyond the frame (we sample too slowly),
|
||||
discard the offseted samples to align next frame */
|
||||
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
|
||||
if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute cumulative moving average CFO */
|
||||
q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt);
|
||||
|
||||
/* compute cumulative moving average time offset */
|
||||
q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt);
|
||||
|
||||
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
|
||||
q->frame_ok_cnt++;
|
||||
q->frame_no_cnt = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
q->state = SF_FIND;
|
||||
} else {
|
||||
INFO("Tracking peak not found. Peak %.3f, %d lost\n",
|
||||
sync_get_peak_value(&q->strack), (int) q->frame_no_cnt);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int receive_samples(ue_sync_t *q) {
|
||||
|
||||
/* A negative time offset means there are samples in our buffer for the next subframe,
|
||||
because we are sampling too fast.
|
||||
*/
|
||||
if (q->time_offset < 0) {
|
||||
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) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* reset time offset */
|
||||
q->time_offset = 0;
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
|
||||
int ret = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32_t track_idx;
|
||||
struct timeval t[3];
|
||||
|
||||
if (q != NULL &&
|
||||
sf_symbols != NULL &&
|
||||
q->input_buffer != NULL)
|
||||
{
|
||||
|
||||
if (receive_samples(q)) {
|
||||
fprintf(stderr, "Error receiving samples\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (q->state) {
|
||||
case SF_FIND:
|
||||
ret = sync_find(&q->sfind, q->input_buffer, 0, &q->peak_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SF_TRACK:
|
||||
ret = 1;
|
||||
|
||||
q->strack.sss_en = q->decode_sss_on_track;
|
||||
|
||||
q->sf_idx = (q->sf_idx + 1) % 10;
|
||||
|
||||
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */
|
||||
if (q->sf_idx == 0 || q->sf_idx == 5) {
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[1], NULL);
|
||||
#endif
|
||||
|
||||
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, &track_idx);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error tracking correlation peak\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
|
||||
#endif
|
||||
|
||||
if (ret == 1) {
|
||||
ret = track_peak_ok(q, track_idx);
|
||||
} else {
|
||||
ret = track_peak_no(q);
|
||||
}
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
fprintf(stderr, "Error processing tracking peak\n");
|
||||
q->state = SF_FIND;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
q->frame_total_cnt++;
|
||||
}
|
||||
|
||||
/* Do CFO Correction and deliver the frame */
|
||||
cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE);
|
||||
*sf_symbols = q->input_buffer;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ue_sync_reset(ue_sync_t *q) {
|
||||
q->state = SF_FIND;
|
||||
|
||||
q->frame_ok_cnt = 0;
|
||||
q->frame_no_cnt = 0;
|
||||
q->frame_total_cnt = 0;
|
||||
q->cur_cfo = 0;
|
||||
q->mean_time_offset = 0;
|
||||
q->time_offset = 0;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
q->mean_exec_time = 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright 2012-2013 The libLTE Developers. See the
|
||||
# COPYRIGHT file at the top-level directory of this distribution.
|
||||
#
|
||||
# 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/.
|
||||
#
|
||||
|
||||
########################################################################
|
||||
# UE SYNC TEST (Only compiled if CUHD is available)
|
||||
########################################################################
|
||||
LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND)
|
||||
LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
|
||||
|
||||
IF(${CUHD_FIND} GREATER -1)
|
||||
ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c)
|
||||
TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd)
|
||||
|
||||
ADD_EXECUTABLE(ue_celldetect_mib_test ue_celldetect_mib_test.c)
|
||||
TARGET_LINK_LIBRARIES(ue_celldetect_mib_test lte_phy cuhd)
|
||||
ENDIF(${CUHD_FIND} GREATER -1)
|
||||
|
||||
IF(${GRAPHICS_FIND} EQUAL -1)
|
||||
SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
|
||||
ELSE(${GRAPHICS_FIND} EQUAL -1)
|
||||
target_link_libraries(ue_sync_usrp graphics)
|
||||
ENDIF(${GRAPHICS_FIND} EQUAL -1)
|
||||
|
@ -0,0 +1,265 @@
|
||||
/**
|
||||
*
|
||||
* \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 <complex.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
int nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL;
|
||||
int nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED;
|
||||
float threshold = -1;
|
||||
|
||||
float uhd_freq = 0.0, uhd_gain = 20.0;
|
||||
char *uhd_args = "";
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agntdv] -f uhd_freq\n", prog);
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-n nof_frames_total [Default 100]\n");
|
||||
printf("\t-d nof_frames_detected [Default 10]\n");
|
||||
printf("\t-t threshold [Default %.2f]\n",threshold);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agndtvf")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
nof_frames_total = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
nof_frames_detected = atoi(argv[optind]);
|
||||
break;
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (uhd_freq == 0.0) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell)
|
||||
{
|
||||
ue_mib_t uemib;
|
||||
pbch_mib_t mib;
|
||||
int n;
|
||||
|
||||
uint32_t nof_frames = 0;
|
||||
uint32_t flen = MIB_FRAME_SIZE;
|
||||
|
||||
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
|
||||
fprintf(stderr, "Error initiating PBCH decoder\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
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");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
|
||||
|
||||
n = ue_mib_decode(&uemib, buffer, flen, &mib);
|
||||
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling ue_mib_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (n == MIB_FRAME_UNALIGNED) {
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
nof_frames++;
|
||||
} while (n != MIB_FOUND && nof_frames < nof_frames_total);
|
||||
if (n == MIB_FOUND) {
|
||||
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
|
||||
pbch_mib_fprint(stdout, &mib, found_cell->cell_id);
|
||||
} else {
|
||||
printf("\nCould not decode MIB\n");
|
||||
}
|
||||
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
ue_mib_free(&uemib);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t *found_cell)
|
||||
{
|
||||
int n;
|
||||
|
||||
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
|
||||
cuhd_set_rx_srate(uhd, 960000.0);
|
||||
INFO("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
uint32_t nof_scanned_cells = 0;
|
||||
uint32_t flen = 4800;
|
||||
|
||||
do {
|
||||
|
||||
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
n = ue_celldetect_scan(s, buffer, flen, found_cell);
|
||||
switch(n) {
|
||||
case CS_FRAME_UNALIGNED:
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
return LIBLTE_ERROR;
|
||||
case CS_CELL_DETECTED:
|
||||
if (found_cell->peak > 0) {
|
||||
printf("\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
|
||||
found_cell->cell_id, lte_cp_string(found_cell->cp),
|
||||
found_cell->peak, found_cell->mode, s->nof_frames_detected);
|
||||
}
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case CS_CELL_NOT_DETECTED:
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case LIBLTE_ERROR:
|
||||
case LIBLTE_ERROR_INVALID_INPUTS:
|
||||
fprintf(stderr, "Error calling cellsearch_scan()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
} while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED);
|
||||
|
||||
INFO("Stopping receiver...\n", 0);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int n;
|
||||
void *uhd;
|
||||
ue_celldetect_t s;
|
||||
ue_celldetect_result_t found_cell;
|
||||
cf_t *buffer;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
|
||||
/* set uhd_freq */
|
||||
cuhd_set_rx_freq(uhd, (double) uhd_freq);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000);
|
||||
|
||||
buffer = vec_malloc(sizeof(cf_t) * 96000);
|
||||
if (!buffer) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
if (ue_celldetect_init(&s)) {
|
||||
fprintf(stderr, "Error initiating UE sync module\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (threshold > 0) {
|
||||
ue_celldetect_set_threshold(&s, threshold);
|
||||
}
|
||||
|
||||
if (nof_frames_total > 0) {
|
||||
ue_celldetect_set_nof_frames_total(&s, nof_frames_total);
|
||||
}
|
||||
if (nof_frames_detected > 0) {
|
||||
ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected);
|
||||
}
|
||||
|
||||
n = find_cell(uhd, &s, buffer, &found_cell);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error searching cell\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (n == CS_CELL_DETECTED) {
|
||||
if (decode_pbch(uhd, buffer, &found_cell)) {
|
||||
fprintf(stderr, "Error decoding PBCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
ue_celldetect_free(&s);
|
||||
cuhd_close(uhd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
function [ y ] = addnoise( x, snr_db )
|
||||
v = 10^(-snr_db/10);
|
||||
y=x+sqrt(v)*(randn(size(x))+1i*randn(size(x)))/sqrt(2);
|
||||
y=y/sqrt(mean(y.*conj(y)));
|
||||
end
|
||||
|
@ -0,0 +1,13 @@
|
||||
function [peaks] = find_peaks(x, N_id_2, fft_size)
|
||||
|
||||
flen=4800*(ceil(fft_size/64));
|
||||
|
||||
n=floor(length(x)/flen)*flen;
|
||||
xf=reshape(x(1:n),flen,[]);
|
||||
|
||||
[n m] = size(xf);
|
||||
|
||||
peaks=zeros(m,1);
|
||||
for i=1:m
|
||||
[w, peaks(i)]= find_pss2(xf(:,i),N_id_2,fft_size);
|
||||
end
|
@ -1,18 +1,14 @@
|
||||
function [ fs eps p_m w2] = find_pss( x, N_id_2, fft_size)
|
||||
function [w2, m, idx] = find_pss2( x, N_id_2, fft_size)
|
||||
c=lte_pss_zc(N_id_2);
|
||||
cc=[zeros(fft_size/2-31,1); c; zeros(fft_size/2-31,1)];
|
||||
cc=[0; cc(fft_size/2+1:fft_size); cc(2:fft_size/2)];
|
||||
ccf=conj(ifft(cc));
|
||||
|
||||
w2=conv(x,ccf);
|
||||
%plot(10*log10(abs(w2)));%./mean(abs(w2))));
|
||||
plot(abs(w2))
|
||||
%axis([0 length(w2) 0 20])
|
||||
[m i]=max(abs(w2));
|
||||
p_m = m/mean(abs(w2));
|
||||
ccd=[0; cc(fft_size/2+1:fft_size); cc(2:fft_size/2)];
|
||||
ccf=sqrt(fft_size)*conj(ifft(ccd));
|
||||
|
||||
w2=abs(conv(x,ccf/62)).^2/var(x,1)/sqrt(2);
|
||||
plot(w2)
|
||||
[m, idx]=max(w2);
|
||||
|
||||
fprintf('Frame starts at %d, m=%g, p=%g, p/m=%g dB\n',i, ...
|
||||
mean(abs(w2)), m, 10*log10(m/mean(abs(w2))));
|
||||
|
||||
%fprintf('Frame starts at %d, energy=%g, p=%g, p/en=%g dB\n',i, ...
|
||||
% en, m, m/en);
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue