Added UE cell search object. Improved PSS detection

This commit is contained in:
ismagom 2014-08-01 23:26:28 +02:00
parent 7658ced99d
commit f4eeec3df7
45 changed files with 1899 additions and 1009 deletions

View File

@ -44,10 +44,14 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTI
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION)
SET(VOLK_DEFINITIONS "HAVE_VOLK")
IF(${HAVE_VOLK_MAX_ABS_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
ENDIF()

View File

@ -48,6 +48,8 @@ LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h,
LIBLTE_API int cuhd_stop_rx_stream(void *h);
LIBLTE_API void cuhd_flush_buffer(void *h);
LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h);
LIBLTE_API double cuhd_set_rx_srate(void *h,

View File

@ -95,6 +95,15 @@ int cuhd_stop_rx_stream(void *h)
return 0;
}
void cuhd_flush_buffer(void *h)
{
int n;
_Complex float tmp[1024];
do {
n = cuhd_recv(h, tmp, 1024, 0);
} while (n > 0);
}
int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);

View File

@ -32,6 +32,7 @@
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
@ -118,6 +119,7 @@ int main(int argc, char **argv) {
ue_sync_t uesync;
void *uhd;
cf_t *buffer;
lte_cell_t cell;
if (argc < 3) {
usage(argv[0]);
@ -148,13 +150,12 @@ int main(int argc, char **argv) {
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
if (ue_sync_init(&uesync, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) {
if (ue_sync_init(&uesync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating UE sync\n");
exit(-1);
}
ue_sync_set_nof_pbch_decodes(&uesync, 1);
ue_sync_decode_sss_on_track(&uesync, true);
ue_sync_change_srate(&uesync, false);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
@ -165,7 +166,6 @@ int main(int argc, char **argv) {
frame_cnt = 0;
ret = 0;
ue_sync_reset(&uesync);
agc_reset(&uesync.agc);
while(frame_cnt < nof_frames_find && ret == 0) {
ret = ue_sync_get_buffer(&uesync, &buffer);
@ -174,8 +174,8 @@ int main(int argc, char **argv) {
exit(-1);
}
frame_cnt++;
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS. RSSI: %+2.2f dB...\r", freq, nof_freqs,
channels[freq].id, channels[freq].fd, 20*log10f(agc_get_rssi(&uesync.agc)));fflush(stdout);
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS. \r", freq, nof_freqs,
channels[freq].id, channels[freq].fd);fflush(stdout);
if (VERBOSE_ISINFO()) {
printf("\n");
}
@ -185,8 +185,7 @@ int main(int argc, char **argv) {
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz FOUND MIB ", freq, nof_freqs,
channels[freq].id, channels[freq].fd);
}
printf("RSSI: %+.2f dBm, CFO: %+.4f KHz\n",
20*log10f(agc_get_rssi(&uesync.agc)), ue_sync_get_cfo(&uesync));
printf("CFO: %+.4f KHz\n", ue_sync_get_cfo(&uesync));
printf("\n");fflush(stdout);
}

View File

@ -33,7 +33,7 @@
#include "iodev.h"
#include "liblte/phy/io/filesource.h"
#include "liblte/phy/phch/ue_sync.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
@ -80,8 +80,9 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) {
DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(q->uhd);
ue_sync_init(&q->sframe, cuhd_set_rx_srate, cuhd_recv_wrapper, q->uhd);
lte_cell_t cell;
ue_sync_init(&q->sframe, cell, cuhd_recv_wrapper, q->uhd);
// Here, the subframe length and input buffer is managed by ue_sync
q->mode = UHD;

View File

@ -30,7 +30,7 @@
#include "liblte/config.h"
#include "liblte/phy/phch/ue_sync.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/io/filesource.h"
#ifndef DISABLE_UHD

View File

@ -257,7 +257,7 @@ int main(int argc, char **argv) {
N_id_2 = cell.id % 3;
sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb));
sf_n_samples = 2 * SLOT_LEN(lte_symbol_sz(cell.nof_prb));
/* this *must* be called after setting slot_len_* */
base_init();

View File

@ -171,7 +171,7 @@ int main(int argc, char **argv) {
symbol_sz = lte_symbol_sz(prog_args.nof_prb_file);
if (symbol_sz > 0) {
if (iodev_init(&iodev, &prog_args.io_config, SF_LEN(symbol_sz, CPNORM))) {
if (iodev_init(&iodev, &prog_args.io_config, SF_LEN(symbol_sz))) {
fprintf(stderr, "Error initiating input device\n");
exit(-1);
}
@ -197,9 +197,6 @@ int main(int argc, char **argv) {
/* Decodes the SSS signal during the tracking phase. Extra overhead, but makes sure we are in the correct subframe */
ue_sync_decode_sss_on_track(&iodev.sframe, true);
/* Decodes the PBCH on each frame. Around 10% more overhead, but makes sure we are in the current System Frame Number (SFN) */
ue_sync_pbch_always(&iodev.sframe, false);
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
@ -212,13 +209,13 @@ int main(int argc, char **argv) {
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, Output level: %+.2f dB FrameCnt: %d, State: %d\r",
sync_get_peak_value(&iodev.sframe.s), 20*log10f(agc_get_output_level(&iodev.sframe.agc)),
sync_get_peak_value(&iodev.sframe.sfind),
iodev.sframe.frame_total_cnt, iodev.sframe.state);
} else if (ret == 1) {
if (!ue_dl_initiated) {
if (iodev_isUSRP(&iodev)) {
cell = ue_sync_get_cell(&iodev.sframe);
mib = ue_sync_get_mib(&iodev.sframe);
//cell = ue_sync_get_cell(&iodev.sframe);
//mib = ue_sync_get_mib(&iodev.sframe);
} else {
cell.id = prog_args.cell_id_file;
cell.cp = CPNORM;
@ -237,7 +234,8 @@ int main(int argc, char **argv) {
if (iodev_isUSRP(&iodev)) {
sf_idx = ue_sync_get_sfidx(&iodev.sframe);
}
rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti);
//rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti);
rlen=-1;
if (rlen < 0) {
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
exit(-1);
@ -249,8 +247,7 @@ int main(int argc, char **argv) {
printed_sib = true;
}
if (!(sf_cnt % 10)) {
printf("RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e\r",
20*log10f(agc_get_rssi(&iodev.sframe.agc))+30,
printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e\r",
ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000,
pdsch_average_noi(&ue_dl.pdsch),
(int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total);

View File

@ -82,17 +82,12 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define CP_NORM(symbol, symbol_sz) (symbol==0)?CP(symbol_sz,CPNORM_0_LEN):CP(symbol_sz,CPNORM_LEN)
#define CP_EXT(symbol_sz) CP(symbol_sz,CPEXT_LEN)
#define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN)))
#define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz))
#define SLOT_LEN(symbol_sz) (480*((symbol_sz)/64))
#define SF_LEN(symbol_sz) (2*SLOT_LEN(symbol_sz))
#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX)
#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz))
#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz))
#define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp))
#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM)
#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp))
#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp))
#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp))
#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp))
#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN))))
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))

View File

@ -89,13 +89,13 @@ LIBLTE_API int pbch_init(pbch_t *q,
LIBLTE_API void pbch_free(pbch_t *q);
LIBLTE_API int pbch_decode(pbch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
cf_t *slot1_symbols,
cf_t *ce_slot1[MAX_PORTS],
pbch_mib_t *mib);
LIBLTE_API int pbch_encode(pbch_t *q,
pbch_mib_t *mib,
cf_t *sf_symbols[MAX_PORTS]);
cf_t *slot1_symbols[MAX_PORTS]);
LIBLTE_API void pbch_decode_reset(pbch_t *q);

View File

@ -92,8 +92,11 @@
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/phch/pcfich.h"
#include "liblte/phy/phch/phich.h"
#include "liblte/phy/phch/ue_sync.h"
#include "liblte/phy/phch/ue_dl.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/ue/ue_cellsearch.h"
#include "liblte/phy/ue/ue_dl.h"
#include "liblte/phy/scrambling/scrambling.h"

View File

@ -72,7 +72,6 @@ typedef struct LIBLTE_API {
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
cf_t *tmp_input;
float *conv_real;
cf_t *conv_output;
}pss_synch_t;

View File

@ -52,65 +52,59 @@
*/
typedef struct LIBLTE_API {
pss_synch_t pss_find;
pss_synch_t pss_track;
pss_synch_t pss;
sss_synch_t sss;
float find_threshold;
float track_threshold;
float threshold;
float mean_energy;
float peak_value;
float mean_peak_value;
uint32_t N_id_2;
uint32_t N_id_1;
uint32_t slot_id;
uint32_t sf_idx;
uint32_t fft_size;
uint32_t find_frame_size;
uint32_t frame_size;
uint64_t frame_cnt;
float cfo;
bool detect_cp;
bool sss_en;
bool normalize_en;
lte_cp_t cp;
}sync_t;
LIBLTE_API int sync_init(sync_t *q,
uint32_t find_frame_size,
uint32_t track_frame_size,
uint32_t frame_size,
uint32_t fft_size);
LIBLTE_API void sync_free(sync_t *q);
LIBLTE_API int sync_realloc(sync_t *q,
uint32_t find_frame_size,
uint32_t track_frame_size,
uint32_t fft_size);
LIBLTE_API void sync_reset(sync_t *q);
/* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be
subframe_size long at least */
/* Finds a correlation peak in the input signal around position find_offset */
LIBLTE_API int sync_find(sync_t *q,
cf_t *input,
uint32_t find_offset,
uint32_t *peak_position);
/* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be
TRACK_LEN long at least */
LIBLTE_API int sync_track(sync_t *q,
cf_t *input,
uint32_t offset,
uint32_t *peak_position);
/* Sets the threshold for peak comparison */
LIBLTE_API void sync_set_threshold(sync_t *q,
float find_threshold,
float track_threshold);
float threshold);
/* Gets the slot id (0 or 10) */
LIBLTE_API uint32_t sync_get_slot_id(sync_t *q);
/* Gets the subframe idx (0 or 5) */
LIBLTE_API uint32_t sync_get_sf_idx(sync_t *q);
/* Gets the last peak-to-average ratio */
/* Gets the last peak value */
LIBLTE_API float sync_get_last_peak_value(sync_t *q);
/* Gets the mean peak value */
LIBLTE_API float sync_get_peak_value(sync_t *q);
/* Gets the N_id_2 from the last call to synch_run() */
LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q);
/* Gets the last input signal energy estimation value */
LIBLTE_API float sync_get_input_energy(sync_t *q);
/* Gets the N_id_1 from the last call to synch_run() */
LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q);
/* Sets the N_id_2 to search for */
LIBLTE_API int sync_set_N_id_2(sync_t *q,
uint32_t N_id_2);
/* Gets the Physical CellId from the last call to synch_run() */
LIBLTE_API int sync_get_cell_id(sync_t *q);
@ -121,6 +115,10 @@ LIBLTE_API float sync_get_cfo(sync_t *q);
/* Gets the CP length estimation from the last call to synch_run() */
LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);
/* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled);

View File

@ -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_cellsearch_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_cellsearch_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_cellsearch_result_t *candidates;
} ue_cellsearch_t;
LIBLTE_API int ue_cellsearch_init(ue_cellsearch_t *q);
LIBLTE_API int ue_cellsearch_init_max(ue_cellsearch_t *q,
uint32_t max_frames_total,
uint32_t max_frames_detected);
LIBLTE_API void ue_cellsearch_free(ue_cellsearch_t *q);
LIBLTE_API void ue_cellsearch_reset(ue_cellsearch_t *q);
LIBLTE_API int ue_cellsearch_scan(ue_cellsearch_t *q,
cf_t *signal,
uint32_t nsamples,
ue_cellsearch_result_t *found_cell);
LIBLTE_API int ue_cellsearch_set_nof_frames_total(ue_cellsearch_t *q,
uint32_t nof_frames);
LIBLTE_API int ue_cellsearch_set_nof_frames_detected(ue_cellsearch_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_cellsearch_set_threshold(ue_cellsearch_t *q,
float threshold);
LIBLTE_API void ue_cellsearch_reset(ue_cellsearch_t *q);
#endif // SYNC_FRAME_

View File

@ -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_

View File

@ -36,57 +36,36 @@
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
#include "liblte/phy/agc/agc.h"
/**************************************************************
*
* This object automatically manages the cell association and
* synchronization procedure. By default, it associates with the
* CELL whose correlation peak to average ratio is the highest.
*
* TODO: Associate with arbitrary CELL ID
* This object automatically manages the cell synchronization procedure.
*
* The main function is ue_sync_get_buffer(), which returns a pointer
* to the aligned subframe of samples (before FFT). This function
* should be called regularly, returning every 1 ms. It reads from the
* USRP, aligns the samples to the subframe and performs time/freq synch.
*
* The function returns 0 during the cell association procedure, which includes
* PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency
* adjustment (according to signal bandwidth) and resynchronization.
*
* The function returns 1 when the signal is correctly acquired and the
* returned buffer is aligned with the subframe.
*
*
*************************************************************/
typedef enum LIBLTE_API { SF_AGC, SF_FIND, SF_TRACK} ue_sync_state_t;
#define SYNC_PBCH_NOF_PRB 6
#define SYNC_PBCH_NOF_PORTS 2
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
#define TRACK_MAX_LOST 10
#define DEFAULT_NOF_MIB_DECODES 10
#define AGC_NOF_FRAMES 100
#define MEASURE_EXEC_TIME
typedef struct LIBLTE_API {
sync_t s;
sync_t sfind;
sync_t strack;
void *stream;
double (*set_rate_callback)(void*, double);
int (*recv_callback)(void*, void*, uint32_t);
ue_sync_state_t state;
cf_t *input_buffer;
cf_t *receive_buffer;
cf_t *sf_symbols;
cf_t *ce[SYNC_PBCH_NOF_PORTS];
/* These count half frames (5ms) */
uint64_t frame_ok_cnt;
@ -101,21 +80,7 @@ typedef struct LIBLTE_API {
cfo_t cfocorr;
float cur_cfo;
/* Variables for PBCH decoding */
agc_t agc;
pbch_mib_t mib;
lte_fft_t fft;
chest_t chest;
pbch_t pbch;
bool pbch_initialized;
uint32_t pbch_decoded;
bool pbch_decode_always;
bool pbch_decoder_enabled;
uint32_t pbch_last_trial;
bool change_srate;
uint32_t nof_mib_decodes;
bool decode_sss_on_track;
uint32_t peak_idx;
@ -128,7 +93,7 @@ typedef struct LIBLTE_API {
LIBLTE_API int ue_sync_init(ue_sync_t *q,
double (set_rate_callback)(void*, double),
lte_cell_t cell,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
@ -137,34 +102,15 @@ LIBLTE_API void ue_sync_free(ue_sync_t *q);
LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q,
cf_t **sf_symbols);
LIBLTE_API void ue_sync_set_nof_pbch_decodes(ue_sync_t *q,
uint32_t nof_pbch_decodes);
LIBLTE_API void ue_sync_reset(ue_sync_t *q);
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q,
bool enabled);
LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q,
bool enabled);
LIBLTE_API void ue_sync_change_srate(ue_sync_t *q,
bool enabled);
LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q,
bool enabled);
LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q);
LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q);
LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q);
LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q);
LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q);
LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q);
LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q);

