Merged with #51

master
ismagom 10 years ago
parent 36e6c153d9
commit cc364f7dfa

@ -84,6 +84,9 @@ IF(${CUHD_FIND} GREATER -1)
add_executable(cell_search cell_search.c cell_search_utils.c)
target_link_libraries(cell_search lte_phy cuhd )
add_executable(cell_measurement cell_measurement.c cell_search_utils.c)
target_link_libraries(cell_measurement cuhd lte_phy)
MESSAGE(STATUS " UHD examples will be installed.")
ELSE(${CUHD_FIND} GREATER -1)

@ -0,0 +1,218 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
bool disable_plots;
int force_N_id_2;
char *uhd_args;
float uhd_freq;
float uhd_gain;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aglnvf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
/* TODO: Do something with the output data */
char data[10000];
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
prog_args_t prog_args;
lte_cell_t cell;
int64_t sf_cnt;
pbch_mib_t mib;
ue_sync_t ue_sync;
void *uhd;
parse_args(&prog_args, argc, argv);
printf("Opening UHD device...\n");
if (cuhd_open(prog_args.uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
/* Set receiver gain */
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
if (cell_search(uhd, prog_args.force_N_id_2, &cell, &mib)) {
fprintf(stderr, "Cell not found\n");
exit(-1);
}
cuhd_start_rx_stream(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
/* Initialize subframe counter */
sf_cnt = 0;
lte_fft_t fft;
chest_t chest;
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
return -1;
}
if (chest_init_LTEDL(&chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
return -1;
}
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
unsigned int nframes=0;
/* Main loop */
while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
float rssi=0, rsrp=0, rsrq=0;
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
/* Run FFT for all subframe data */
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
chest_measure_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(chest_rssi_sf(&chest, sf_symbols),rssi,nframes);
rsrq = VEC_CMA(chest_rsrq_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync)),rsrq,nframes);
rsrp = VEC_CMA(chest_rsrp_sf(&chest, ue_sync_get_sfidx(&ue_sync)),rsrp,nframes);
nframes++;
// Plot and Printf
if ((nframes%10) == 0) {
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, RSSI: %+5.2f dBm, RSRP: %+4.2f dBm, RSRQ: %4.2f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rssi*1000/4/cell.nof_prb/12/2)-prog_args.uhd_gain,
10*log10(rsrp*1000)-prog_args.uhd_gain,
10*log10(rsrq));
}
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop
ue_sync_free(&ue_sync);
cuhd_close(uhd);
printf("\nBye\n");
exit(0);
}

@ -121,7 +121,6 @@ int main(int argc, char **argv) {
void *uhd;
ue_celldetect_t s;
ue_celldetect_result_t found_cells[3];
cf_t *buffer;
int nof_freqs;
lte_earfcn_t channels[MAX_EARFCN];
uint32_t freq;
@ -142,12 +141,6 @@ int main(int argc, char **argv) {
exit(-1);
}
buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
return LIBLTE_ERROR;
}
if (ue_celldetect_init(&s)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
@ -178,7 +171,7 @@ int main(int argc, char **argv) {
printf("\n");
}
n = find_cell(uhd, &s, buffer, found_cells);
n = find_all_cells(uhd, found_cells);
if (n < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
@ -186,7 +179,7 @@ int main(int argc, char **argv) {
if (n == CS_CELL_DETECTED) {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > threshold/2) {
if (decode_pbch(uhd, buffer, &found_cells[i], nof_frames_total, &mib)) {
if (decode_pbch(uhd, &found_cells[i], nof_frames_total, &mib)) {
fprintf(stderr, "Error decoding PBCH\n");
exit(-1);
}
@ -195,6 +188,8 @@ int main(int argc, char **argv) {
}
}
printf("\nBye\n");
ue_celldetect_free(&s);
cuhd_close(uhd);
exit(0);

@ -40,19 +40,26 @@
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
int decode_pbch(void *uhd, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
{
ue_mib_t uemib;
int n;
bzero(mib, sizeof(pbch_mib_t));
int ret = LIBLTE_ERROR;
uint32_t nof_frames = 0;
uint32_t flen = MIB_FRAME_SIZE;
cf_t *buffer = vec_malloc(sizeof(cf_t) * flen);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
bzero(mib, sizeof(pbch_mib_t));
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
fprintf(stderr, "Error initiating PBCH decoder\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0);
@ -63,95 +70,203 @@ int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uin
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
DEBUG("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
n = ue_mib_decode(&uemib, buffer, flen, mib);
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling ue_mib_decode()\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
if (n == MIB_FRAME_UNALIGNED) {
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
if (cuhd_recv(uhd, buffer, 1500, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
bzero(buffer, flen * sizeof(cf_t));
}
nof_frames++;
} while (n != MIB_FOUND && nof_frames < 2*nof_frames_total);
if (n == MIB_FOUND) {
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
pbch_mib_fprint(stdout, mib, found_cell->cell_id);
ret = LIBLTE_SUCCESS;
} else {
printf("\nCould not decode MIB\n");
ret = LIBLTE_ERROR;
}
free_and_exit:
free(buffer);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
ue_mib_free(&uemib);
return LIBLTE_SUCCESS;
return ret;
}
int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3])
int find_cell(void *uhd, ue_celldetect_result_t *found_cell, uint32_t N_id_2)
{
int n;
int ret = LIBLTE_ERROR;
ue_celldetect_t cd;
cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
if (ue_celldetect_init(&cd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
goto free_and_exit;
}
ue_celldetect_set_nof_frames_detected(&cd, 50);
ue_celldetect_set_nof_frames_total(&cd, 500);
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
cuhd_set_rx_srate(uhd, 960000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
uint32_t nof_scanned_cells = 0;
uint32_t flen = 4800;
int nof_detected_cells = 0;
int n;
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]);
DEBUG("Scanning cell at N_id_2=%d\n",N_id_2);
n = ue_celldetect_scan(&cd, buffer, flen, found_cell, N_id_2);
switch(n) {
case CS_FRAME_UNALIGNED:
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
return LIBLTE_ERROR;
/* FIXME: What should we do here?? */
ret = -1;
goto free_and_exit;
case CS_CELL_DETECTED:
nof_detected_cells++;
if (found_cell[nof_scanned_cells].peak > 0) {
if (found_cell->peak > 0) {
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
found_cell[nof_scanned_cells].cell_id,
lte_cp_string(found_cell[nof_scanned_cells].cp),
found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode,
s->nof_frames_detected);
found_cell->cell_id,
lte_cp_string(found_cell->cp),
found_cell->peak, found_cell->mode,
cd.nof_frames_detected);
}
nof_scanned_cells++;
ret = 1;
INFO("Cell found at N_id_2=%d\n",N_id_2);
break;
case CS_CELL_NOT_DETECTED:
nof_scanned_cells++;
ret = 0;
DEBUG("No cell found at N_id_2=%d\n",N_id_2);
break;
case LIBLTE_ERROR:
case LIBLTE_ERROR_INVALID_INPUTS:
ret = LIBLTE_ERROR;
fprintf(stderr, "Error calling cellsearch_scan()\n");
return LIBLTE_ERROR;
goto free_and_exit;
}
} while(nof_scanned_cells < 3);
} while(n == 0);
free_and_exit:
free(buffer);
ue_celldetect_free(&cd);
INFO("Stopping receiver...\n", 0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
return ret;
}
int find_all_cells(void *uhd, ue_celldetect_result_t found_cell[3])
{
uint32_t N_id_2;
int ret;
int nof_detected_cells = 0;
for (N_id_2=0;N_id_2<3;N_id_2++) {
ret = find_cell(uhd, &found_cell[N_id_2], N_id_2);
if (ret == 1) {
nof_detected_cells++;
} else if (ret == LIBLTE_ERROR) {
return LIBLTE_ERROR;
}
}
return nof_detected_cells;
}
int cell_search(void *uhd, int force_N_id_2, lte_cell_t *cell, pbch_mib_t *mib)
{
int ret;
ue_celldetect_result_t found_cells[3];
bzero(found_cells, 3*sizeof(ue_celldetect_result_t));
if (force_N_id_2 >= 0) {
ret = find_cell(uhd, &found_cells[force_N_id_2], force_N_id_2);
} else {
ret = find_all_cells(uhd, found_cells);
}
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
int max_peak_cell = 0;
float max_peak_value = -1.0;
if (ret > 0) {
if (force_N_id_2 >= 0) {
max_peak_cell = force_N_id_2;
} else {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > max_peak_value) {
max_peak_value = found_cells[i].peak;
max_peak_cell = i;
}
}
}
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", found_cells[max_peak_cell].cell_id, max_peak_cell);
if (decode_pbch(uhd, &found_cells[max_peak_cell], 400, mib)) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id);
return LIBLTE_ERROR;
}
} else {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_ERROR;
}
cell->cp = found_cells[max_peak_cell].cp;
cell->id = found_cells[max_peak_cell].cell_id;
cell->nof_prb = mib->nof_prb;
cell->nof_ports = mib->nof_ports;
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell->nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
return LIBLTE_SUCCESS;
}
#endif