View File

@ -99,6 +99,7 @@ LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len);
/* return the index of the maximum value in the vector */
LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len);
LIBLTE_API uint32_t vec_max_abs_ci(cf_t *x, uint32_t len);
/* quantify vector of floats and convert to unsigned char */
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len);

View File

@ -145,7 +145,7 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32
if (q->refsignal[port_id][nslot].nsymbols <= 2) {
refsignal_t *r = &q->refsignal[port_id][nslot];
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) {
@ -276,6 +276,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_
{
ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell);
#ifdef VOLK_INTERP
if (ret == LIBLTE_SUCCESS) {
if (nslot == 0) {
ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2);
@ -285,6 +286,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_
}
}
}
#endif
}
return ret;
}
@ -318,6 +320,10 @@ void chest_free(chest_t *q) {
refsignal_free(&q->refsignal[p][n]);
}
}
#ifdef VOLK_INTERP
interp_free(&q->interp_freq);
interp_free(&q->interp_time);
#endif
bzero(q, sizeof(chest_t));
}

View File

@ -61,7 +61,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) {
q->cp = cp;
q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2);
q->slot_sz = SLOT_LEN(symbol_sz, cp);
q->slot_sz = SLOT_LEN(symbol_sz);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n",
dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,

View File

@ -87,7 +87,7 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb)));
outfft = malloc(sizeof(cf_t) * SLOT_LEN(lte_symbol_sz(n_prb)));
if (!outfft) {
perror("malloc");
exit(-1);

View File

@ -453,30 +453,25 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, ui
*
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
*/
int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) {
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], pbch_mib_t *mib) {
uint32_t src, dst, nb;
uint32_t nant_[3] = { 1, 2, 4 };
uint32_t na, nant;
cf_t *slot1_symbols;
int i;
int nof_bits;
cf_t *x[MAX_LAYERS];
cf_t *ce_slot[MAX_PORTS];
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
sf_symbols != NULL &&
slot1_symbols != NULL &&
mib != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (ce[i] == NULL) {
if (ce_slot1[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
} else {
ce_slot[i] = &ce[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
}
}
}
slot1_symbols = &sf_symbols[q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
/* Set pointers for layermapping & precoding */
nof_bits = 2 * q->nof_symbols;
@ -495,7 +490,7 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) {
if (q->nof_symbols != pbch_get(ce_slot1[i], q->ce[i], q->cell)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return LIBLTE_ERROR;
}
@ -508,7 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi
for (na = 0; na < q->cell.nof_ports && !ret; na++) {
nant = nant_[na];
INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx);
/* in conctrol channels, only diversity is supported */
if (nant == 1) {
@ -554,21 +549,18 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) {
int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS]) {
int i;
int nof_bits;
cf_t *slot1_symbols[MAX_PORTS];
cf_t *x[MAX_LAYERS];
if (q != NULL &&
mib != NULL)
{
for (i=0;i<q->cell.nof_ports;i++) {
if (sf_symbols[i] == NULL) {
if (slot1_symbols[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
} else {
slot1_symbols[i] = &sf_symbols[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)];
}
}
}
/* Set pointers for layermapping & precoding */
nof_bits = 2 * q->nof_symbols;

View File

@ -1,627 +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;
}
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);
}

View File

@ -19,23 +19,6 @@
# 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)
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)
########################################################################
# PBCH TEST
########################################################################

View File

@ -117,14 +117,14 @@ int base_init() {
exit(-1);
}
fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t));
fft_buffer = malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<cell.nof_ports;i++) {
ce[i] = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t));
ce[i] = malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
@ -194,7 +194,7 @@ int main(int argc, char **argv) {
n = filesource_read(&fsrc, input_buffer, FLEN);
lte_fft_run_sf(&fft, input_buffer, fft_buffer);
lte_fft_run_slot(&fft, &input_buffer[960], fft_buffer);
if (fmatlab) {
fprintf(fmatlab, "outfft=");
@ -205,7 +205,7 @@ int main(int argc, char **argv) {
}
/* Get channel estimates for each port */
chest_ce_sf(&chest, fft_buffer, ce, 0);
chest_ce_slot(&chest, fft_buffer, ce, 1);
INFO("Decoding PBCH\n", 0);

View File

@ -78,11 +78,11 @@ int main(int argc, char **argv) {
int i, j;
cf_t *ce[MAX_PORTS];
int nof_re;
cf_t *sf_symbols[MAX_PORTS];
cf_t *slot1_symbols[MAX_PORTS];
parse_args(argc,argv);
nof_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
nof_re = SLOT_LEN_RE(cell.nof_prb, CPNORM);
/* init memory */
for (i=0;i<cell.nof_ports;i++) {
@ -94,8 +94,8 @@ int main(int argc, char **argv) {
for (j=0;j<nof_re;j++) {
ce[i][j] = 1;
}
sf_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!sf_symbols[i]) {
slot1_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot1_symbols[i]) {
perror("malloc");
exit(-1);
}
@ -112,17 +112,17 @@ int main(int argc, char **argv) {
mib_tx.phich_resources = R_1_6;
mib_tx.sfn = 124;
pbch_encode(&pbch, &mib_tx, sf_symbols);
pbch_encode(&pbch, &mib_tx, slot1_symbols);
/* combine outputs */
for (i=1;i<cell.nof_ports;i++) {
for (j=0;j<nof_re;j++) {
sf_symbols[0][j] += sf_symbols[i][j];
slot1_symbols[0][j] += slot1_symbols[i][j];
}
}
pbch_decode_reset(&pbch);
if (1 != pbch_decode(&pbch, sf_symbols[0], ce, &mib_rx)) {
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, &mib_rx)) {
printf("Error decoding\n");
exit(-1);
}
@ -131,7 +131,7 @@ int main(int argc, char **argv) {
for (i=0;i<cell.nof_ports;i++) {
free(ce[i]);
free(sf_symbols[i]);
free(slot1_symbols[i]);
}
if (!memcmp(&mib_tx, &mib_rx, sizeof(pbch_mib_t))) {

View File

@ -119,7 +119,7 @@ int base_init() {
fmatlab = NULL;
}
flen = SLOT_LEN(lte_symbol_sz(cell.nof_prb), cell.cp);
flen = SLOT_LEN(lte_symbol_sz(cell.nof_prb));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {

View File

@ -133,7 +133,7 @@ int base_init() {
fmatlab = NULL;
}
flen = 2 * (SLOT_LEN(lte_symbol_sz(cell.nof_prb), cell.cp));
flen = 2 * (SLOT_LEN(lte_symbol_sz(cell.nof_prb)));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {

View File

@ -136,7 +136,7 @@ int base_init() {
fmatlab = NULL;
}
flen = 2 * (SLOT_LEN(lte_symbol_sz(cell.nof_prb), cell.cp));
flen = 2 * (SLOT_LEN(lte_symbol_sz(cell.nof_prb)));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {

View File

@ -144,7 +144,7 @@ int base_init() {
fmatlab = NULL;
}
flen = SLOT_LEN(lte_symbol_sz(cell.nof_prb), cell.cp);
flen = SLOT_LEN(lte_symbol_sz(cell.nof_prb));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {

View File

@ -65,7 +65,8 @@ int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_s
dft_run_c(&plan, pss_signal_pad, pss_signal_freq);
vec_conj_cc(pss_signal_freq, pss_signal_freq, fft_size);
vec_sc_prod_cfc(pss_signal_freq, 1.0/62.0, pss_signal_freq, fft_size);
dft_plan_free(&plan);
ret = LIBLTE_SUCCESS;
@ -98,11 +99,6 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) {
buffer_size = fft_size + frame_size + 1;
q->conv_real = vec_malloc(buffer_size * sizeof(float));
if (!q->conv_real) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->tmp_input) {
fprintf(stderr, "Error allocating memory\n");
@ -161,9 +157,6 @@ void pss_synch_free(pss_synch_t *q) {
if (q->conv_output) {
free(q->conv_output);
}
if (q->conv_real) {
free(q->conv_real);
}
bzero(q, sizeof(pss_synch_t));
}
@ -260,16 +253,11 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size);
#endif
/* Take the real part of the convolution result and normalize */
vec_deinterleave_real_cf(q->conv_output, q->conv_real, conv_output_len);
vec_sc_prod_fff(q->conv_real, 1.0/62.0, q->conv_real, conv_output_len);
/* Find maximum */
corr_peak_pos = vec_max_fi(q->conv_real, conv_output_len);
/* Find maximum of the absolute value of the correlation */
corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len);
if (corr_peak_value) {
*corr_peak_value = q->conv_real[corr_peak_pos];
*corr_peak_value = cabsf(q->conv_output[corr_peak_pos]);
}
DEBUG("PSS correlation peak %.3f position %5d\n", q->conv_real[corr_peak_pos], corr_peak_pos);
ret = (int) corr_peak_pos;
}
return ret;

View File

@ -26,6 +26,8 @@
*/
#include <strings.h>
#include <complex.h>
#include <math.h>
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/common/phy_common.h"
@ -41,24 +43,25 @@ static bool fft_size_isvalid(uint32_t fft_size) {
}
}
int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, uint32_t fft_size) {
int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
find_frame_size > fft_size &&
find_frame_size < 307200 &&
frame_size >= fft_size &&
frame_size <= 307200 &&
fft_size_isvalid(fft_size))
{
bzero(q, sizeof(sync_t));
q->detect_cp = true;
q->normalize_en = true;
q->sss_en = true;
q->N_id_2 = 1000;
q->N_id_1 = 1000;
q->fft_size = fft_size;
q->find_frame_size = find_frame_size;
q->frame_size = frame_size;
if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) {
if (pss_synch_init_fft(&q->pss, frame_size, fft_size)) {
fprintf(stderr, "Error initializing PSS object\n");
return LIBLTE_ERROR;
}
@ -66,112 +69,72 @@ int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, ui
fprintf(stderr, "Error initializing SSS object\n");
return LIBLTE_ERROR;
}
if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) {
fprintf(stderr, "Error initializing PSS track object\n");
return LIBLTE_ERROR;
}
DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size);
DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size);
ret = LIBLTE_SUCCESS;
}
return ret;
}
int sync_realloc(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size,
uint32_t fft_size)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
find_frame_size > fft_size &&
find_frame_size < 307200 &&
fft_size_isvalid(fft_size))
{
q->N_id_2 = 1000;
q->N_id_1 = 1000;
q->fft_size = fft_size;
q->find_frame_size = find_frame_size;
pss_synch_free(&q->pss_find);
if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) {
fprintf(stderr, "Error initializing PSS object\n");
return LIBLTE_ERROR;
}
pss_synch_free(&q->pss_track);
if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) {
fprintf(stderr, "Error initializing PSS track object\n");
return LIBLTE_ERROR;
}
if (sss_synch_realloc(&q->sss, fft_size)) {
fprintf(stderr, "Error realloc'ing SSS object\n");
return LIBLTE_ERROR;
}
DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size);
ret = LIBLTE_SUCCESS;
}
return ret;
}
void sync_free(sync_t *q) {
if (q) {
pss_synch_free(&q->pss_track);
pss_synch_free(&q->pss_find);
pss_synch_free(&q->pss);
sss_synch_free(&q->sss);
}
}
void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) {
q->find_threshold = find_threshold;
q->track_threshold = track_threshold;
void sync_set_threshold(sync_t *q, float threshold) {
q->threshold = threshold;
}
void sync_sss_en(sync_t *q, bool enabled) {
q->sss_en = enabled;
}
void sync_normalize_en(sync_t *q, bool enable) {
q->normalize_en = enable;
}
bool sync_sss_detected(sync_t *q) {
return lte_N_id_1_isvalid(q->N_id_1);
}
int sync_get_cell_id(sync_t *q) {
if (q->N_id_2 != 10) {
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;
}
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, N_id_2 not set\n");
fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n");
return LIBLTE_ERROR;
}
}
uint32_t sync_get_N_id_1(sync_t *q) {
return q->N_id_1;
int sync_set_N_id_2(sync_t *q, uint32_t N_id_2) {
if (lte_N_id_2_isvalid(N_id_2)) {
q->N_id_2 = N_id_2;
return LIBLTE_SUCCESS;
} else {
fprintf(stderr, "Invalid N_id_2=%d\n", N_id_2);
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
uint32_t sync_get_N_id_2(sync_t *q) {
return q->N_id_2;
}
uint32_t sync_get_slot_id(sync_t *q) {
return q->slot_id;
uint32_t sync_get_sf_idx(sync_t *q) {
return q->sf_idx;
}
float sync_get_cfo(sync_t *q) {
return q->cfo;
}
float sync_get_peak_value(sync_t *q) {
float sync_get_last_peak_value(sync_t *q) {
return q->peak_value;
}
float sync_get_peak_value(sync_t *q) {
return q->mean_peak_value;
}
void sync_cp_en(sync_t *q, bool enabled) {
q->detect_cp = enabled;
}
@ -180,11 +143,11 @@ lte_cp_t sync_get_cp(sync_t *q) {
return q->cp;
}
int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) {
int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
uint32_t m0, m1;
int sss_idx_n, sss_idx_e, ret;
float m0_value_e, m1_value_e,m0_value_n, m1_value_n;
uint32_t slot_id_e, N_id_1_e, slot_id_n, N_id_1_n;
uint32_t sf_idx_e, N_id_1_e, sf_idx_n, N_id_1_n;
sss_synch_set_N_id_2(&q->sss, q->N_id_2);
@ -192,7 +155,7 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) {
sss_idx_n = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPNORM_LEN));
sss_idx_e = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPEXT_LEN));
if (en_cp) {
if (q->detect_cp) {
if (sss_idx_n < 0 || sss_idx_e < 0) {
INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e);
return LIBLTE_SUCCESS;
@ -211,16 +174,16 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) {
}
}
slot_id_n = 0;
slot_id_e = 0;
sf_idx_n = 0;
sf_idx_e = 0;
N_id_1_n = 0;
N_id_1_e = 0;
/* try Normal CP length */
if (en_cp || CP_ISNORM(q->cp)) {
if (q->detect_cp || CP_ISNORM(q->cp)) {
sss_synch_m0m1(&q->sss, &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n);
slot_id_n = 2 * sss_synch_subframe(m0, m1);
sf_idx_n = sss_synch_subframe(m0, m1);
ret = sss_synch_N_id_1(&q->sss, m0, m1);
if (ret >= 0) {
N_id_1_n = (uint32_t) ret;
@ -229,11 +192,11 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) {
}
}
if (en_cp || CP_ISEXT(q->cp)) {
if (q->detect_cp || CP_ISEXT(q->cp)) {
/* Now try Extended CP length */
sss_synch_m0m1(&q->sss, &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e);
slot_id_e = 2 * sss_synch_subframe(m0, m1);
sf_idx_e = sss_synch_subframe(m0, m1);
ret = sss_synch_N_id_1(&q->sss, m0, m1);
if (ret >= 0) {
N_id_1_e = (uint32_t) ret;
@ -243,46 +206,71 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) {
}
/* Correlation with extended CP hypoteshis is greater than with normal? */
if ((en_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n)
if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n)
|| CP_ISEXT(q->cp)) {
q->cp = CPEXT;
q->slot_id = slot_id_e;
q->sf_idx = sf_idx_e;
q->N_id_1 = N_id_1_e;
/* otherwise is normal CP */
} else {
q->cp = CPNORM;
q->slot_id = slot_id_n;
q->sf_idx = sf_idx_n;
q->N_id_1 = N_id_1_n;
}
DEBUG("SSS detected N_id_1=%d, slot_idx=%d, position=%d/%d %s CP\n",
q->N_id_1, q->slot_id, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended");
DEBUG("SSS detected N_id_1=%d, sf_idx=%d, position=%d/%d %s CP\n",
q->N_id_1, q->sf_idx, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended");
return 1;
}
int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) {
int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
float peak_unnormalized, energy;
if (q != NULL &&
input != NULL &&
lte_N_id_2_isvalid(q->N_id_2) &&
fft_size_isvalid(q->fft_size))
{
uint32_t peak_pos;
pss_synch_set_N_id_2(&q->pss_track, q->N_id_2);
peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &q->peak_value);
DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n",
peak_pos, q->peak_value, q->track_threshold);
if (q->peak_value > q->track_threshold) {
if (offset + peak_pos > q->fft_size) {
q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]);
if (peak_position) {
*peak_position = 0;
}
pss_synch_set_N_id_2(&q->pss, q->N_id_2);
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized);
if (q->normalize_en &&
peak_pos + find_offset >= q->fft_size &&
peak_pos + find_offset + q->fft_size <= q->frame_size)
{
/* Compute the energy of the received PSS sequence to normalize */
cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size];
energy = sqrtf(crealf(vec_dot_prod_conj_ccc(pss_ptr, pss_ptr, q->fft_size)) / (q->fft_size));
q->mean_energy = EXPAVERAGE(energy, q->mean_energy, q->frame_cnt);
} else {
if (q->mean_energy == 0.0) {
q->mean_energy = 1.0;
}
energy = q->mean_energy;
}
/* Normalize and compute mean peak value */
q->peak_value = peak_unnormalized/energy;
q->mean_peak_value = EXPAVERAGE(q->peak_value, q->mean_peak_value, q->frame_cnt);
q->frame_cnt++;
/* If peak is over threshold, compute CFO and SSS */
if (q->peak_value >= q->threshold) {
if (find_offset + peak_pos >= q->fft_size) {
q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
if (q->sss_en) {
if (sync_sss(q, input, offset + peak_pos, false) < 0) {
if (sync_sss(q, input, find_offset + peak_pos) < 0) {
fprintf(stderr, "Error synchronizing with SSS\n");
return LIBLTE_ERROR;
}
@ -290,6 +278,7 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position)
} else {
printf("Warning: no space for CFO computation\n");
}
if (peak_position) {
*peak_position = peak_pos;
}
@ -297,67 +286,17 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position)
} else {
ret = LIBLTE_SUCCESS;
}
INFO("SYNC ret=%d pos=%d peak=%.2f energy=%.3f threshold=%.2f sf_idx=%d\n",
ret, peak_pos, q->peak_value, energy, q->threshold, q->sf_idx);
} else if (lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Must call sync_set_N_id_2() first!\n");
}
return ret;
}
int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) {
uint32_t N_id_2, peak_pos[3];
float peak_value[3];
float max=-999;
uint32_t i;
int ret;
for (N_id_2=0;N_id_2<3;N_id_2++) {
pss_synch_set_N_id_2(&q->pss_find, N_id_2);
ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2]);
if (ret < 0) {
fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2);
return LIBLTE_ERROR;
}
peak_pos[N_id_2] = (uint32_t) ret;
}
for (i=0;i<3;i++) {
if (peak_value[i] > max) {
max = peak_value[i];
N_id_2 = i;
}
}
q->peak_value = peak_value[N_id_2];
if (peak_position) {
*peak_position = 0;
}
/* If peak detected */
if (q->peak_value > q->find_threshold) {
if (peak_pos[N_id_2] > q->fft_size &&
peak_pos[N_id_2] + q->fft_size < q->find_frame_size)
{
q->N_id_2 = N_id_2;
pss_synch_set_N_id_2(&q->pss_find, q->N_id_2);
q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]);
DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f th=%.2f cfo=%.4f\n", N_id_2,
peak_pos[N_id_2], q->peak_value, q->find_threshold, q->cfo);
if (q->sss_en) {
if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) {
fprintf(stderr, "Error synchronizing with SSS\n");
return LIBLTE_ERROR;
}
}
}
if (peak_position) {
*peak_position = peak_pos[N_id_2];
}
return 1;
} else {
return LIBLTE_SUCCESS;
}
void sync_reset(sync_t *q) {
q->frame_cnt = 0;
}