@ -29,12 +29,18 @@
#include "liblte/phy/phy.h"
int decode_pbch(void *uhd,
cf_t *buffer,
ue_celldetect_result_t *found_cell,
uint32_t nof_frames_total,
pbch_mib_t *mib);
int find_cell(void *uhd,
ue_celldetect_t *s,
cf_t *buffer,
int find_all_cells(void *uhd,
ue_celldetect_result_t found_cell[3]);
int find_cell(void *uhd,
ue_celldetect_result_t *found_cell,
uint32_t N_id_2);
int cell_search(void *uhd,
int force_N_id_2,
lte_cell_t *cell,
pbch_mib_t *mib);

@ -84,74 +84,27 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mi
q->sf_idx = 9;
} else {
#ifndef DISABLE_UHD
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(config->uhd_args, &q->uhd)) {
fprintf(stderr, "Error opening uhd\n");
return LIBLTE_ERROR;
}
/* Set receiver gain */
cuhd_set_rx_gain(q->uhd, config->uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq);
cuhd_rx_wait_lo_locked(q->uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq);
int n;
ue_celldetect_t cd;
ue_celldetect_result_t found_cells[3];
cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
if (cell_search(q->uhd, config->force_N_id_2, cell, mib)) {
fprintf(stderr, "Cell not found\n");
return LIBLTE_ERROR;
}
if (ue_celldetect_init(&cd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1);
}
n = find_cell(q->uhd, &cd, buffer, found_cells);
if (n < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
int max_peak_cell = 0;
float max_peak_value = -1.0;
if (n > 0) {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > max_peak_value) {
max_peak_value = found_cells[i].peak;
max_peak_cell = i;
}
}
if (decode_pbch(q->uhd, buffer, &found_cells[max_peak_cell], 400, mib)) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id);
return LIBLTE_ERROR;
}
} else {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_ERROR;
}
free(buffer);
cell->cp = found_cells[max_peak_cell].cp;
cell->id = found_cells[max_peak_cell].cell_id;
cell->nof_prb = mib->nof_prb;
cell->nof_ports = mib->nof_ports;
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell->nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(q->uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(q->uhd);
if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) {
@ -159,9 +112,6 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mi
return LIBLTE_ERROR;
}
/* 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(&q->sframe, true);
// Here, the subframe length and input buffer is managed by ue_sync
q->mode = UHD;

@ -57,6 +57,7 @@ typedef struct LIBLTE_API {
uint32_t cell_id_file;
uint32_t nof_prb_file;
uint32_t nof_ports_file;
int force_N_id_2;
float uhd_freq;
float uhd_gain;

@ -68,13 +68,14 @@ void args_default(prog_args_t *args) {
args->disable_plots = false;
args->io_config.find_threshold = -1.0;
args->io_config.input_file_name = NULL;
args->io_config.force_N_id_2 = -1; // Pick the best
args->io_config.uhd_args = "";
args->io_config.uhd_freq = -1.0;
args->io_config.uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog);
printf("Usage: %s [cargndvtbl] [-i input_file | -f rx_frequency (in Hz)]\n", prog);
printf("\t-c cell_id if reading from file [Default %d]\n", args->io_config.cell_id_file);
printf("\t-p nof_prb if reading from file [Default %d]\n", args->io_config.nof_prb_file);
printf("\t-o nof_ports if reading from file [Default %d]\n", args->io_config.nof_ports_file);
@ -85,6 +86,7 @@ void usage(prog_args_t *args, char *prog) {
#else
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-b Decode PBCH only [Default All channels]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold);
@ -99,7 +101,7 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "icagfndvtbpro")) != -1) {
while ((opt = getopt(argc, argv, "icagfndvtbprol")) != -1) {
switch (opt) {
case 'i':
args->io_config.input_file_name = argv[optind];
@ -128,6 +130,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->io_config.force_N_id_2 = atoi(argv[optind]);
break;
case 'r':
args->rnti= atoi(argv[optind]);
break;
@ -144,6 +149,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
}
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
@ -177,10 +183,6 @@ int main(int argc, char **argv) {
}
#endif
/* Setup SIGINT handler */
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
/* Initialize subframe counter */
sf_cnt = 0;

@ -76,27 +76,43 @@ LIBLTE_API void chest_free(chest_t *q);
LIBLTE_API int chest_set_nof_ports(chest_t *q,
uint32_t nof_ports);
LIBLTE_API int chest_init_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q,
LIBLTE_API float chest_rsrp(chest_t *q,
uint32_t nslot,
uint32_t port_id,
lte_cell_t cell);
uint32_t port_id);
LIBLTE_API float chest_rsrp_sf(chest_t *q,
uint32_t sf_idx);
LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q,
LIBLTE_API float chest_rssi(chest_t *q,
cf_t *input);
LIBLTE_API float chest_rssi_sf(chest_t *q,
cf_t *input);
LIBLTE_API float chest_rsrq(chest_t *q,
cf_t *input,
uint32_t nslot,
lte_cell_t cell);
uint32_t port_id);
LIBLTE_API int chest_ref_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API float chest_rsrq_sf(chest_t *q,
cf_t *input,
uint32_t sf_idx);
LIBLTE_API int chest_ce_ref(chest_t *q,
LIBLTE_API int chest_measure_ref(chest_t *q,
cf_t *input,
uint32_t nslot,
uint32_t port_id,
uint32_t nref);
LIBLTE_API void chest_measure_slot(chest_t *q,
cf_t *input,
uint32_t nslot);
LIBLTE_API void chest_measure_sf(chest_t *q,
cf_t *input,
uint32_t sf_idx);
LIBLTE_API int chest_ce_slot_port(chest_t *q,
cf_t *input,
cf_t *ce,
@ -139,11 +155,51 @@ LIBLTE_API void chest_ce_fprint(chest_t *q,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API int chest_ref_symbols(chest_t *q,
LIBLTE_API int chest_ref_get_symbols(chest_t *q,
uint32_t port_id,
uint32_t nslot,
uint32_t l[2]);
/*********************************************************
*
* Downlink Channel Estimator
*
*********************************************************/
LIBLTE_API int chest_init_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL_slot_port(chest_t *q,
uint32_t nslot,
uint32_t port_id,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL_slot(chest_t *q,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL(chest_t *q,
lte_cell_t cell);
/*********************************************************
*
* Uplink Channel Estimator
*
*********************************************************/
LIBLTE_API int chest_init_LTEUL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEUL_slot(chest_t *q,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEUL(chest_t *q,
lte_cell_t cell);
/* High-level API */
/** TODO: The high-level API has N interfaces, one for each port */

@ -45,8 +45,7 @@ typedef _Complex float cf_t;
typedef struct LIBLTE_API{
uint32_t time_idx;
uint32_t freq_idx;
cf_t simbol;
cf_t recv_simbol;
cf_t symbol;
}ref_t;
typedef struct LIBLTE_API{
@ -57,13 +56,34 @@ typedef struct LIBLTE_API{
uint32_t nof_prb;
ref_t *refs;
cf_t *ch_est;
cf_t *recv_symbol;
} refsignal_t;
typedef struct LIBLTE_API {
float beta; // amplitude scaling
uint32_t delta_ss; // Set to 0 for PUCCH
uint32_t cyclic_shift;
uint32_t cyclic_shift_for_drms; /* From DCI 0. Set to 0 if no PDCCH with DCI 0 for the same TB
or if the initial PUSCH is semi-persisently scheduled or
if the initial PUSCH is scheduled by the RA response grant */
bool group_hopping_en;
bool sequence_hopping_en;
} refsignal_ul_cfg_t;
LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q,
uint32_t port_id,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int refsignal_init_LTEUL_drms_pusch(refsignal_t *q,
uint32_t nof_prb,
uint32_t prb_start,
uint32_t nslot,
lte_cell_t cell,
refsignal_ul_cfg_t *drms_cfg);
LIBLTE_API void refsignal_free(refsignal_t *q);
LIBLTE_API int refsignal_put(refsignal_t *q,

@ -92,7 +92,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#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)))
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx)
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx)
#define RS_VSHIFT(cell_id) (cell_id%6)

@ -40,7 +40,7 @@ LIBLTE_API int sequence_init(sequence_t *q, uint32_t len);
LIBLTE_API void sequence_free(sequence_t *q);
LIBLTE_API int sequence_LTEPRS(sequence_t *q,
LIBLTE_API int sequence_LTE_pr(sequence_t *q,
uint32_t len,
uint32_t seed);

@ -69,6 +69,10 @@ typedef struct LIBLTE_API {
bool sss_en;
bool normalize_en;
lte_cp_t cp;
uint32_t m0;
uint32_t m1;
float m0_value;
float m1_value;
}sync_t;
@ -115,6 +119,9 @@ 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);
/* Sets the CP length estimation (must do it if disabled) */
LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);

@ -57,8 +57,8 @@
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 300
#define CS_DEFAULT_MAXFRAMES_DETECTED 30
#define CS_DEFAULT_MAXFRAMES_TOTAL 500
#define CS_DEFAULT_MAXFRAMES_DETECTED 50
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
@ -87,8 +87,6 @@ typedef struct LIBLTE_API {
uint32_t current_nof_detected;
uint32_t current_nof_total;
uint32_t current_N_id_2;
uint32_t *mode_ntimes;
char *mode_counted;
@ -109,7 +107,8 @@ LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q,
cf_t *signal,
uint32_t nsamples,
ue_celldetect_result_t *found_cell);
ue_celldetect_result_t *found_cell,
uint32_t N_id_2);
LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q,
uint32_t nof_frames);

@ -55,10 +55,8 @@
#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

@ -35,8 +35,11 @@
typedef _Complex float cf_t;
#define EXPAVERAGE(data, average, nframes) (((data) + (average) * (nframes)) / ((nframes) + 1))
// Cumulative moving average
#define VEC_CMA(data, average, n) ((data) + ((data) - (average)) / ((n)+1))
// Exponential moving average
#define VEC_EMA(data, average, alpha) ((factor)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, uint32_t len);

@ -38,7 +38,7 @@
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
#define SF_SZ(q) (2 * SLOT_SZ(q))
#define VOLK_INTERP
//#define VOLK_INTERP
void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
chest_ref_fprint(q, stream, nslot, port_id);
@ -62,8 +62,8 @@ void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id
int i;
fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].simbol);
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].symbol,
__imag__ q->refsignal[port_id][nslot].refs[i].symbol);
}
fprintf(stream, "];\n");
}
@ -72,8 +72,8 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t por
int i;
fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol);
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].recv_symbol[i],
__imag__ q->refsignal[port_id][nslot].recv_symbol[i]);
}
fprintf(stream, "];\n");
}
@ -92,7 +92,59 @@ void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id)
fprintf(stream, "];\n");
}
int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) {
float chest_rsrp(chest_t *q, uint32_t nslot, uint32_t port_id) {
int nof_refs = q->refsignal[port_id][nslot].nof_refs;
cf_t *ch_est = q->refsignal[port_id][nslot].ch_est;
return crealf(vec_dot_prod_conj_ccc(ch_est, ch_est, nof_refs))/nof_refs;
}
float chest_rsrp_sf(chest_t *q, uint32_t sf_idx) {
int n,p;
float rsrp=0;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
rsrp+=chest_rsrp(q, 2*sf_idx+n, p)/(2*q->nof_ports);
}
}
return rsrp;
}
float chest_rssi(chest_t *q, cf_t *input) {
float rssi = 0;
int i;
int l[2];
if (q->nof_symbols == CPNORM_NSYMB) {
l[0] = 0; l[1] = 4;
} else {
l[0] = 0; l[1] = 3;
}
for (i=0;i<2;i++) {
cf_t *tmp = &input[l[i]*q->nof_re];
rssi += crealf(vec_dot_prod_conj_ccc(tmp, tmp, q->nof_re));
}
return rssi;
}
float chest_rssi_sf(chest_t *q, cf_t *input) {
int n;
int slotsz = q->nof_symbols*q->nof_re;
float rssi=0;
for (n=0;n<2;n++) {
rssi += chest_rssi(q, &input[n*slotsz]);
}
return rssi;
}
float chest_rsrq(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) {
return (q->nof_re/RE_X_RB) * chest_rsrp(q, nslot, port_id) / chest_rssi(q, input);
}
float chest_rsrq_sf(chest_t *q, cf_t *input, uint32_t sf_idx) {
return (4*q->nof_ports*q->nof_re/RE_X_RB) * chest_rsrp_sf(q, sf_idx) / chest_rssi_sf(q, input);
}
int chest_measure_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) {
int fidx, tidx;
cf_t known_ref, channel_ref;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
@ -107,10 +159,9 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
known_ref = q->refsignal[port_id][nslot].refs[nref].symbol;
channel_ref = input[tidx * q->nof_re + fidx];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
q->refsignal[port_id][nslot].recv_symbol[nref] = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx,
10*log10f(cabsf(channel_ref/known_ref)),
@ -130,10 +181,42 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint
return ret;
}
void chest_measure_slot_port(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id)
{
int i;
refsignal_t *r = &q->refsignal[port_id][nslot];
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++) {
chest_measure_ref(q, input, nslot, port_id, i);
}
}
void chest_measure_slot(chest_t *q, cf_t *input, uint32_t nslot) {
int p;
for (p=0;p<q->nof_ports;p++) {
chest_measure_slot_port(q, input, nslot, p);
}
}
void chest_measure_sf(chest_t *q, cf_t *input, uint32_t sf_idx) {
int p, n, slotsz;
slotsz = q->nof_symbols*q->nof_re;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
chest_measure_slot_port(q, &input[n*slotsz], 2*sf_idx+n, p);
}
}
}
/* Computes channel estimates for each reference in a slot and port.
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
*/
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) {
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id)
{
uint32_t i, j;
cf_t x[2], y[MAX_NSYMB];
@ -147,12 +230,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];
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++) {
chest_ce_ref(q, input, nslot, port_id, i);
}
chest_measure_slot_port(q, input, nslot, port_id);
/* interpolate the symbols with references
* in the freq domain */
@ -259,17 +337,58 @@ int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_p
return ret;
}
void chest_free(chest_t *q) {
int p, n;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<NSLOTS_X_FRAME;n++) {
refsignal_free(&q->refsignal[p][n]);
}
}
#ifdef VOLK_INTERP
for (p=0;p<MAX_PORTS;p++) {
interp_free(&q->interp_freq[p]);
interp_free(&q->interp_time[p]);
}
#endif
bzero(q, sizeof(chest_t));
}
/* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot)
*/
int chest_ref_get_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/*********************************************************************
*
* Downlink Channel estimator
*
*********************************************************************/
int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
int ret;
ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
if (ret != LIBLTE_SUCCESS) {
return ret;
} else {
return chest_ref_LTEDL(q, cell);
return chest_ref_set_LTEDL(q, cell);
}
}
int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
int chest_ref_set_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
@ -293,10 +412,10 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_
return ret;
}
int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int chest_ref_set_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell);
ret = chest_ref_set_LTEDL_slot_port(q, nslot, p, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
@ -304,10 +423,10 @@ int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
return LIBLTE_SUCCESS;
}
int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
int chest_ref_set_LTEDL(chest_t *q, lte_cell_t cell) {
int n, ret;
for (n=0;n<NSLOTS_X_FRAME;n++) {
ret = chest_ref_LTEDL_slot(q, n, cell);
ret = chest_ref_set_LTEDL_slot(q, n, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
@ -315,37 +434,32 @@ int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
return LIBLTE_SUCCESS;
}
void chest_free(chest_t *q) {
int p, n;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<NSLOTS_X_FRAME;n++) {
refsignal_free(&q->refsignal[p][n]);
}
}
#ifdef VOLK_INTERP
for (p=0;p<MAX_PORTS;p++) {
interp_free(&q->interp_freq[p]);
interp_free(&q->interp_time[p]);
}
#endif
bzero(q, sizeof(chest_t));
}
/* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot)
*/
int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/*********************************************************************
*
* TODO: Uplink Channel estimator
*
*
*********************************************************************/
/** High-level API

@ -38,49 +38,52 @@
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/common/sequence.h"
#include "ul_rs_tables.h"
#define idx(x, y) (l*nof_refs_x_symbol+i)
int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) {
int v=-1;
switch(port_id) {
int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id)
{
int v = -1;
switch (port_id) {
case 0:
if (symbol_id == 0) {
v=0;
v = 0;
} else {
v=3;
v = 3;
}
break;
case 1:
if (symbol_id == 0) {
v=3;
v = 3;
} else {
v=0;
v = 0;
}
break;
case 2:
v=3*(ns%2);
v = 3 * (ns % 2);
break;
case 3:
v=3+3*(ns%2);
v = 3 + 3 * (ns % 2);
break;
}
return v;
}
uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) {
return 6*m+((v+(cell_id%6))%6);
uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id)
{
return 6 * m + ((v + (cell_id % 6)) % 6);
}
int refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
int refsignal_put(refsignal_t * q, cf_t * slot_symbols)
{
uint32_t i;
uint32_t fidx, tidx;
if (q != NULL &&
slot_symbols != NULL)
{
for (i=0;i<q->nof_refs;i++) {
if (q != NULL && slot_symbols != NULL) {
for (i = 0; i < q->nof_refs; i++) {
fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol;
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].symbol;
}
return LIBLTE_SUCCESS;
} else {
@ -91,8 +94,9 @@ int refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
/** Initializes refsignal_t object according to 3GPP 36.211 6.10.1
*
*/
int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
lte_cell_t cell) {
int refsignal_init_LTEDL(refsignal_t * q, uint32_t port_id, uint32_t nslot,
lte_cell_t cell)
{
uint32_t c_init;
uint32_t ns, l, lp[2];
@ -106,9 +110,7 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME &&
lte_cell_isvalid(&cell))
{
nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) {
bzero(q, sizeof(refsignal_t));
bzero(&seq, sizeof(sequence_t));
@ -131,7 +133,7 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
q->nsymbols = nof_ref_symbols;
q->voffset = cell.id%6;
q->voffset = cell.id % 6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols);
@ -151,12 +153,17 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
goto free_and_exit;
}
q->recv_symbol = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->recv_symbol) {
goto free_and_exit;
}
ns = nslot;
for (l = 0; l < nof_ref_symbols; l++) {
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1)
+ 2 * cell.id + N_cp;
ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init);
ret = sequence_LTE_pr(&seq, 2 * 2 * MAX_PRB, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
@ -167,12 +174,14 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
mp = i + MAX_PRB - cell.nof_prb;
/* generate signal */
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
__real__ q->refs[idx(l, i)].symbol =
(1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
__imag__ q->refs[idx(l, i)].symbol =
(1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
/* mapping to resource elements */
q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id);
q->refs[idx(l,i)].time_idx = lp[l];
q->refs[idx(l, i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id);
q->refs[idx(l, i)].time_idx = lp[l];
}
}
ret = LIBLTE_SUCCESS;
@ -187,7 +196,179 @@ free_and_exit:
return ret;
}
void refsignal_free(refsignal_t *q) {
// n_drms_2 table 5.5.2.1.1-1 from 36.211
uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 };
// n_drms_1 table 5.5.2.1.1-2 from 36.211
uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 };
/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */
int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id,
refsignal_ul_cfg_t * cfg)
{
uint32_t i;
// Calculate u and v
uint32_t u, v;
uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30);
if (cfg->group_hopping_en) {
sequence_t seq;
sequence_LTE_pr(&seq, cell_id / 30, 160);
uint32_t f_gh = 0;
for (i = 0; i < 8; i++) {
f_gh += seq.c[8 * ns + i] << i;
}
sequence_free(&seq);
u = ((f_gh%30) + f_ss) % 30;
} else {
u = f_ss % 30;
}
if (len < 6 * RE_X_RB) {
v = 0;
} else {
if (!cfg->group_hopping_en && cfg->sequence_hopping_en) {
sequence_t seq;
sequence_LTE_pr(&seq, ((cell_id / 30) << 5) + f_ss, 20);
v = seq.c[ns];
sequence_free(&seq);
} else {
v = 0;
}
}
if (len >= 3 * RE_X_RB) {
uint32_t n_sz;
uint32_t q;
float q_hat;
/* get largest prime n_zc<len */
for (i = NOF_PRIME_NUMBERS - 1; i > 0; i--) {
if (prime_numbers[i] < len) {
n_sz = prime_numbers[i];
break;
}
}
q_hat = (float) n_sz *(u + 1) / 31;
if ((((uint32_t) (2 * q_hat)) % 2) == 0) {
q = (uint32_t) (q_hat + 0.5) + v;
} else {
q = (uint32_t) (q_hat + 0.5) - v;
}
cf_t *x_q = malloc(sizeof(cf_t) * n_sz);
if (!x_q) {
perror("malloc");
return LIBLTE_ERROR;
}
for (i = 0; i < n_sz; i++) {
x_q[i] =
cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz);
}
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz];
}
free(x_q);
} else {
if (len == RE_X_RB) {
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i));
}
} else {
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i));
}
}
}
return LIBLTE_SUCCESS;
}
/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2
*
*/
int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start,
uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg)
{
uint32_t i;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t n_prs;
uint32_t M_sc;
float alpha;
if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) {
bzero(q, sizeof(refsignal_t));
M_sc = nof_prb * RE_X_RB;
q->nof_refs = M_sc;
q->nsymbols = 1;
q->voffset = cell.id % 6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * 1);
if (!q->symbols_ref) {
perror("malloc");
goto free_and_exit;
}
if (CP_ISNORM(cell.cp)) {
q->symbols_ref[0] = 3;
} else {
q->symbols_ref[0] = 2;
}
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) {
goto free_and_exit;
}
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->ch_est) {
goto free_and_exit;
}
/* Calculate n_prs */
uint32_t c_init;
sequence_t seq;
c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30);
ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
n_prs = 0;
for (i = 0; i < 8; i++) {
n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i);
}
sequence_free(&seq);
// Calculate cyclic shift alpha
uint32_t n_cs =
(n_drms_1[cfg->cyclic_shift] +
n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12;
alpha = 2 * M_PI * (n_cs) / 12;
if (rs_sequence(q->refs, M_sc, alpha, cell.id, nslot, cfg)) {
fprintf(stderr, "Error generating RS sequence\n");
goto free_and_exit;
}
/* mapping to resource elements */
for (i=0;i<M_sc;i++) {
q->refs[i].freq_idx = prb_start*RE_X_RB + i;
q->refs[i].time_idx = q->symbols_ref[0];
}
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret == LIBLTE_ERROR) {
refsignal_free(q);
}
return ret;
}
void refsignal_free(refsignal_t * q)
{
if (q->symbols_ref) {
free(q->symbols_ref);
}
@ -199,5 +380,3 @@ void refsignal_free(refsignal_t *q) {
}
bzero(q, sizeof(refsignal_t));
}