View File

@ -19,6 +19,15 @@
# and at http://www.gnu.org/licenses/.
#
########################################################################
# PROGRAM TO DEBUG PSS FROM USRP
########################################################################
LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND)
IF(${CUHD_FIND} GREATER -1)
ADD_EXECUTABLE(pss_usrp pss_usrp.c)
TARGET_LINK_LIBRARIES(pss_usrp lte_phy cuhd)
ENDIF(${CUHD_FIND} GREATER -1)
########################################################################
# SYNC TEST
@ -27,15 +36,15 @@
ADD_EXECUTABLE(sync_test sync_test.c)
TARGET_LINK_LIBRARIES(sync_test lte_phy)
ADD_TEST(sync_test_100 sync_test -o 100)
ADD_TEST(sync_test_400 sync_test -o 400)
ADD_TEST(sync_test_100_e sync_test -o 100 -e)
ADD_TEST(sync_test_400_e sync_test -o 400 -e)
ADD_TEST(sync_test_100 sync_test -o 100 -c 501)
ADD_TEST(sync_test_400 sync_test -o 400 -c 2)
ADD_TEST(sync_test_100_e sync_test -o 100 -e -c 150)
ADD_TEST(sync_test_400_e sync_test -o 400 -e -c 151)
ADD_TEST(sync_test_100 sync_test -o 100 -p 50)
ADD_TEST(sync_test_400 sync_test -o 400 -p 50)
ADD_TEST(sync_test_100_e sync_test -o 100 -e -p 50)
ADD_TEST(sync_test_400_e sync_test -o 400 -e -p 50)
ADD_TEST(sync_test_100 sync_test -o 100 -p 50 -c 501)
ADD_TEST(sync_test_400 sync_test -o 400 -p 50 -c 500)
ADD_TEST(sync_test_100_e sync_test -o 100 -e -p 50 -c 133)
ADD_TEST(sync_test_400_e sync_test -o 400 -e -p 50 -c 123)
########################################################################
# CFO TEST