@ -0,0 +1,127 @@
/**
*
* \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 <stdint.h>
// Phi values for M_sc=12 Table 5.5.1.2-1 in 36.211
int phi_M_sc_12[30][12] = {{-1, 1, 3,-3, 3, 3, 1, 1, 3, 1,-3, 3},
{ 1, 1, 3, 3, 3,-1, 1,-3,-3, 1,-3, 3},
{ 1, 1,-3,-3,-3,-1,-3,-3, 1,-3, 1,-1},
{-1, 1, 1, 1, 1,-1,-3,-3, 1,-3, 3,-1},
{-1, 3, 1,-1, 1,-1,-3,-1, 1,-1, 1, 3},
{ 1,-3, 3,-1,-1, 1, 1,-1,-1, 3,-3, 1},
{-1, 3,-3,-3,-3, 3, 1,-1, 3, 3,-3, 1},
{-3,-1,-1,-1, 1,-3, 3,-1, 1,-3, 3, 1},
{ 1,-3, 3, 1,-1,-1,-1, 1, 1, 3,-1, 1},
{ 1,-3,-1, 3, 3,-1,-3, 1, 1, 1, 1, 1},
{-1, 3,-1, 1, 1,-3,-3,-1,-3,-3, 3,-1},
{ 3, 1,-1,-1, 3, 3,-3, 1, 3, 1, 3, 3},
{ 1,-3, 1, 1,-3, 1, 1, 1,-3,-3,-3, 1},
{ 3, 3,-3, 3,-3, 1, 1, 3,-1,-3, 3, 3},
{-3, 1,-1,-3,-1, 3, 1, 3, 3, 3,-1, 1},
{ 3,-1, 1,-3,-1,-1, 1, 1, 3, 1,-1,-3},
{ 1, 3, 1,-1, 1, 3, 3, 3,-1,-1, 3,-1},
{-3, 1, 1, 3,-3, 3,-3,-3, 3, 1, 3,-1},
{-3, 3, 1, 1,-3, 1,-3,-3,-1,-1, 1,-3},
{-1, 3, 1, 3, 1,-1,-1, 3,-3,-1,-3,-1},
{-1,-3, 1, 1, 1, 1, 3, 1,-1, 1,-3,-1},
{-1, 3,-1, 1,-3,-3,-3,-3,-3, 1,-1,-3},
{ 1, 1,-3,-3,-3,-3,-1, 3,-3, 1,-3, 3},
{ 1, 1,-1,-3,-1,-3, 1,-1, 1, 3,-1, 1},
{ 1, 1, 3, 1, 3, 3,-1, 1,-1,-3,-3, 1},
{ 1,-3, 3, 3, 1, 3, 3, 1,-3,-1,-1, 3},
{ 1, 3,-3,-3, 3,-3, 1,-1,-1, 3,-1,-3},
{-3,-1,-3,-1,-3, 3, 1,-1, 1, 3,-3,-3},
{-1, 3,-3, 3,-1, 3, 3,-3, 3, 3,-1,-1},
{ 3,-3,-3,-1,-1,-3,-1, 3,-3, 3, 1,-1}};
// Phi values for M_sc=24 Table 5.5.1.2-2 in 36.211
int phi_M_sc_24[30][24] = {{-1, 3, 1,-3, 3,-1, 1, 3,-3, 3, 1, 3,-3, 3, 1, 1,-1, 1, 3,-3, 3,-3,-1,-3},
{-3, 3,-3,-3,-3, 1,-3,-3, 3,-1, 1, 1, 1, 3, 1,-1, 3,-3,-3, 1, 3, 1, 1,-3},
{ 3,-1, 3, 3, 1, 1,-3, 3, 3, 3, 3, 1,-1, 3,-1, 1, 1,-1,-3,-1,-1, 1, 3, 3},
{-1,-3, 1, 1, 3,-3, 1, 1,-3,-1,-1, 1, 3, 1, 3, 1,-1, 3, 1, 1,-3,-1,-3,-1},
{-1,-1,-1,-3,-3,-1, 1, 1, 3, 3,-1, 3,-1, 1,-1,-3, 1,-1,-3,-3, 1,-3,-1,-1},
{-3, 1, 1, 3,-1, 1, 3, 1,-3, 1,-3, 1, 1,-1,-1, 3,-1,-3, 3,-3,-3,-3, 1, 1},
{ 1, 1,-1,-1, 3,-3,-3, 3,-3, 1,-1,-1, 1,-1, 1, 1,-1,-3,-1, 1,-1, 3,-1,-3},
{-3, 3, 3,-1,-1,-3,-1, 3, 1, 3, 1, 3, 1, 1,-1, 3, 1,-1, 1, 3,-3,-1,-1, 1},
{-3, 1, 3,-3, 1,-1,-3, 3,-3, 3,-1,-1,-1,-1, 1,-3,-3,-3, 1,-3,-3,-3, 1,-3},
{ 1, 1,-3, 3, 3,-1,-3,-1, 3,-3, 3, 3, 3,-1, 1, 1,-3, 1,-1, 1, 1,-3, 1, 1},
{-1, 1,-3,-3, 3,-1, 3,-1,-1,-3,-3,-3,-1,-3,-3, 1,-1, 1, 3, 3,-1, 1,-1, 3},
{ 1, 3, 3,-3,-3, 1, 3, 1,-1,-3,-3,-3, 3, 3,-3, 3, 3,-1,-3, 3,-1, 1,-3, 1},
{ 1, 3, 3, 1, 1, 1,-1,-1, 1,-3, 3,-1, 1, 1,-3, 3, 3,-1,-3, 3,-3,-1,-3,-1},
{ 3,-1,-1,-1,-1,-3,-1, 3, 3, 1,-1, 1, 3, 3, 3,-1, 1, 1,-3, 1, 3,-1,-3, 3},
{-3,-3, 3, 1, 3, 1,-3, 3, 1, 3, 1, 1, 3, 3,-1,-1,-3, 1,-3,-1, 3, 1, 1, 3},
{-1,-1, 1,-3, 1, 3,-3, 1,-1,-3,-1, 3, 1, 3, 1,-1,-3,-3,-1,-1,-3,-3,-3,-1},
{-1,-3, 3,-1,-1,-1,-1, 1, 1,-3, 3, 1, 3, 3, 1,-1, 1,-3, 1,-3, 1, 1,-3,-1},
{ 1, 3,-1, 3, 3,-1,-3, 1,-1,-3, 3, 3, 3,-1, 1, 1, 3,-1,-3,-1, 3,-1,-1,-1},
{ 1, 1, 1, 1, 1,-1, 3,-1,-3, 1, 1, 3,-3, 1,-3,-1, 1, 1,-3,-3, 3, 1, 1,-3},
{ 1, 3, 3, 1,-1,-3, 3,-1, 3, 3, 3,-3, 1,-1, 1,-1,-3,-1, 1, 3,-1, 3,-3,-3},
{-1,-3, 3,-3,-3,-3,-1,-1,-3,-1,-3, 3, 1, 3,-3,-1, 3,-1, 1,-1, 3,-3, 1,-1},
{-3,-3, 1, 1,-1, 1,-1, 1,-1, 3, 1,-3,-1, 1,-1, 1,-1,-1, 3, 3,-3,-1, 1,-3},
{-3,-1,-3, 3, 1,-1,-3,-1,-3,-3, 3,-3, 3,-3,-1, 1, 3, 1,-3, 1, 3, 3,-1,-3},
{-1,-1,-1,-1, 3, 3, 3, 1, 3, 3,-3, 1, 3,-1, 3,-1, 3, 3,-3, 3, 1,-1, 3, 3},
{ 1,-1, 3, 3,-1,-3, 3,-3,-1,-1, 3,-1, 3,-1,-1, 1, 1, 1, 1,-1,-1,-3,-1, 3},
{ 1,-1, 1,-1, 3,-1, 3, 1, 1,-1,-1,-3, 1, 1,-3, 1, 3,-3, 1, 1,-3,-3,-1,-1},
{-3,-1, 1, 3, 1, 1,-3,-1,-1,-3, 3,-3, 3, 1,-3, 3,-3, 1,-1, 1,-3, 1, 1, 1},
{-1,-3, 3, 3, 1, 1, 3,-1,-3,-1,-1,-1, 3, 1,-3,-3,-1, 3,-3,-1,-3,-1,-3,-1},
{-1,-3,-1,-1, 1,-3,-1,-1, 1,-1,-3, 1, 1,-3, 1,-3,-3, 3, 1, 1,-1, 3,-1,-1},
{ 1, 1,-1,-1,-3,-1, 3,-1, 3,-1, 1, 3, 1,-1, 3, 1, 3,-3,-3, 1,-1,-1, 1, 3}};
// Prime numbers used for Section 5.5.1.1 of 36.211
#define NOF_PRIME_NUMBERS 309
uint32_t prime_numbers[NOF_PRIME_NUMBERS] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997,1009,1013,
1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,
1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,
1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,
1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,
1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,
1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,
1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,
1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,
1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,
1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,
1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,
1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,
1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,
1993,1997,1999,2003,2011,2017,2027,2029,2039};

@ -20,13 +20,26 @@
#
########################################################################
# Channel Estimation TEST
# Downlink Channel Estimation TEST
########################################################################
ADD_EXECUTABLE(chest_test chest_test.c)
TARGET_LINK_LIBRARIES(chest_test lte_phy)
ADD_EXECUTABLE(chest_test_dl chest_test_dl.c)
TARGET_LINK_LIBRARIES(chest_test_dl lte_phy)
ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0)
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1)
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)
########################################################################
# Uplink Channel Estimation TEST
########################################################################
#ADD_EXECUTABLE(chest_test_ul chest_test_ul.c)
#TARGET_LINK_LIBRARIES(chest_test_ul lte_phy)
#ADD_TEST(chest_test_ul_cellid0 chest_ul_test -c 0)
#ADD_TEST(chest_test_ul_cellid1 chest_ul_test -c 1)
#ADD_TEST(chest_test_ul_cellid2 chest_ul_test -c 2)
ADD_TEST(chest_test_all_cellids chest_test)
ADD_TEST(chest_test_cellid chest_test -c 1)

@ -0,0 +1,249 @@
/**
*
* \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 <strings.h>
#include <unistd.h>
#include <complex.h>
#include "liblte/phy/phy.h"
lte_cell_t cell = {
6, // nof_prb
MAX_PORTS, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
char *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id);
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
cell.nof_prb = atoi(argv[optind]);
break;
case 'e':
cell.cp = CPEXT;
break;
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int check_mse(float mod, float arg, int n_port) {
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) {
case 0:
if (mod > 0.029) {
return -1;
}
if (arg > 0.029) {
return -1;
}
break;
case 1:
if (mod > 0.012) {
return -1;
}
if (arg > 0.012) {
return -1;
}
break;
case 2:
case 3:
if (mod > 3.33) {
return -1;
}
if (arg > 0.63) {
return -1;
}
break;
default:
return -1;
}
return 0;
}
int main(int argc, char **argv) {
chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
float mse_mag, mse_phase;
parse_args(argc,argv);
if (output_matlab) {
fmatlab=fopen(output_matlab, "w");
if (!fmatlab) {
perror("fopen");
goto do_exit;
}
}
num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
goto do_exit;
}
ce = malloc(num_re * sizeof(cf_t));
if (!ce) {
perror("malloc");
goto do_exit;
}
if (cell.id == 1000) {
cid = 0;
max_cid = 504;
} else {
cid = cell.id;
max_cid = cell.id;
}
while(cid <= max_cid) {
cell.id = cid;
if (chest_init_LTEUL(&eq, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<cell.nof_ports;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
}
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input);
for (i=0;i<CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
}
}
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
mse_mag = mse_phase = 0;
for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
}
if (check_mse(mse_mag, mse_phase, n_port)) {
goto do_exit;
}
if (fmatlab) {
fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port);
}
}
}
chest_free(&eq);
cid+=10;
INFO("cid=%d\n", cid);
}
ret = 0;
do_exit:
if (ce) {
free(ce);
}
if (input) {
free(input);
}
if (h) {
free(h);
}
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
}
exit(ret);
}

@ -25,14 +25,13 @@
*
*/
#include "liblte/phy/common/sequence.h"
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <assert.h>
#include "liblte/phy/common/sequence.h"
#define Nc 1600
@ -75,7 +74,7 @@ void generate_prs_c(sequence_t *q, uint32_t seed) {
free(x2);
}
int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) {
int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed) {
if (sequence_init(q, len)) {
return LIBLTE_ERROR;
}

@ -189,7 +189,7 @@ int main(int argc, char **argv) {
/* compute exponentially averaged execution time */
if (n > 0) {
mean_texec = EXPAVERAGE((float) t[0].tv_usec, mean_texec, n-1);
mean_texec = VEC_CMA((float) t[0].tv_usec, mean_texec, n-1);
}
/* check MSE */

@ -559,7 +559,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e,
} while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop);
q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations,
q->average_nof_iterations = VEC_CMA((float) q->nof_iterations,
q->average_nof_iterations,
q->average_nof_iterations_n);
q->average_nof_iterations_n++;

@ -35,7 +35,7 @@
*/
int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id);
return sequence_LTE_pr(seq, CP_ISNORM(cp)?1920:1728, cell_id);
}
/**
@ -43,7 +43,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) {
*/
int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
return sequence_LTE_pr(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
}
@ -52,7 +52,7 @@ int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) {
*/
int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
return sequence_LTE_pr(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
}
/**
@ -60,7 +60,7 @@ int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) {
*/
int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id);
return sequence_LTE_pr(seq, len, (nslot/2) * 512 + cell_id);
}
/**
@ -68,5 +68,5 @@ int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t l
*/
int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id);
return sequence_LTE_pr(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id);
}

@ -254,7 +254,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
#endif
/* Find maximum of the absolute value of the correlation */
corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len);
corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len-1);
if (corr_peak_value) {
*corr_peak_value = cabsf(q->conv_output[corr_peak_pos]);
}

@ -55,6 +55,7 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
bzero(q, sizeof(sync_t));
q->detect_cp = true;
q->normalize_en = true;
q->mean_energy = 1.0;
q->sss_en = true;
q->N_id_2 = 1000;
q->N_id_1 = 1000;
@ -144,6 +145,9 @@ void sync_cp_en(sync_t *q, bool enabled) {
lte_cp_t sync_get_cp(sync_t *q) {
return q->cp;
}
void sync_set_cp(sync_t *q, lte_cp_t cp) {
q->cp = cp;
}
/* CP detection algorithm taken from:
* "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
@ -183,9 +187,7 @@ static lte_cp_t detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
}
int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
uint32_t m0, m1;
int sss_idx, ret;
float m0_value, m1_value;
sss_synch_set_N_id_2(&q->sss, q->N_id_2);
@ -195,17 +197,15 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
/* Make sure we have enough room to find SSS sequence */
sss_idx = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, q->cp));
if (sss_idx < 0) {
INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos);
return LIBLTE_SUCCESS;
}
/* try Normal CP length */
sss_synch_m0m1(&q->sss, &input[sss_idx], &m0, &m0_value, &m1, &m1_value);
sss_synch_m0m1(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
q->sf_idx = sss_synch_subframe(m0, m1);
ret = sss_synch_N_id_1(&q->sss, m0, m1);
q->sf_idx = sss_synch_subframe(q->m0, q->m1);
ret = sss_synch_N_id_1(&q->sss, q->m0, q->m1);
if (ret >= 0) {
q->N_id_1 = (uint32_t) ret;
} else {
@ -223,14 +223,14 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
int ret = LIBLTE_ERROR_INVALID_INPUTS;
float peak_unnormalized, energy;
float peak_unnormalized=0, energy=1;
if (q != NULL &&
input != NULL &&
lte_N_id_2_isvalid(q->N_id_2) &&
fft_size_isvalid(q->fft_size))
{
uint32_t peak_pos;
int peak_pos;
if (peak_position) {
*peak_position = 0;
@ -239,14 +239,17 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
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 (peak_pos < 0) {
fprintf(stderr, "Error calling finding PSS sequence\n");
return LIBLTE_ERROR;
}
if (q->normalize_en &&
peak_pos + find_offset >= q->fft_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);
q->mean_energy = VEC_CMA(energy, q->mean_energy, q->frame_cnt);
} else {
if (q->mean_energy == 0.0) {
q->mean_energy = 1.0;
@ -256,7 +259,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
/* 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->mean_peak_value = VEC_CMA(q->peak_value, q->mean_peak_value, q->frame_cnt);
q->frame_cnt++;
/* If peak is over threshold, compute CFO and SSS */
@ -264,25 +267,27 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
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, find_offset + peak_pos) < 0) {
ret = sync_sss(q, input, find_offset + peak_pos);
if (ret < 0) {
fprintf(stderr, "Error synchronizing with SSS\n");
return LIBLTE_ERROR;
}
} else {
ret = 1;
}
} else {
INFO("Warning: no space for CFO computation\n",0);
}
if (peak_position) {
*peak_position = peak_pos;
*peak_position = (uint32_t) peak_pos;
}
ret = 1;
} else {
ret = LIBLTE_SUCCESS;
}
INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f energy=%.3f threshold=%.2f sf_idx=%d\n",
ret, q->N_id_2, peak_pos, q->peak_value, energy, q->threshold, q->sf_idx);
INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f threshold=%.2f sf_idx=%d offset=%d\n",
ret, q->N_id_2, peak_pos, peak_unnormalized,energy,q->peak_value, q->threshold, q->sf_idx, find_offset);
} else if (lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Must call sync_set_N_id_2() first!\n");

@ -161,7 +161,7 @@ int main(int argc, char **argv) {
fft_size);
float x = peak_value/y;
mean_peak = EXPAVERAGE(x, mean_peak, frame_cnt);
mean_peak = VEC_CMA(x, mean_peak, frame_cnt);
if (x >= threshold) {
nof_det++;

@ -109,7 +109,6 @@ void ue_celldetect_reset(ue_celldetect_t * q)
{
q->current_nof_detected = 0;
q->current_nof_total = 0;
q->current_N_id_2 = 0;
}
void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold)
@ -189,7 +188,8 @@ void decide_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell)
int ue_celldetect_scan(ue_celldetect_t * q,
cf_t *signal,
uint32_t nsamples,
ue_celldetect_result_t *found_cell)
ue_celldetect_result_t *found_cell,
uint32_t N_id_2)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t peak_idx;
@ -198,7 +198,8 @@ int ue_celldetect_scan(ue_celldetect_t * q,
if (q != NULL &&
signal != NULL &&
nsamples >= 4800)
nsamples >= 4800 &&
lte_N_id_2_isvalid(N_id_2))
{
ret = LIBLTE_SUCCESS;
@ -209,16 +210,18 @@ int ue_celldetect_scan(ue_celldetect_t * q,
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);
if (sync_set_N_id_2(&q->sfind, N_id_2)) {
return LIBLTE_ERROR;
}
INFO("[%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);
q->current_nof_detected, q->current_nof_total, 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;
return LIBLTE_ERROR;
}
/* If peak position does not allow to read SSS, return error -3 */
@ -249,17 +252,13 @@ int ue_celldetect_scan(ue_celldetect_t * q,
/* 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;
} else {
ret = 0;
}
}
}

@ -169,7 +169,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint16_t
gettimeofday(&t[2], NULL);
get_time_interval(t);
mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, mean_exec_time, frame_cnt);
mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, mean_exec_time, frame_cnt);
frame_cnt++;
for (int i=0;i<MAX_PORTS;i++) {

@ -37,7 +37,9 @@
#include "liblte/phy/utils/vector.h"
#define FIND_FFTSIZE 128
#define FIND_SFLEN 10*SF_LEN(FIND_FFTSIZE)
#define FIND_SFLEN 5*SF_LEN(FIND_FFTSIZE)
#define MIB_FIND_THRESHOLD 0.0
int ue_mib_init(ue_mib_t * q,
uint32_t cell_id,
@ -80,6 +82,8 @@ int ue_mib_init(ue_mib_t * q,
sync_set_threshold(&q->sfind, MIB_FIND_THRESHOLD);
sync_sss_en(&q->sfind, true);
sync_set_N_id_2(&q->sfind, cell_id % 3);
sync_cp_en(&q->sfind, false);
sync_set_cp(&q->sfind, cp);
if (lte_fft_init(&q->fft, cp, cell.nof_prb)) {
fprintf(stderr, "Error initializing FFT\n");
@ -137,22 +141,24 @@ void ue_mib_set_threshold(ue_mib_t * q, float threshold)
static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib)
{
int ret;
int ret = LIBLTE_SUCCESS;
/* 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) {
if (ret < 0) {
return LIBLTE_ERROR;
}
/* Reset decoder if we missed a frame */
if ((q->last_frame_trial && (q->frame_cnt - q->last_frame_trial > 2)) ||
q->frame_cnt > 10)
if ((q->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) ||
q->frame_cnt > 16)
{
ue_mib_reset(q);
INFO("Resetting PBCH decoder: last trial %u, now is %u\n",
q->last_frame_trial, q->frame_cnt);
ue_mib_reset(q);
}
/* Decode PBCH */
@ -162,14 +168,15 @@ static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib)
} else if (ret == 1) {
INFO("MIB decoded: %u\n", q->frame_cnt/2);
ue_mib_reset(q);
ret = 1;
ret = MIB_FOUND;
} else {
INFO("MIB not decoded: %u\n", q->frame_cnt / 2);
q->last_frame_trial = q->frame_cnt;
}
ret = LIBLTE_SUCCESS;
}
return ret;
}
int counter1=0,counter2=0,counter3=0,counter4=0;
int ue_mib_decode(ue_mib_t * q,
cf_t *signal,
@ -177,13 +184,18 @@ int ue_mib_decode(ue_mib_t * q,
pbch_mib_t *mib)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t peak_idx;
uint32_t peak_idx=0;
uint32_t nof_input_frames;
if (q != NULL &&
signal != NULL)
{
if (nsamples < MIB_FRAME_SIZE) {
fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE);
return LIBLTE_ERROR;
}
ret = LIBLTE_SUCCESS;
if (nsamples % MIB_FRAME_SIZE) {
@ -201,25 +213,40 @@ int ue_mib_decode(ue_mib_t * q,
return -1;
}
/* If peak position does not allow to read SSS, return error -3 */
if (ret == 0) {
counter2++;
} else if (ret == 1) {
counter4++;
}
/* Check if we have space for reading the MIB and we are in Subframe #0 */
if (ret == 1 &&
nf*MIB_FRAME_SIZE + peak_idx + 960 <= nsamples &&
sync_sss_detected(&q->sfind) &&
sync_get_sf_idx(&q->sfind) == 0)
{
INFO("Trying to decode MIB\n",0);
ret = mib_decoder_run(q, &signal[nf*MIB_FRAME_SIZE+peak_idx], mib);
counter3++;
} else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) ||
(ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 > nsamples))
{
printf("Not enough space for PBCH\n",0);
ret = MIB_FRAME_UNALIGNED;
} else {
INFO("SSS not detected\n",0);
ret = 0;
}
counter1++;
INFO("Total: %3d - Sync0: %3d - Sync1: %3d - Tried: %3d - Peak: %4d - Ret: %d\n",counter1,counter2,counter4, counter3, peak_idx, ret);
q->frame_cnt++;
}
}
return ret;
}