View File

@ -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);
}

View File

@ -41,7 +41,7 @@ int cell_id = -1, offset = 0;
lte_cp_t cp = CPNORM;
uint32_t nof_prb=6;
#define FLEN SF_LEN(fft_size, cp)
#define FLEN SF_LEN(fft_size)
void usage(char *prog) {
printf("Usage: %s [cpoev]\n", prog);
@ -115,13 +115,13 @@ int main(int argc, char **argv) {
exit(-1);
}
if (sync_init(&sync, FLEN, fft_size, fft_size)) {
if (sync_init(&sync, FLEN, fft_size)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
/* Set a very high threshold to make sure the correlation is ok */
sync_set_threshold(&sync, 0.99, 0.99);
sync_set_threshold(&sync, 1.4);
if (cell_id == -1) {
cid = 0;
@ -137,6 +137,8 @@ int main(int argc, char **argv) {
pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cid);
sync_set_N_id_2(&sync, N_id_2);
for (ns=0;ns<2;ns++) {
memset(buffer, 0, sizeof(cf_t) * FLEN);
pss_put_slot(pss_signal, buffer, nof_prb, cp);
@ -148,8 +150,11 @@ int main(int argc, char **argv) {
vec_save_file("input", fft_buffer, sizeof(cf_t) * FLEN);
sync_find(&sync, fft_buffer, &find_idx);
find_ns = sync_get_slot_id(&sync);
if (sync_find(&sync, fft_buffer, 0, &find_idx) < 0) {
fprintf(stderr, "Error running sync_find\n");
exit(-1);
}
find_ns = 2*sync_get_sf_idx(&sync);
printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset,
ns, find_ns);
if (find_idx != offset + FLEN/2) {

View File

@ -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_cellsearch.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_cellsearch_init(ue_cellsearch_t * q) {
return ue_cellsearch_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, CS_DEFAULT_MAXFRAMES_DETECTED);
}
int ue_cellsearch_init_max(ue_cellsearch_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_cellsearch_t));
q->candidates = malloc(sizeof(ue_cellsearch_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_cellsearch_reset(q);
ret = LIBLTE_SUCCESS;
}
clean_exit:
if (ret == LIBLTE_ERROR) {
ue_cellsearch_free(q);
}
return ret;
}
void ue_cellsearch_free(ue_cellsearch_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_cellsearch_reset(ue_cellsearch_t * q)
{
q->current_nof_detected = 0;
q->current_nof_total = 0;
q->current_N_id_2 = 0;
}
void ue_cellsearch_set_threshold(ue_cellsearch_t * q, float threshold)
{
sync_set_threshold(&q->sfind, threshold);
}
int ue_cellsearch_set_nof_frames_total(ue_cellsearch_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_cellsearch_set_nof_frames_detected(ue_cellsearch_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_cellsearch_t * q, ue_cellsearch_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_cellsearch_scan(ue_cellsearch_t * q,
cf_t *signal,
uint32_t nsamples,
ue_cellsearch_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;
}

View File

@ -25,7 +25,7 @@
*
*/
#include "liblte/phy/phch/ue_dl.h"
#include "liblte/phy/ue/ue_dl.h"
#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1))

225
lte/phy/lib/ue/src/ue_mib.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,377 @@
/**
*
* \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;
if(sync_init(&q->sfind, 5 * CURRENT_SFLEN, CURRENT_FFTSIZE)) {
goto clean_exit;
}
if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
goto clean_exit;
}
sync_set_N_id_2(&q->sfind, cell.id%3);
sync_set_threshold(&q->sfind, FIND_THRESHOLD);
sync_set_N_id_2(&q->strack, cell.id%3);
sync_set_threshold(&q->strack, TRACK_THRESHOLD);
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) {
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->sfind)) {
/* Get the subframe index (0 or 5) */
q->sf_idx = sync_get_sf_idx(&q->sfind);
/* 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->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
if (q->peak_idx < CURRENT_SFLEN) {
q->sf_idx++;
}
} else {
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
ret = 0;
}
return ret;
}
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_sf_idx(&q->strack)) && q->decode_sss_on_track) {
INFO("\nWarning: 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);
} 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->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;
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->strack), (int) q->frame_no_cnt);
}
return LIBLTE_SUCCESS;
}
static int receive_samples(ue_sync_t *q) {
uint32_t read_len;
/* 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;
}
if (q->state == SF_FIND) {
read_len = 5 * CURRENT_SFLEN;
} else {
read_len = CURRENT_SFLEN;
}
/* copy last part of the last subframe (use move since there could be overlapping) */
memcpy(q->input_buffer, &q->input_buffer[read_len-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], read_len - 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;
}
DEBUG("Find PAR=%.2f\n", sync_get_last_peak_value(&q->sfind));
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 = LIBLTE_SUCCESS;
q->strack.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_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);
}
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->strack),
q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->strack));
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;
if (ret == LIBLTE_SUCCESS) {
ret = 1;
}
break;
}
}
DEBUG("UE SYNC returns %d\n", ret);
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
}