@ -46,7 +46,7 @@ cf_t dummy[MAX_TIME_OFFSET];
#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 FIND_THRESHOLD 1.2
#define TRACK_THRESHOLD 0.2
@ -138,7 +138,7 @@ float ue_sync_get_cfo(ue_sync_t *q) {
}
float ue_sync_get_sfo(ue_sync_t *q) {
return 1000*q->mean_time_offset/5;
return 1000*q->mean_time_offset;
}
void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
@ -179,8 +179,9 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
/* Make sure subframe idx is what we expect */
if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) {
INFO("Warning: Expected SF idx %d but got %d!\n",
q->sf_idx, sync_get_sf_idx(&q->strack));
INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n",
q->sf_idx, sync_get_sf_idx(&q->strack), q->strack.m0, q->strack.m1, q->strack.m0_value, q->strack.m1_value);
/* FIXME: What should we do in this case? */
q->sf_idx = sync_get_sf_idx(&q->strack);
q->state = SF_TRACK;
} else {
@ -196,10 +197,9 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
}
/* compute cumulative moving average CFO */
q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt);
q->cur_cfo = VEC_CMA(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->mean_time_offset = (float) VEC_CMA((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++;
@ -310,7 +310,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
#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);
q->mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt);
#endif
if (ret == 1) {

@ -169,7 +169,7 @@ int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_
return LIBLTE_ERROR;
}
n = ue_celldetect_scan(s, buffer, flen, found_cell);
n = ue_celldetect_scan(s, buffer, flen, found_cell, nof_scanned_cells);
switch(n) {
case CS_FRAME_UNALIGNED:
printf("Realigning frame\n");

Loading…
Cancel
Save