View File

@ -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_cell_detect ue_cell_detect.c)
TARGET_LINK_LIBRARIES(ue_cell_detect 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)

View File

@ -0,0 +1,246 @@
/**
*
* \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"
void *uhd;
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);
}
}
void input_init() {
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);
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
cuhd_set_rx_srate(uhd, 960000.0);
DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
}
int main(int argc, char **argv) {
ue_cellsearch_t s;
ue_mib_t uemib;
ue_cellsearch_result_t found_cell;
pbch_mib_t mib;
uint32_t flen;
cf_t *buffer;
int n;
parse_args(argc, argv);
input_init();
// allocate for the maximum size (10 ms at 1.92 MHz for PBCH decoding)
buffer = vec_malloc(sizeof(cf_t) * 19200*30);
if (!buffer) {
perror("malloc");
exit(-1);
}
if (ue_cellsearch_init(&s)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
}
if (threshold > 0) {
ue_cellsearch_set_threshold(&s, threshold);
}
if (nof_frames_total > 0) {
ue_cellsearch_set_nof_frames_total(&s, nof_frames_total);
}
if (nof_frames_detected > 0) {
ue_cellsearch_set_nof_frames_detected(&s, nof_frames_detected);
}
uint32_t nof_scanned_cells = 0;
flen = 4800;
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
exit(-1);
}
n = ue_cellsearch_scan(&s, buffer, flen, &found_cell);
switch(n) {
case CS_FRAME_UNALIGNED:
fprintf(stderr, "Unaliged frame!! Exiting\n");
exit(-1);
case CS_CELL_DETECTED:
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");
exit(-1);
}
} while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED);
if (n == CS_CELL_DETECTED) {
INFO("Stopping receiver...\n", 0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
if (ue_mib_init(&uemib, found_cell.cell_id, found_cell.cp)) {
fprintf(stderr, "Error initiating PBCH decoder\n");
exit(-1);
}
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);
usleep(50000);
uint32_t nof_frames = 0;
flen = MIB_FRAME_SIZE;
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
exit(-1);
}
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");
exit(-1);
}
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");
exit(-1);
}
}
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");
}
}
ue_mib_free(&uemib);
ue_cellsearch_free(&s);
cuhd_close(uhd);
exit(0);
}

View File

@ -167,14 +167,17 @@ int main(int argc, char **argv) {
#endif
input_init();
cell.cp = CPNORM;
cell.id = 1;
cell.nof_ports = 1;
cell.nof_prb = 6;
if (ue_sync_init(&s, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) {
if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
}
ue_sync_pbch_enable(&s, true);
signal_detected = true;
frame_cnt = 0;
mean_ce_time=0;
@ -191,9 +194,8 @@ int main(int argc, char **argv) {
if (n == 1 && ue_sync_get_sfidx(&s) == 0) {
if (signal_detected) {
cell = ue_sync_get_cell(&s);
pss_synch_init_fft(&pss,
SF_LEN(lte_symbol_sz(cell.nof_prb), cell.cp),
SF_LEN(lte_symbol_sz(cell.nof_prb)),
lte_symbol_sz(cell.nof_prb));
pss_synch_set_N_id_2(&pss, cell.id%3);

View File

@ -424,6 +424,29 @@ uint32_t vec_max_fi(float *x, uint32_t len) {
#endif
}
uint32_t vec_max_abs_ci(cf_t *x, uint32_t len) {
#ifdef HAVE_VOLK_MAX_ABS_FUNCTION
uint32_t target=0;
volk_32fc_index_max_16u(&target,x,len);
return target;
#else
uint32_t i;
float m=-FLT_MAX;
uint32_t p=0;
float tmp;
for (i=0;i<len;i++) {
tmp = crealf(x[i])*crealf(x[i]) + cimagf(x[i])*cimagf(x[i]);
if (tmp>m) {
m=tmp;
p=i;
}
}
return p;
#endif
}
void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len) {
int i;
int tmp;

13
matlab/sync/find_peaks.m Normal file
View File

@ -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

View File

@ -1,16 +1,14 @@
function [ w2] = find_pss2( 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)];
ccd=[0; cc(fft_size/2+1:fft_size); cc(2:fft_size/2)];
ccf=sqrt(fft_size)*conj(ifft(ccd));
w2=real(conv(x,ccf))/62;
w2=abs(conv(x,ccf/62)).^2/var(x,1)/sqrt(2);
plot(w2)
[m i]=max(w2);
en=var(x,1);
p_m = m/en;
[m, idx]=max(w2);
fprintf('Frame starts at %d, energy=%g, p=%g, p/en=%g dB\n',i, ...
en, m, m/en);
%fprintf('Frame starts at %d, energy=%g, p=%g, p/en=%g dB\n',i, ...
% en, m, m/en);
end