mirror of https://github.com/pvnis/srsRAN_4G.git
commit
60456d29bd
@ -0,0 +1,203 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#include "cell_search_utils.h"
|
||||
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
|
||||
|
||||
int band = -1;
|
||||
int earfcn_start=-1, earfcn_end = -1;
|
||||
int nof_frames_total = 50;
|
||||
int nof_frames_detected = 10;
|
||||
float threshold = CS_FIND_THRESHOLD;
|
||||
|
||||
|
||||
float uhd_gain = 60.0;
|
||||
char *uhd_args="";
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agsendtvb] -b band\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-s earfcn_start [Default All]\n");
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
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, "agsendtvb")) != -1) {
|
||||
switch(opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames_total = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
nof_frames_detected = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (band == -1) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int n;
|
||||
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;
|
||||
pbch_mib_t mib;
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
|
||||
nof_freqs = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
if (nof_freqs < 0) {
|
||||
fprintf(stderr, "Error getting EARFCN list\n");
|
||||
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);
|
||||
}
|
||||
if (threshold > 0) {
|
||||
ue_celldetect_set_threshold(&s, threshold);
|
||||
}
|
||||
|
||||
if (nof_frames_total > 0) {
|
||||
ue_celldetect_set_nof_frames_total(&s, nof_frames_total);
|
||||
}
|
||||
if (nof_frames_detected > 0) {
|
||||
ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected);
|
||||
}
|
||||
|
||||
for (freq=0;freq<nof_freqs;freq+=10) {
|
||||
|
||||
/* set uhd_freq */
|
||||
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
usleep(10000);
|
||||
INFO("Set uhd_freq to %.3f MHz\n", (double) channels[freq].fd * MHZ/1000000);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
n = find_cell(uhd, &s, buffer, found_cells);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error searching cell\n");
|
||||
exit(-1);
|
||||
}
|
||||
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)) {
|
||||
fprintf(stderr, "Error decoding PBCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ue_celldetect_free(&s);
|
||||
cuhd_close(uhd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,157 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
|
||||
{
|
||||
ue_mib_t uemib;
|
||||
int n;
|
||||
|
||||
bzero(mib, sizeof(pbch_mib_t));
|
||||
|
||||
uint32_t nof_frames = 0;
|
||||
uint32_t flen = MIB_FRAME_SIZE;
|
||||
|
||||
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
|
||||
fprintf(stderr, "Error initiating PBCH decoder\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0);
|
||||
cuhd_set_rx_srate(uhd, 1920000.0);
|
||||
INFO("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
do {
|
||||
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
|
||||
|
||||
n = ue_mib_decode(&uemib, buffer, flen, mib);
|
||||
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling ue_mib_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
if (n == MIB_FRAME_UNALIGNED) {
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
nof_frames++;
|
||||
} while (n != MIB_FOUND && nof_frames < 2*nof_frames_total);
|
||||
if (n == MIB_FOUND) {
|
||||
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
|
||||
pbch_mib_fprint(stdout, mib, found_cell->cell_id);
|
||||
} else {
|
||||
printf("\nCould not decode MIB\n");
|
||||
}
|
||||
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
ue_mib_free(&uemib);
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3])
|
||||
{
|
||||
int n;
|
||||
|
||||
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
|
||||
cuhd_set_rx_srate(uhd, 960000.0);
|
||||
INFO("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
uint32_t nof_scanned_cells = 0;
|
||||
uint32_t flen = 4800;
|
||||
int nof_detected_cells = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]);
|
||||
switch(n) {
|
||||
case CS_FRAME_UNALIGNED:
|
||||
printf("Realigning frame\n");
|
||||
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
|
||||
fprintf(stderr, "Error receiving from USRP\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
return LIBLTE_ERROR;
|
||||
case CS_CELL_DETECTED:
|
||||
nof_detected_cells++;
|
||||
if (found_cell[nof_scanned_cells].peak > 0) {
|
||||
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
|
||||
found_cell[nof_scanned_cells].cell_id,
|
||||
lte_cp_string(found_cell[nof_scanned_cells].cp),
|
||||
found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode,
|
||||
s->nof_frames_detected);
|
||||
}
|
||||
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case CS_CELL_NOT_DETECTED:
|
||||
nof_scanned_cells++;
|
||||
break;
|
||||
case LIBLTE_ERROR:
|
||||
case LIBLTE_ERROR_INVALID_INPUTS:
|
||||
fprintf(stderr, "Error calling cellsearch_scan()\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
} while(nof_scanned_cells < 3);
|
||||
|
||||
INFO("Stopping receiver...\n", 0);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
cuhd_flush_buffer(uhd);
|
||||
|
||||
return nof_detected_cells;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
int decode_pbch(void *uhd,
|
||||
cf_t *buffer,
|
||||
ue_celldetect_result_t *found_cell,
|
||||
uint32_t nof_frames_total,
|
||||
pbch_mib_t *mib);
|
||||
|
||||
int find_cell(void *uhd,
|
||||
ue_celldetect_t *s,
|
||||
cf_t *buffer,
|
||||
ue_celldetect_result_t found_cell[3]);
|
@ -0,0 +1,254 @@
|
||||
/**
|
||||
*
|
||||
* \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 <unistd.h>
|
||||
|
||||
#include "iodev.h"
|
||||
|
||||
#include "liblte/phy/io/filesource.h"
|
||||
#include "liblte/phy/ue/ue_sync.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
#include "cell_search_utils.h"
|
||||
|
||||
|
||||
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
|
||||
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
|
||||
return cuhd_recv(h, data, nsamples, 1);
|
||||
}
|
||||
|
||||
/* Setup USRP or input file */
|
||||
int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) {
|
||||
|
||||
if (config->input_file_name) {
|
||||
|
||||
mib->phich_resources = R_1;
|
||||
mib->phich_length = PHICH_NORM;
|
||||
|
||||
cell->id = config->cell_id_file;
|
||||
cell->cp = CPNORM;
|
||||
cell->nof_ports = config->nof_ports_file;
|
||||
cell->nof_prb = config->nof_prb_file;
|
||||
|
||||
if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
q->mode = FILESOURCE;
|
||||
int symbol_sz = lte_symbol_sz(cell->nof_prb);
|
||||
if (symbol_sz > 0) {
|
||||
q->sf_len = SF_LEN(symbol_sz);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
q->input_buffer_file = vec_malloc(q->sf_len * sizeof(cf_t));
|
||||
if (!q->input_buffer_file) {
|
||||
perror("malloc");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
q->sf_idx = 9;
|
||||
|
||||
} else {
|
||||
#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;
|
||||
}
|
||||
|
||||
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");
|
||||
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)) {
|
||||
fprintf(stderr, "Error initiating ue_sync\n");
|
||||
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;
|
||||
|
||||
#else
|
||||
printf("Error UHD not available. Select an input file\n");
|
||||
return LIBLTE_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(&q->config, config, sizeof(iodev_cfg_t));
|
||||
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void iodev_free(iodev_t *q) {
|
||||
|
||||
if (q->mode == FILESOURCE) {
|
||||
filesource_free(&q->fsrc);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(q->uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Receive samples from the USRP or read from file */
|
||||
int iodev_receive(iodev_t *q, cf_t **buffer) {
|
||||
int n;
|
||||
if (q->mode == FILESOURCE) {
|
||||
INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len);
|
||||
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
|
||||
*buffer = q->input_buffer_file;
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
/* wrap file if arrive to end */
|
||||
} else if (n < q->sf_len) {
|
||||
DEBUG("Read %d from file. Seeking to 0\n",n);
|
||||
filesource_seek(&q->fsrc, 0);
|
||||
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
/* wrap file if arrive to end */
|
||||
} else {
|
||||
n = 1;
|
||||
}
|
||||
} else {
|
||||
n = 1;
|
||||
}
|
||||
q->sf_idx++;
|
||||
if (q->sf_idx == 10) {
|
||||
q->sf_idx = 0;
|
||||
}
|
||||
usleep(5000);
|
||||
} else {
|
||||
/* Use ue_sync_work which returns a synchronized buffer of subframe samples */
|
||||
#ifndef DISABLE_UHD
|
||||
n = ue_sync_get_buffer(&q->sframe, buffer);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error calling ue_sync_work()\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void* iodev_get_cuhd(iodev_t *q) {
|
||||
if (q->mode == UHD) {
|
||||
return q->uhd;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool iodev_isfile(iodev_t *q) {
|
||||
return q->mode == FILESOURCE;
|
||||
}
|
||||
|
||||
bool iodev_isUSRP(iodev_t *q) {
|
||||
return q->mode == UHD;
|
||||
}
|
||||
|
||||
uint32_t iodev_get_sfidx(iodev_t *q) {
|
||||
if (iodev_isfile(q)) {
|
||||
return q->sf_idx;
|
||||
} else {
|
||||
return ue_sync_get_sfidx(&q->sframe);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,99 @@
|
||||
/**
|
||||
*
|
||||
* \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 IODEF_H
|
||||
#define IODEF_H
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
#include "liblte/phy/ue/ue_sync.h"
|
||||
#include "liblte/phy/io/filesource.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
/*********
|
||||
*
|
||||
* This component is a wrapper to the cuhd or filesource modules. It uses
|
||||
* sync_frame_t to read aligned subframes from the USRP or filesource to read
|
||||
* subframes from a file.
|
||||
*
|
||||
* When created, it starts receiving/reading at 1.92 MHz. The sampling frequency
|
||||
* can then be changed using iodev_set_srate()
|
||||
*/
|
||||
|
||||
|
||||
typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t;
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
char *input_file_name;
|
||||
uint32_t cell_id_file;
|
||||
uint32_t nof_prb_file;
|
||||
uint32_t nof_ports_file;
|
||||
|
||||
float uhd_freq;
|
||||
float uhd_gain;
|
||||
char *uhd_args;
|
||||
float find_threshold;
|
||||
} iodev_cfg_t;
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
#ifndef DISABLE_UHD
|
||||
void *uhd;
|
||||
ue_sync_t sframe;
|
||||
#endif
|
||||
uint32_t sf_len;
|
||||
uint32_t sf_idx;
|
||||
cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t
|
||||
filesource_t fsrc;
|
||||
iodev_cfg_t config;
|
||||
iodev_mode_t mode;
|
||||
} iodev_t;
|
||||
|
||||
|
||||
LIBLTE_API int iodev_init(iodev_t *q,
|
||||
iodev_cfg_t *config,
|
||||
lte_cell_t *cell,
|
||||
pbch_mib_t *mib);
|
||||
|
||||
LIBLTE_API void iodev_free(iodev_t *q);
|
||||
|
||||
LIBLTE_API int iodev_receive(iodev_t *q,
|
||||
cf_t **buffer);
|
||||
|
||||
LIBLTE_API void* iodev_get_cuhd(iodev_t *q);
|
||||
|
||||
LIBLTE_API uint32_t iodev_get_sfidx(iodev_t *q);
|
||||
|
||||
LIBLTE_API bool iodev_isfile(iodev_t *q);
|
||||
|
||||
LIBLTE_API bool iodev_isUSRP(iodev_t *q);
|
||||
|
||||
#endif
|
@ -1,283 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
char *output_file_name = NULL;
|
||||
int nof_frames=-1;
|
||||
int cell_id = 1;
|
||||
int nof_prb = 6;
|
||||
char *uhd_args = "";
|
||||
|
||||
float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000;
|
||||
|
||||
filesink_t fsink;
|
||||
lte_fft_t ifft;
|
||||
pbch_t pbch;
|
||||
|
||||
cf_t *slot_buffer = NULL, *output_buffer = NULL;
|
||||
int slot_n_re, slot_n_samples;
|
||||
|
||||
#define UHD_SAMP_FREQ 1920000
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agmfoncvp]\n", prog);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp);
|
||||
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-o output_file [Default USRP]\n");
|
||||
printf("\t-n number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-c cell id [Default %d]\n", cell_id);
|
||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'm':
|
||||
uhd_amp = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#ifdef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void base_init() {
|
||||
/* init memory */
|
||||
slot_buffer = malloc(sizeof(cf_t) * slot_n_re);
|
||||
if (!slot_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
output_buffer = malloc(sizeof(cf_t) * slot_n_samples);
|
||||
if (!output_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
/* open file or USRP */
|
||||
if (output_file_name) {
|
||||
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", output_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args,&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an output file\n");
|
||||
exit(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* create ifft object */
|
||||
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
pbch_free(&pbch);
|
||||
|
||||
lte_ifft_free(&ifft);
|
||||
|
||||
if (slot_buffer) {
|
||||
free(slot_buffer);
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
}
|
||||
if (output_file_name) {
|
||||
filesink_free(&fsink);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(&uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nf, ns, N_id_2;
|
||||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
pbch_mib_t mib;
|
||||
refsignal_t refs[NSLOTS_X_FRAME];
|
||||
int i;
|
||||
cf_t *slot1_symbols[MAX_PORTS_CTRL];
|
||||
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
N_id_2 = cell_id%3;
|
||||
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
|
||||
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
|
||||
|
||||
/* this *must* be called after setting slot_len_* */
|
||||
base_init();
|
||||
|
||||
/* Generate PSS/SSS signals */
|
||||
pss_generate(pss_signal, N_id_2);
|
||||
sss_generate(sss_signal0, sss_signal5, cell_id);
|
||||
|
||||
/* Generate CRS signals */
|
||||
for (i=0;i<NSLOTS_X_FRAME;i++) {
|
||||
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mib.nof_ports = 1;
|
||||
mib.nof_prb = 6;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
mib.phich_resources = R_1;
|
||||
mib.sfn = 0;
|
||||
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
|
||||
slot1_symbols[i] = slot_buffer;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000);
|
||||
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
|
||||
printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
nf = 0;
|
||||
|
||||
while(nf<nof_frames || nof_frames == -1) {
|
||||
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
||||
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
|
||||
|
||||
switch(ns) {
|
||||
case 0: // tx pss/sss
|
||||
case 10: // tx pss/sss
|
||||
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
|
||||
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
|
||||
break;
|
||||
case 1: // tx pbch
|
||||
pbch_encode(&pbch, &mib, slot1_symbols, 1);
|
||||
break;
|
||||
default: // transmit zeros
|
||||
break;
|
||||
}
|
||||
|
||||
refsignal_put(&refs[ns], slot_buffer);
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
lte_ifft_run(&ifft, slot_buffer, output_buffer);
|
||||
|
||||
/* send to file or usrp */
|
||||
if (output_file_name) {
|
||||
filesink_write(&fsink, output_buffer, slot_n_samples);
|
||||
usleep(5000);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
|
||||
cuhd_send(uhd, output_buffer, slot_n_samples, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mib.sfn=(mib.sfn+1)%1024;
|
||||
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
|
||||
nf++;
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -1,501 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
#include "liblte/graphics/plot.h"
|
||||
plot_real_t poutfft;
|
||||
plot_complex_t pce;
|
||||
plot_scatter_t pscatrecv, pscatequal;
|
||||
#endif
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define NOF_PORTS 2
|
||||
|
||||
float find_threshold = 20.0, track_threshold = 10.0;
|
||||
int max_track_lost = 20, nof_frames = -1;
|
||||
int track_len=300;
|
||||
char *input_file_name = NULL;
|
||||
int disable_plots = 0;
|
||||
|
||||
int go_exit=0;
|
||||
|
||||
float uhd_freq = 2600000000.0, uhd_gain = 20.0;
|
||||
char *uhd_args = "";
|
||||
|
||||
filesource_t fsrc;
|
||||
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
|
||||
pbch_t pbch;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
sync_t sfind, strack;
|
||||
cfo_t cfocorr;
|
||||
|
||||
|
||||
enum sync_state {FIND, TRACK};
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [iagfndvp]\n", prog);
|
||||
printf("\t-i input_file [Default use USRP]\n");
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-n nof_frames [Default %d]\n", nof_frames);
|
||||
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
printf("\t-d disable plots [Default enabled]\n");
|
||||
#else
|
||||
printf("\t plots are disabled. Graphics library not available\n");
|
||||
#endif
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "iagfndvp")) != -1) {
|
||||
switch(opt) {
|
||||
case 'i':
|
||||
input_file_name = 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 'p':
|
||||
find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
disable_plots = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
|
||||
void init_plots() {
|
||||
plot_init();
|
||||
plot_real_init(&poutfft);
|
||||
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
|
||||
plot_real_setLabels(&poutfft, "Index", "dB");
|
||||
plot_real_setYAxisScale(&poutfft, -60, 0);
|
||||
plot_real_setXAxisScale(&poutfft, 1, 504);
|
||||
|
||||
plot_complex_init(&pce);
|
||||
plot_complex_setTitle(&pce, "Channel Estimates");
|
||||
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
|
||||
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
|
||||
|
||||
plot_scatter_init(&pscatrecv);
|
||||
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
|
||||
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
|
||||
|
||||
plot_scatter_init(&pscatequal);
|
||||
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
|
||||
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int base_init(int frame_length) {
|
||||
int i;
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!disable_plots) {
|
||||
init_plots();
|
||||
}
|
||||
#else
|
||||
printf("-- PLOTS are disabled. Graphics library not available --\n\n");
|
||||
#endif
|
||||
|
||||
if (input_file_name) {
|
||||
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* open UHD device */
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args,&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an input file\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!fft_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (sync_init(&sfind, FLEN)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (sync_init(&strack, track_len)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cfo_init(&cfocorr, FLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lte_fft_init(&fft, CPNORM, 6)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
int i;
|
||||
|
||||
if (input_file_name) {
|
||||
filesource_free(&fsrc);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(uhd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
plot_exit();
|
||||
#endif
|
||||
|
||||
sync_free(&sfind);
|
||||
sync_free(&strack);
|
||||
lte_fft_free(&fft);
|
||||
chest_free(&chest);
|
||||
cfo_free(&cfocorr);
|
||||
|
||||
free(input_buffer);
|
||||
free(fft_buffer);
|
||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||
free(ce[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mib_decoder_init(int cell_id) {
|
||||
|
||||
if (chest_ref_LTEDL(&chest, cell_id)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
|
||||
int i, n;
|
||||
lte_fft_run(&fft, input, fft_buffer);
|
||||
|
||||
/* Get channel estimates for each port */
|
||||
for (i=0;i<NOF_PORTS;i++) {
|
||||
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
|
||||
}
|
||||
|
||||
DEBUG("Decoding PBCH\n", 0);
|
||||
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
|
||||
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
float tmp[72*7];
|
||||
if (!disable_plots) {
|
||||
for (i=0;i<72*7;i++) {
|
||||
tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp, 72*7);
|
||||
plot_complex_setNewData(&pce, ce[0], 72*7);
|
||||
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
|
||||
if (n) {
|
||||
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void sigintHandler(int sig_num)
|
||||
{
|
||||
go_exit=1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt;
|
||||
int cell_id;
|
||||
int find_idx, track_idx, last_found;
|
||||
enum sync_state state;
|
||||
int nslot;
|
||||
pbch_mib_t mib;
|
||||
float cfo;
|
||||
int n;
|
||||
int nof_found_mib = 0;
|
||||
float timeoffset = 0;
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init(FLEN)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sync_pss_det_peak_to_avg(&sfind);
|
||||
sync_pss_det_peak_to_avg(&strack);
|
||||
|
||||
if (!input_file_name) {
|
||||
#ifndef DISABLE_UHD
|
||||
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
cuhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
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);
|
||||
|
||||
DEBUG("Starting receiver...\n",0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("\n --- Press Ctrl+C to exit --- \n");
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
||||
state = FIND;
|
||||
nslot = 0;
|
||||
find_idx = 0;
|
||||
cfo = 0;
|
||||
mib.sfn = -1;
|
||||
frame_cnt = 0;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&sfind, find_threshold);
|
||||
sync_force_N_id_2(&sfind, -1);
|
||||
|
||||
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
|
||||
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
|
||||
if (input_file_name) {
|
||||
n = filesource_read(&fsrc, input_buffer, FLEN);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
exit(-1);
|
||||
} else if (n < FLEN) {
|
||||
filesource_seek(&fsrc, 0);
|
||||
filesource_read(&fsrc, input_buffer, FLEN);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
switch(state) {
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_run(&sfind, input_buffer);
|
||||
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
|
||||
if (find_idx != -1) {
|
||||
/* if found peak, go to track and set track threshold */
|
||||
cell_id = sync_get_cell_id(&sfind);
|
||||
if (cell_id != -1) {
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&strack, track_threshold);
|
||||
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
|
||||
sync_force_cp(&strack, sync_get_cp(&sfind));
|
||||
mib_decoder_init(cell_id);
|
||||
nof_found_mib = 0;
|
||||
nslot = sync_get_slot_id(&sfind);
|
||||
nslot=(nslot+10)%20;
|
||||
cfo = 0;
|
||||
timeoffset = 0;
|
||||
printf("\n");
|
||||
state = TRACK;
|
||||
} else {
|
||||
printf("cellid=-1\n");
|
||||
}
|
||||
}
|
||||
if (verbose == VERBOSE_NONE) {
|
||||
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
|
||||
}
|
||||
break;
|
||||
case TRACK:
|
||||
/* Find peak around known position find_idx */
|
||||
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
|
||||
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
|
||||
|
||||
if (track_idx != -1) {
|
||||
/* compute cumulative moving average CFO */
|
||||
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
|
||||
/* compute cumulative moving average time offset */
|
||||
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
|
||||
last_found = frame_cnt;
|
||||
find_idx = (find_idx + track_idx - track_len)%FLEN;
|
||||
if (nslot != sync_get_slot_id(&strack)) {
|
||||
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
state = FIND;
|
||||
}
|
||||
} else {
|
||||
/* if sync not found, adjust time offset with the averaged value */
|
||||
find_idx = (find_idx + (int) timeoffset)%FLEN;
|
||||
}
|
||||
|
||||
/* if we missed too many PSS go back to FIND */
|
||||
if (frame_cnt - last_found > max_track_lost) {
|
||||
INFO("%d frames lost. Going back to FIND", frame_cnt - last_found);
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
state = FIND;
|
||||
}
|
||||
|
||||
// Correct CFO
|
||||
INFO("Correcting CFO=%.4f\n", cfo);
|
||||
|
||||
cfo_correct(&cfocorr, input_buffer, -cfo/128);
|
||||
|
||||
if (nslot == 0 && find_idx + 960 < FLEN) {
|
||||
INFO("Finding MIB at idx %d\n", find_idx);
|
||||
if (mib_decoder_run(&input_buffer[find_idx], &mib)) {
|
||||
INFO("MIB detected attempt=%d\n", frame_cnt);
|
||||
if (verbose == VERBOSE_NONE) {
|
||||
if (!nof_found_mib) {
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
printf("\r\n");
|
||||
printf(" - Phy. CellId:\t%d\n", cell_id);
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
}
|
||||
}
|
||||
nof_found_mib++;
|
||||
} else {
|
||||
INFO("MIB not found attempt %d\n",frame_cnt);
|
||||
}
|
||||
if (frame_cnt) {
|
||||
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn,
|
||||
cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt,
|
||||
(float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
if (input_file_name) {
|
||||
usleep(5000);
|
||||
}
|
||||
nslot = (nslot+10)%20;
|
||||
break;
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -0,0 +1,393 @@
|
||||
/**
|
||||
*
|
||||
* \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 "liblte/phy/phy.h"
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
void *uhd;
|
||||
#endif
|
||||
|
||||
char *output_file_name = NULL;
|
||||
|
||||
lte_cell_t cell = {
|
||||
6, // nof_prb
|
||||
1, // nof_ports
|
||||
1, // cell_id
|
||||
CPNORM // cyclic prefix
|
||||
};
|
||||
|
||||
uint32_t cfi=1;
|
||||
uint32_t mcs_idx = 12;
|
||||
int nof_frames = -1;
|
||||
|
||||
char *uhd_args = "";
|
||||
float uhd_amp = 0.01, uhd_gain = 10.0, uhd_freq = 2400000000;
|
||||
|
||||
filesink_t fsink;
|
||||
lte_fft_t ifft;
|
||||
pbch_t pbch;
|
||||
pcfich_t pcfich;
|
||||
pdcch_t pdcch;
|
||||
pdsch_t pdsch;
|
||||
pdsch_harq_t harq_process;
|
||||
regs_t regs;
|
||||
|
||||
cf_t *sf_buffer = NULL, *output_buffer = NULL;
|
||||
int sf_n_re, sf_n_samples;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [agmfoncvp]\n", prog);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", uhd_args);
|
||||
printf("\t-l UHD amplitude [Default %.2f]\n", uhd_amp);
|
||||
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq / 1000000);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
printf("\t-o output_file [Default USRP]\n");
|
||||
printf("\t-m MCS index [Default %d]\n", mcs_idx);
|
||||
printf("\t-n number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-c cell id [Default %d]\n", cell.id);
|
||||
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "aglfmoncpv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
uhd_amp = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
break;
|
||||
case 'm':
|
||||
mcs_idx = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
cell.nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell.id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
#ifdef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void base_init() {
|
||||
|
||||
/* init memory */
|
||||
sf_buffer = malloc(sizeof(cf_t) * sf_n_re);
|
||||
if (!sf_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
output_buffer = malloc(sizeof(cf_t) * sf_n_samples);
|
||||
if (!output_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
/* open file or USRP */
|
||||
if (output_file_name) {
|
||||
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
|
||||
fprintf(stderr, "Error opening file %s\n", output_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open(uhd_args, &uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
printf("Error UHD not available. Select an output file\n");
|
||||
exit(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* create ifft object */
|
||||
if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) {
|
||||
fprintf(stderr, "Error creating iFFT object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pbch_init(&pbch, cell)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (regs_init(®s, R_1, PHICH_NORM, cell)) {
|
||||
fprintf(stderr, "Error initiating regs\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pcfich_init(&pcfich, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PBCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (regs_set_cfi(®s, cfi)) {
|
||||
fprintf(stderr, "Error setting CFI\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdcch_init(&pdcch, ®s, cell)) {
|
||||
fprintf(stderr, "Error creating PDCCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdsch_init(&pdsch, cell)) {
|
||||
fprintf(stderr, "Error creating PDSCH object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pdsch_set_rnti(&pdsch, 1234);
|
||||
|
||||
if (pdsch_harq_init(&harq_process, &pdsch)) {
|
||||
fprintf(stderr, "Error initiating HARQ process\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
pdsch_harq_free(&harq_process);
|
||||
pdsch_free(&pdsch);
|
||||
pdcch_free(&pdcch);
|
||||
regs_free(®s);
|
||||
pbch_free(&pbch);
|
||||
|
||||
lte_ifft_free(&ifft);
|
||||
|
||||
if (sf_buffer) {
|
||||
free(sf_buffer);
|
||||
}
|
||||
if (output_buffer) {
|
||||
free(output_buffer);
|
||||
}
|
||||
if (output_file_name) {
|
||||
filesink_free(&fsink);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(&uhd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int nf, sf_idx, N_id_2;
|
||||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
pbch_mib_t mib;
|
||||
ra_pdsch_t ra_dl;
|
||||
ra_prb_t prb_alloc;
|
||||
refsignal_t refs[NSLOTS_X_FRAME];
|
||||
int i, n;
|
||||
char *data;
|
||||
cf_t *sf_symbols[MAX_PORTS];
|
||||
dci_msg_t dci_msg;
|
||||
dci_location_t locations[NSUBFRAMES_X_FRAME][10];
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc, 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(lte_symbol_sz(cell.nof_prb));
|
||||
|
||||
/* this *must* be called after setting slot_len_* */
|
||||
base_init();
|
||||
|
||||
/* Generate PSS/SSS signals */
|
||||
pss_generate(pss_signal, N_id_2);
|
||||
sss_generate(sss_signal0, sss_signal5, cell.id);
|
||||
|
||||
/* Generate CRS signals */
|
||||
for (i = 0; i < NSLOTS_X_FRAME; i++) {
|
||||
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
|
||||
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mib.nof_ports = cell.nof_ports;
|
||||
mib.nof_prb = cell.nof_prb;
|
||||
mib.phich_length = PHICH_NORM;
|
||||
mib.phich_resources = R_1;
|
||||
mib.sfn = 0;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
|
||||
sf_symbols[i] = sf_buffer;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
if (!output_file_name) {
|
||||
printf("Set TX rate: %.2f MHz\n",
|
||||
cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 1000000);
|
||||
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
|
||||
printf("Set TX freq: %.2f MHz\n",
|
||||
cuhd_set_tx_freq(uhd, uhd_freq) / 1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
bzero(&ra_dl, sizeof(ra_pdsch_t));
|
||||
ra_dl.harq_process = 0;
|
||||
ra_dl.mcs_idx = mcs_idx;
|
||||
ra_dl.ndi = 0;
|
||||
ra_dl.rv_idx = 0;
|
||||
ra_dl.alloc_type = alloc_type0;
|
||||
ra_dl.type0_alloc.rbg_bitmask = 0xffffffff;
|
||||
|
||||
dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false);
|
||||
|
||||
ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
|
||||
ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
|
||||
ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs);
|
||||
|
||||
ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
|
||||
|
||||
/* Initiate valid DCI locations */
|
||||
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
|
||||
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234);
|
||||
}
|
||||
|
||||
data = malloc(sizeof(char) * ra_dl.mcs.tbs);
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
nf = 0;
|
||||
|
||||
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while (nf < nof_frames || nof_frames == -1) {
|
||||
for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
|
||||
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
|
||||
|
||||
if (sf_idx == 0 || sf_idx == 5) {
|
||||
pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
|
||||
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
|
||||
CPNORM);
|
||||
}
|
||||
|
||||
if (sf_idx == 0) {
|
||||
pbch_encode(&pbch, &mib, sf_symbols);
|
||||
}
|
||||
|
||||
for (n=0;n<2;n++) {
|
||||
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
|
||||
}
|
||||
|
||||
pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
|
||||
|
||||
INFO("SF: %d, Generating %d random bits\n", sf_idx, ra_dl.mcs.tbs);
|
||||
for (i=0;i<ra_dl.mcs.tbs;i++) {
|
||||
data[i] = rand()%2;
|
||||
}
|
||||
|
||||
INFO("Puttting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
|
||||
if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) {
|
||||
fprintf(stderr, "Error encoding DCI message\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx)) {
|
||||
fprintf(stderr, "Error encoding PDSCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
|
||||
|
||||
/* send to file or usrp */
|
||||
if (output_file_name) {
|
||||
filesink_write(&fsink, output_buffer, sf_n_samples);
|
||||
usleep(5000);
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples);
|
||||
cuhd_send(uhd, output_buffer, sf_n_samples, true);
|
||||
#endif
|
||||
}
|
||||
nf++;
|
||||
}
|
||||
mib.sfn = (mib.sfn + 1) % 1024;
|
||||
printf("SFN: %4d\r", mib.sfn);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,306 @@
|
||||
/**
|
||||
*
|
||||
* \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 "iodev.h"
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
void init_plots();
|
||||
void do_plots(ue_dl_t *q, uint32_t sf_idx);
|
||||
#endif
|
||||
|
||||
int go_exit = 0;
|
||||
|
||||
/* Local function definitions */
|
||||
void init_plots();
|
||||
|
||||
/**********************************************************************
|
||||
* Program arguments processing
|
||||
***********************************************************************/
|
||||
typedef struct {
|
||||
uint16_t rnti;
|
||||
int nof_subframes;
|
||||
bool disable_plots;
|
||||
iodev_cfg_t io_config;
|
||||
}prog_args_t;
|
||||
|
||||
void args_default(prog_args_t *args) {
|
||||
args->io_config.cell_id_file = 195;
|
||||
args->io_config.nof_prb_file = 50;
|
||||
args->io_config.nof_ports_file = 2;
|
||||
args->rnti = SIRNTI;
|
||||
args->nof_subframes = -1;
|
||||
args->disable_plots = false;
|
||||
args->io_config.find_threshold = -1.0;
|
||||
args->io_config.input_file_name = NULL;
|
||||
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("\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);
|
||||
printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti);
|
||||
#ifndef DISABLE_UHD
|
||||
printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args);
|
||||
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain);
|
||||
#else
|
||||
printf("\t UHD is disabled. CUHD library not available\n");
|
||||
#endif
|
||||
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);
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
printf("\t-d disable plots [Default enabled]\n");
|
||||
#else
|
||||
printf("\t plots are disabled. Graphics library not available\n");
|
||||
#endif
|
||||
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, "icagfndvtbpro")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
args->io_config.input_file_name = argv[optind];
|
||||
break;
|
||||
case 'c':
|
||||
args->io_config.cell_id_file = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
args->io_config.nof_prb_file = atoi(argv[optind]);
|
||||
break;
|
||||
case 'o':
|
||||
args->io_config.nof_ports_file = atoi(argv[optind]);
|
||||
break;
|
||||
case 'a':
|
||||
args->io_config.uhd_args = argv[optind];
|
||||
break;
|
||||
case 'g':
|
||||
args->io_config.uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
args->io_config.uhd_freq = atof(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
args->io_config.find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
args->nof_subframes = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
args->rnti= atoi(argv[optind]);
|
||||
break;
|
||||
case 'd':
|
||||
args->disable_plots = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(args, argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
|
||||
usage(args, argv[0]);
|
||||
}
|
||||
}
|
||||
/**********************************************************************/
|
||||
|
||||
void sigintHandler(int x) {
|
||||
go_exit = 1;
|
||||
}
|
||||
|
||||
/* TODO: Do something with the output data */
|
||||
char data[10000];
|
||||
|
||||
extern float mean_exec_time;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
cf_t *sf_buffer;
|
||||
iodev_t iodev;
|
||||
prog_args_t prog_args;
|
||||
lte_cell_t cell;
|
||||
ue_dl_t ue_dl;
|
||||
int64_t sf_cnt;
|
||||
pbch_mib_t mib;
|
||||
bool printed_sib = false;
|
||||
int rlen;
|
||||
|
||||
parse_args(&prog_args, argc, argv);
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!prog_args.disable_plots) {
|
||||
init_plots();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup SIGINT handler */
|
||||
printf("\n --- Press Ctrl+C to exit --- \n");
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
||||
/* Initialize subframe counter */
|
||||
sf_cnt = 0;
|
||||
|
||||
if (iodev_init(&iodev, &prog_args.io_config, &cell, &mib)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) {
|
||||
fprintf(stderr, "Error initiating UE downlink processing module\n");
|
||||
exit(-1);
|
||||
}
|
||||
pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti);
|
||||
|
||||
/* Main loop */
|
||||
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
|
||||
|
||||
ret = iodev_receive(&iodev, &sf_buffer);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error reading from input device (%d)\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
|
||||
if (ret == 1) {
|
||||
rlen = ue_dl_decode(&ue_dl, sf_buffer, data, iodev_get_sfidx(&iodev), prog_args.rnti);
|
||||
if (rlen < 0) {
|
||||
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
|
||||
exit(-1);
|
||||
}
|
||||
if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) {
|
||||
printf("\n\nDecoded SIB1 Message: ");
|
||||
vec_fprint_hex(stdout, data, rlen);
|
||||
printf("\n");fflush(stdout);
|
||||
printed_sib = true;
|
||||
}
|
||||
|
||||
// Plot and Printf
|
||||
if (!(sf_cnt % 10)) {
|
||||
printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d/%4d, BLER: %.1e, Texec: %.2f\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, (int) ue_dl.nof_trials,
|
||||
(float) ue_dl.pkt_errors / ue_dl.pkts_total,
|
||||
mean_exec_time);
|
||||
}
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!prog_args.disable_plots && iodev_get_sfidx(&iodev) == 5) {
|
||||
do_plots(&ue_dl, 5);
|
||||
}
|
||||
#endif
|
||||
} else if (ret == 0) {
|
||||
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
|
||||
sync_get_peak_value(&iodev.sframe.sfind),
|
||||
iodev.sframe.frame_total_cnt, iodev.sframe.state);
|
||||
}
|
||||
sf_cnt++;
|
||||
} // Main loop
|
||||
|
||||
ue_dl_free(&ue_dl);
|
||||
iodev_free(&iodev);
|
||||
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Plotting Functions
|
||||
***********************************************************************/
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
|
||||
|
||||
#include "liblte/graphics/plot.h"
|
||||
plot_real_t poutfft;
|
||||
plot_complex_t pce;
|
||||
plot_scatter_t pscatrecv, pscatequal;
|
||||
|
||||
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
|
||||
|
||||
void init_plots() {
|
||||
plot_init();
|
||||
plot_real_init(&poutfft);
|
||||
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
|
||||
plot_real_setLabels(&poutfft, "Index", "dB");
|
||||
plot_real_setYAxisScale(&poutfft, -30, 20);
|
||||
|
||||
plot_complex_init(&pce);
|
||||
plot_complex_setTitle(&pce, "Channel Estimates");
|
||||
plot_complex_setYAxisScale(&pce, Ip, -3, 3);
|
||||
plot_complex_setYAxisScale(&pce, Q, -3, 3);
|
||||
plot_complex_setYAxisScale(&pce, Magnitude, 0, 4);
|
||||
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
|
||||
|
||||
plot_scatter_init(&pscatrecv);
|
||||
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatrecv, -4, 4);
|
||||
plot_scatter_setYAxisScale(&pscatrecv, -4, 4);
|
||||
|
||||
plot_scatter_init(&pscatequal);
|
||||
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
|
||||
plot_scatter_setXAxisScale(&pscatequal, -2, 2);
|
||||
plot_scatter_setYAxisScale(&pscatequal, -2, 2);
|
||||
}
|
||||
|
||||
void do_plots(ue_dl_t *q, uint32_t sf_idx) {
|
||||
int i;
|
||||
uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp);
|
||||
uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx];
|
||||
for (i = 0; i < nof_re; i++) {
|
||||
tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i]));
|
||||
if (isinf(tmp_plot[i])) {
|
||||
tmp_plot[i] = -80;
|
||||
}
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp_plot, nof_re);
|
||||
plot_complex_setNewData(&pce, q->ce[0], nof_re);
|
||||
plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols);
|
||||
plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,559 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
|
||||
//#define DISABLE_UHD
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
#endif
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define RSSI_FS 1000000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define RSSI_DECIM 20
|
||||
|
||||
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
|
||||
|
||||
int band, earfcn=-1;
|
||||
float find_threshold = 10.0, track_threshold = 8.0;
|
||||
int earfcn_start=-1, earfcn_end = -1;
|
||||
float rssi_threshold = -45.0;
|
||||
int max_track_lost=9;
|
||||
int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000;
|
||||
int track_len=500;
|
||||
|
||||
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS];
|
||||
pbch_t pbch;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
sync_t sfind, strack;
|
||||
cfo_t cfocorr;
|
||||
|
||||
float *cfo_v;
|
||||
int *idx_v, *idx_valid, *t;
|
||||
float *p2a_v;
|
||||
void *uhd;
|
||||
int nof_bands;
|
||||
float uhd_gain = 20.0;
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
float rssi[MAX_EARFCN];
|
||||
float rssi_d[MAX_EARFCN/RSSI_DECIM];
|
||||
float freqs[MAX_EARFCN];
|
||||
float cfo[MAX_EARFCN];
|
||||
float p2a[MAX_EARFCN];
|
||||
|
||||
enum sync_state {INIT, FIND, TRACK, MIB, DONE};
|
||||
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
|
||||
printf("\t-s earfcn_start [Default All]\n");
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
|
||||
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
|
||||
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
|
||||
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
|
||||
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
|
||||
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
|
||||
printf("\t-l pss_track_len [Default %d]\n", track_len);
|
||||
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'R':
|
||||
nof_samples_rssi = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rssi_threshold = -atof(argv[optind]);
|
||||
break;
|
||||
case 'F':
|
||||
nof_frames_find = atoi(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'T':
|
||||
nof_frames_track = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
track_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int base_init(int frame_length) {
|
||||
int i;
|
||||
|
||||
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!fft_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;i<MAX_PORTS;i++) {
|
||||
ce[i] = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
|
||||
if (!ce[i]) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (sync_init(&sfind, FLEN)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (sync_init(&strack, track_len)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lte_fft_init(&fft, CPNORM, 6)) {
|
||||
fprintf(stderr, "Error initializing FFT\n");
|
||||
return -1;
|
||||
}
|
||||
if (cfo_init(&cfocorr, FLEN)) {
|
||||
fprintf(stderr, "Error initiating CFO\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
idx_v = malloc(nof_frames_track * sizeof(int));
|
||||
if (!idx_v) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
idx_valid = malloc(nof_frames_track * sizeof(int));
|
||||
if (!idx_valid) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
t = malloc(nof_frames_track * sizeof(int));
|
||||
if (!t) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
cfo_v = malloc(nof_frames_track * sizeof(float));
|
||||
if (!cfo_v) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
p2a_v = malloc(nof_frames_track * sizeof(float));
|
||||
if (!p2a_v) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(cfo, sizeof(float) * MAX_EARFCN);
|
||||
bzero(p2a, sizeof(float) * MAX_EARFCN);
|
||||
|
||||
/* open UHD device */
|
||||
#ifndef DISABLE_UHD
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open("",&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
int i;
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_close(uhd);
|
||||
#endif
|
||||
|
||||
sync_free(&sfind);
|
||||
sync_free(&strack);
|
||||
lte_fft_free(&fft);
|
||||
chest_free(&chest);
|
||||
cfo_free(&cfocorr);
|
||||
|
||||
free(input_buffer);
|
||||
free(fft_buffer);
|
||||
for (i=0;i<MAX_PORTS;i++) {
|
||||
free(ce[i]);
|
||||
}
|
||||
free(idx_v);
|
||||
free(idx_valid);
|
||||
free(t);
|
||||
free(cfo_v);
|
||||
free(p2a_v);
|
||||
}
|
||||
|
||||
float mean_valid(int *idx_v, float *x, int nof_frames) {
|
||||
int i;
|
||||
float mean = 0;
|
||||
int n = 0;
|
||||
for (i=0;i<nof_frames;i++) {
|
||||
if (idx_v[i] != -1) {
|
||||
mean += x[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
return mean/n;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
int preprocess_idx(int *in, int *out, int *period, int len) {
|
||||
int i, n;
|
||||
n=0;
|
||||
for (i=0;i<len;i++) {
|
||||
if (in[i] != -1) {
|
||||
out[n] = in[i];
|
||||
period[n] = i;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int rssi_scan() {
|
||||
int n=0;
|
||||
int i;
|
||||
|
||||
if (nof_bands > 100) {
|
||||
/* scan every Mhz, that is 10 freqs */
|
||||
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
|
||||
freqs[n] = channels[i].fd * MHZ;
|
||||
n++;
|
||||
}
|
||||
#ifndef DISABLE_UHD
|
||||
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
|
||||
fprintf(stderr, "Error while doing RSSI scan\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
/* linearly interpolate the rssi vector */
|
||||
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
|
||||
} else {
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
freqs[i] = channels[i].fd * MHZ;
|
||||
}
|
||||
#ifndef DISABLE_UHD
|
||||
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
|
||||
fprintf(stderr, "Error while doing RSSI scan\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
n = nof_bands;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int mib_decoder_init(int cell_id) {
|
||||
|
||||
if (chest_ref_LTEDL(&chest, cell_id)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
|
||||
int i;
|
||||
lte_fft_run(&fft, input, fft_buffer);
|
||||
|
||||
/* Get channel estimates for each port */
|
||||
for (i=0;i<MAX_PORTS;i++) {
|
||||
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
|
||||
}
|
||||
|
||||
DEBUG("Decoding PBCH\n", 0);
|
||||
return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt, valid_frames;
|
||||
int freq;
|
||||
int cell_id;
|
||||
float max_peak_to_avg;
|
||||
float sfo;
|
||||
int find_idx, track_idx, last_found;
|
||||
enum sync_state state;
|
||||
int n;
|
||||
int mib_attempts;
|
||||
int nslot;
|
||||
pbch_mib_t mib;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init(FLEN)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sync_pss_det_peak_to_avg(&sfind);
|
||||
sync_pss_det_peak_to_avg(&strack);
|
||||
|
||||
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
|
||||
|
||||
n = rssi_scan();
|
||||
if (n == -1) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("\nDone. Starting PSS search on %d channels\n", n);
|
||||
usleep(500000);
|
||||
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
#endif
|
||||
|
||||
freq=0;
|
||||
state = INIT;
|
||||
nslot = 0;
|
||||
sfo = 0;
|
||||
find_idx = 0;
|
||||
frame_cnt = 0;
|
||||
max_peak_to_avg = -1;
|
||||
last_found = 0;
|
||||
cell_id = 0;
|
||||
|
||||
while(freq<nof_bands) {
|
||||
/* scan only bands above rssi_threshold */
|
||||
if (!IS_SIGNAL(freq)) {
|
||||
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
|
||||
freq++;
|
||||
} else {
|
||||
if (state != INIT && state != DONE) {
|
||||
#ifndef DISABLE_UHD
|
||||
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
|
||||
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
|
||||
#endif
|
||||
}
|
||||
switch(state) {
|
||||
case INIT:
|
||||
DEBUG("Stopping receiver...\n",0);
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
|
||||
/* set freq */
|
||||
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
|
||||
|
||||
DEBUG("Starting receiver...\n",0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
#endif
|
||||
/* init variables */
|
||||
frame_cnt = 0;
|
||||
max_peak_to_avg = -1;
|
||||
cell_id = -1;
|
||||
|
||||
/* receive first frame */
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
#endif
|
||||
/* set find_threshold and go to FIND state */
|
||||
sync_set_threshold(&sfind, find_threshold);
|
||||
sync_force_N_id_2(&sfind, -1);
|
||||
state = FIND;
|
||||
break;
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
|
||||
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
|
||||
if (find_idx != -1) {
|
||||
/* if found peak, go to track and set lower threshold */
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
max_peak_to_avg = -1;
|
||||
sync_set_threshold(&strack, track_threshold);
|
||||
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
|
||||
cell_id = sync_get_cell_id(&sfind);
|
||||
|
||||
state = TRACK;
|
||||
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,
|
||||
10*log10f(sync_get_peak_to_avg(&sfind)));
|
||||
} else {
|
||||
if (frame_cnt >= nof_frames_find) {
|
||||
state = INIT;
|
||||
freq++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TRACK:
|
||||
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len);
|
||||
|
||||
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
|
||||
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
|
||||
|
||||
/* save cell id for the best peak-to-avg */
|
||||
if (p2a_v[frame_cnt] > max_peak_to_avg) {
|
||||
max_peak_to_avg = p2a_v[frame_cnt];
|
||||
cell_id = sync_get_cell_id(&strack);
|
||||
}
|
||||
if (track_idx != -1) {
|
||||
cfo_v[frame_cnt] = sync_get_cfo(&strack);
|
||||
last_found = frame_cnt;
|
||||
find_idx += track_idx - track_len;
|
||||
idx_v[frame_cnt] = find_idx;
|
||||
nslot = sync_get_slot_id(&strack);
|
||||
} else {
|
||||
idx_v[frame_cnt] = -1;
|
||||
cfo_v[frame_cnt] = 0.0;
|
||||
}
|
||||
/* if we missed to many PSS it is not a cell, next freq */
|
||||
if (frame_cnt - last_found > max_track_lost) {
|
||||
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
|
||||
|
||||
state = INIT;
|
||||
freq++;
|
||||
} else if (frame_cnt >= nof_frames_track) {
|
||||
mib_decoder_init(cell_id);
|
||||
|
||||
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
|
||||
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
|
||||
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
|
||||
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
|
||||
|
||||
state = MIB;
|
||||
nslot=(nslot+10)%20;
|
||||
}
|
||||
break;
|
||||
case MIB:
|
||||
INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot);
|
||||
|
||||
// TODO: Correct SFO
|
||||
|
||||
// Correct CFO
|
||||
INFO("Correcting CFO=%.4f\n", cfo[freq]);
|
||||
cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128);
|
||||
|
||||
if (nslot == 0) {
|
||||
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {
|
||||
INFO("MIB detected attempt=%d\n", mib_attempts);
|
||||
state = DONE;
|
||||
} else {
|
||||
INFO("MIB not detected attempt=%d\n", mib_attempts);
|
||||
if (mib_attempts == 0) {
|
||||
freq++;
|
||||
state = INIT;
|
||||
}
|
||||
}
|
||||
mib_attempts++;
|
||||
}
|
||||
nslot = (nslot+10)%20;
|
||||
|
||||
|
||||
break;
|
||||
case DONE:
|
||||
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
|
||||
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,
|
||||
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
state = INIT;
|
||||
freq++;
|
||||
break;
|
||||
}
|
||||
|
||||
/** FIXME: This is not necessary at all */
|
||||
if (state == TRACK || state == FIND) {
|
||||
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("\n\nDone\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -1,509 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define RSSI_FS 1000000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define RSSI_DECIM 20
|
||||
|
||||
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
|
||||
|
||||
|
||||
int band, earfcn=-1;
|
||||
float find_threshold = 10.0, track_threshold = 8.0;
|
||||
int earfcn_start=-1, earfcn_end = -1;
|
||||
float rssi_threshold = -45.0;
|
||||
int max_track_lost=9;
|
||||
int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000;
|
||||
int track_len=500;
|
||||
|
||||
cf_t *input_buffer;
|
||||
float *cfo_v;
|
||||
int *idx_v, *idx_valid, *t;
|
||||
float *p2a_v;
|
||||
void *uhd;
|
||||
int nof_bands;
|
||||
float uhd_gain = 20.0;
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
float rssi[MAX_EARFCN];
|
||||
float rssi_d[MAX_EARFCN/RSSI_DECIM];
|
||||
float freqs[MAX_EARFCN];
|
||||
float cfo[MAX_EARFCN];
|
||||
float p2a[MAX_EARFCN];
|
||||
|
||||
enum sync_state {INIT, FIND, TRACK, DONE};
|
||||
|
||||
void print_to_matlab();
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
|
||||
printf("\t-s earfcn_start [Default All]\n");
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
|
||||
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
|
||||
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
|
||||
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
|
||||
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
|
||||
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
|
||||
printf("\t-l pss_track_len [Default %d]\n", track_len);
|
||||
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'R':
|
||||
nof_samples_rssi = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rssi_threshold = -atof(argv[optind]);
|
||||
break;
|
||||
case 'F':
|
||||
nof_frames_find = atoi(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
find_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'T':
|
||||
nof_frames_track = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
track_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'g':
|
||||
uhd_gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int base_init(int frame_length) {
|
||||
|
||||
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
idx_v = malloc(nof_frames_track * sizeof(int));
|
||||
if (!idx_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
idx_valid = malloc(nof_frames_track * sizeof(int));
|
||||
if (!idx_valid) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
t = malloc(nof_frames_track * sizeof(int));
|
||||
if (!t) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
cfo_v = malloc(nof_frames_track * sizeof(float));
|
||||
if (!cfo_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
p2a_v = malloc(nof_frames_track * sizeof(float));
|
||||
if (!p2a_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bzero(cfo, sizeof(float) * MAX_EARFCN);
|
||||
bzero(p2a, sizeof(float) * MAX_EARFCN);
|
||||
|
||||
/* open UHD device */
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open("",&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
cuhd_close(uhd);
|
||||
free(input_buffer);
|
||||
free(idx_v);
|
||||
free(idx_valid);
|
||||
free(t);
|
||||
free(cfo_v);
|
||||
free(p2a_v);
|
||||
}
|
||||
|
||||
float mean_valid(int *idx_v, float *x, int nof_frames) {
|
||||
int i;
|
||||
float mean = 0;
|
||||
int n = 0;
|
||||
for (i=0;i<nof_frames;i++) {
|
||||
if (idx_v[i] != -1) {
|
||||
mean += x[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
return mean/n;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
int preprocess_idx(int *in, int *out, int *period, int len) {
|
||||
int i, n;
|
||||
n=0;
|
||||
for (i=0;i<len;i++) {
|
||||
if (in[i] != -1) {
|
||||
out[n] = in[i];
|
||||
period[n] = i;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int rssi_scan() {
|
||||
int n=0;
|
||||
int i;
|
||||
|
||||
if (nof_bands > 100) {
|
||||
/* scan every Mhz, that is 10 freqs */
|
||||
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
|
||||
freqs[n] = channels[i].fd * MHZ;
|
||||
n++;
|
||||
}
|
||||
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
|
||||
fprintf(stderr, "Error while doing RSSI scan\n");
|
||||
return -1;
|
||||
}
|
||||
/* linearly interpolate the rssi vector */
|
||||
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
|
||||
} else {
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
freqs[i] = channels[i].fd * MHZ;
|
||||
}
|
||||
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
|
||||
fprintf(stderr, "Error while doing RSSI scan\n");
|
||||
return -1;
|
||||
}
|
||||
n = nof_bands;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt, valid_frames;
|
||||
int freq;
|
||||
int cell_id;
|
||||
sync_t sfind, strack;
|
||||
float max_peak_to_avg;
|
||||
float sfo;
|
||||
int find_idx, track_idx, last_found;
|
||||
enum sync_state state;
|
||||
int n;
|
||||
filesink_t fs;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init(FLEN)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sync_init(&sfind, FLEN)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
sync_pss_det_peak_to_avg(&sfind);
|
||||
|
||||
if (sync_init(&strack, track_len)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
sync_pss_det_peak_to_avg(&strack);
|
||||
|
||||
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
|
||||
|
||||
n = rssi_scan();
|
||||
if (n == -1) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("\nDone. Starting PSS search on %d channels\n", n);
|
||||
usleep(500000);
|
||||
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
cuhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
|
||||
print_to_matlab();
|
||||
|
||||
filesink_init(&fs, "test.dat", COMPLEX_FLOAT_BIN);
|
||||
|
||||
freq=0;
|
||||
state = INIT;
|
||||
find_idx = 0;
|
||||
max_peak_to_avg = 0;
|
||||
last_found = 0;
|
||||
frame_cnt = 0;
|
||||
while(freq<nof_bands) {
|
||||
/* scan only bands above rssi_threshold */
|
||||
if (!IS_SIGNAL(freq)) {
|
||||
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
|
||||
freq++;
|
||||
} else {
|
||||
if (state == TRACK || state == FIND) {
|
||||
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
|
||||
}
|
||||
switch(state) {
|
||||
case INIT:
|
||||
DEBUG("Stopping receiver...\n",0);
|
||||
cuhd_stop_rx_stream(uhd);
|
||||
|
||||
/* set freq */
|
||||
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
|
||||
|
||||
DEBUG("Starting receiver...\n",0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
|
||||
/* init variables */
|
||||
frame_cnt = 0;
|
||||
max_peak_to_avg = -99;
|
||||
cell_id = -1;
|
||||
|
||||
/* receive first frame */
|
||||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
|
||||
/* set find_threshold and go to FIND state */
|
||||
sync_set_threshold(&sfind, find_threshold);
|
||||
sync_force_N_id_2(&sfind, -1);
|
||||
state = FIND;
|
||||
break;
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
|
||||
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
|
||||
if (find_idx != -1) {
|
||||
/* if found peak, go to track and set lower threshold */
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&strack, track_threshold);
|
||||
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
|
||||
state = TRACK;
|
||||
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,
|
||||
10*log10f(sync_get_peak_to_avg(&sfind)));
|
||||
} else {
|
||||
if (frame_cnt >= nof_frames_find) {
|
||||
state = INIT;
|
||||
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz No PSS found\r", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("\n");
|
||||
}
|
||||
freq++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TRACK:
|
||||
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len);
|
||||
|
||||
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
|
||||
|
||||
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
|
||||
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
|
||||
|
||||
/* save cell id for the best peak-to-avg */
|
||||
if (p2a_v[frame_cnt] > max_peak_to_avg) {
|
||||
max_peak_to_avg = p2a_v[frame_cnt];
|
||||
cell_id = sync_get_cell_id(&strack);
|
||||
}
|
||||
if (track_idx != -1) {
|
||||
cfo_v[frame_cnt] = sync_get_cfo(&strack);
|
||||
last_found = frame_cnt;
|
||||
find_idx += track_idx - track_len;
|
||||
idx_v[frame_cnt] = find_idx;
|
||||
} else {
|
||||
idx_v[frame_cnt] = -1;
|
||||
cfo_v[frame_cnt] = 0.0;
|
||||
}
|
||||
/* if we missed to many PSS it is not a cell, next freq */
|
||||
if (frame_cnt - last_found > max_track_lost) {
|
||||
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
|
||||
|
||||
state = INIT;
|
||||
freq++;
|
||||
} else if (frame_cnt >= nof_frames_track) {
|
||||
state = DONE;
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
|
||||
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
|
||||
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
|
||||
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
|
||||
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
|
||||
|
||||
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
|
||||
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,
|
||||
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
|
||||
state = INIT;
|
||||
freq++;
|
||||
break;
|
||||
}
|
||||
if (state == TRACK || (state == FIND && frame_cnt)) {
|
||||
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
print_to_matlab();
|
||||
|
||||
sync_free(&sfind);
|
||||
base_free();
|
||||
|
||||
printf("\n\nDone\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void print_to_matlab() {
|
||||
int i;
|
||||
|
||||
FILE *f = fopen("output.m", "w");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(f, "fd=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", channels[i].fd);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
fprintf(f, "rssi=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", rssi[i]);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
|
||||
fprintf(f, "rssi_d=[");
|
||||
for (i=0;i<nof_bands/RSSI_DECIM;i++) {
|
||||
fprintf(f, "%g, ", rssi_d[i]);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
/*
|
||||
fprintf(f, "cfo=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
if (IS_SIGNAL(i)) {
|
||||
fprintf(f, "%g, ", cfo[i]);
|
||||
} else {
|
||||
fprintf(f, "NaN, ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
*/
|
||||
fprintf(f, "p2a=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
if (IS_SIGNAL(i)) {
|
||||
fprintf(f, "%g, ", p2a[i]);
|
||||
} else {
|
||||
fprintf(f, "0, ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
fprintf(f, "clf;\n\n");
|
||||
fprintf(f, "subplot(1,2,1)\n");
|
||||
fprintf(f, "plot(fd, 10*log10(rssi)+30)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('RSSI [dBm]');\n");
|
||||
fprintf(f, "title('RSSI Estimation')\n");
|
||||
|
||||
fprintf(f, "subplot(1,2,2)\n");
|
||||
fprintf(f, "plot(fd, p2a)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('Peak-to-Avg [dB]');\n");
|
||||
fprintf(f, "title('PSS Correlation')\n");
|
||||
/*
|
||||
fprintf(f, "subplot(1,3,3)\n");
|
||||
fprintf(f, "plot(fd, cfo)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel(''); axis([min(fd) max(fd) -0.5 0.5]);\n");
|
||||
fprintf(f, "title('CFO Estimation')\n");
|
||||
*/
|
||||
fprintf(f, "drawnow;\n");
|
||||
fclose(f);
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "liblte/phy/phy.h"
|
||||
#include "liblte/cuhd/cuhd.h"
|
||||
|
||||
int nof_frames=1000;
|
||||
int band;
|
||||
|
||||
cf_t *input_buffer, *fft_buffer;
|
||||
void *uhd;
|
||||
int earfcn_start = -1, earfcn_end = -1;
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [nvse] -b band\n", prog);
|
||||
printf("\t-s earfcn_start [Default All]\n");
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
printf("\t-n number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "sebnv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_frames = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int base_init() {
|
||||
|
||||
input_buffer = malloc(4 * 960 * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* open UHD device */
|
||||
printf("Opening UHD device...\n");
|
||||
if (cuhd_open("",&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
cuhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
|
||||
printf("Starting receiver...\n");
|
||||
cuhd_start_rx_stream(uhd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt;
|
||||
int i;
|
||||
int nsamples;
|
||||
float rssi[MAX_EARFCN];
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init()) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
printf("Scanning %d freqs in band %d\n", nof_bands, band);
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
cuhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
|
||||
frame_cnt = 0;
|
||||
nsamples=0;
|
||||
rssi[i]=0;
|
||||
while(frame_cnt < nof_frames) {
|
||||
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
|
||||
rssi[i] += vec_avg_power_cf(input_buffer, 1920);
|
||||
frame_cnt++;
|
||||
}
|
||||
printf("[%3d/%d]: Scanning earfcn %d freq %.2f MHz RSSI %.2f dBm\n", i, nof_bands,
|
||||
channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30);
|
||||
}
|
||||
|
||||
FILE *f = fopen("output.m", "w");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(f, "fd=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", channels[i].fd);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
fprintf(f, "rssi=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", rssi[i]);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
fprintf(f, "plot(fd/1000, 10*log10(rssi)+30)\ngrid on\nxlabel('f_d [Ghz]')\nylabel('RSSI [dBm]')\n");
|
||||
fclose(f);
|
||||
|
||||
free(input_buffer);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
*
|
||||
* \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 AGC_
|
||||
#define AGC_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
/* Automatic Gain Control
|
||||
*
|
||||
*/
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
#define AGC_DEFAULT_BW (5e-2)
|
||||
|
||||
typedef struct LIBLTE_API{
|
||||
float bandwidth;
|
||||
float gain;
|
||||
float y_out;
|
||||
bool lock;
|
||||
bool isfirst;
|
||||
} agc_t;
|
||||
|
||||
LIBLTE_API int agc_init (agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_free(agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_reset(agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_set_bandwidth(agc_t *q,
|
||||
float bandwidth);
|
||||
|
||||
LIBLTE_API float agc_get_rssi(agc_t *q);
|
||||
|
||||
LIBLTE_API float agc_get_output_level(agc_t *q);
|
||||
|
||||
LIBLTE_API float agc_get_gain(agc_t *q);
|
||||
|
||||
LIBLTE_API void agc_lock(agc_t *q,
|
||||
bool enable);
|
||||
|
||||
LIBLTE_API void agc_process(agc_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t len);
|
||||
|
||||
#endif // AGC_
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
*
|
||||
* \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 DECIM_H
|
||||
#define DECIM_H_
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
|
||||
LIBLTE_API void decim_c(cf_t *input, cf_t *output, int M, int len);
|
||||
LIBLTE_API void decim_f(float *input, float *output, int M, int len);
|
||||
|
||||
#endif // DECIM_H
|
@ -0,0 +1,131 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2014 The libLTE Developers. See the
|
||||
* COPYRIGHT file at the top-level directory of this distribution.
|
||||
*
|
||||
* \section LICENSE
|
||||
*
|
||||
* This file is part of the libLTE library.
|
||||
*
|
||||
* libLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* libLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Lesser General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UE_CELLSEARCH_
|
||||
#define UE_CELLSEARCH_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "liblte/config.h"
|
||||
#include "liblte/phy/sync/sync.h"
|
||||
#include "liblte/phy/sync/cfo.h"
|
||||
#include "liblte/phy/ch_estimation/chest.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
|
||||
/************************************************************
|
||||
*
|
||||
* This object scans a signal for LTE cells using the known PSS
|
||||
* and SSS sequences.
|
||||
*
|
||||
* The function ue_celldetect_scan() shall be called multiple times,
|
||||
* each passing a number of samples multiple of 4800, sampled at 960 KHz
|
||||
* (that is, 5 ms of samples).
|
||||
*
|
||||
* The function returns 0 until a signal is found nof_frames_detected times or
|
||||
* after nof_frames_total with no signal detected.
|
||||
*
|
||||
* See ue_cell_detect.c for an example.
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
/**
|
||||
* TODO: Check also peak offset
|
||||
*/
|
||||
|
||||
#define CS_DEFAULT_MAXFRAMES_TOTAL 300
|
||||
#define CS_DEFAULT_MAXFRAMES_DETECTED 30
|
||||
|
||||
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
|
||||
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
|
||||
|
||||
#define CS_FIND_THRESHOLD 0.6
|
||||
|
||||
#define CS_FRAME_UNALIGNED -3
|
||||
#define CS_CELL_DETECTED 2
|
||||
#define CS_CELL_NOT_DETECTED 3
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
uint32_t cell_id;
|
||||
lte_cp_t cp;
|
||||
float peak;
|
||||
uint32_t mode;
|
||||
} ue_celldetect_result_t;
|
||||
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t sfind;
|
||||
uint32_t max_frames_total;
|
||||
uint32_t max_frames_detected;
|
||||
uint32_t nof_frames_total;
|
||||
uint32_t nof_frames_detected;
|
||||
|
||||
uint32_t current_nof_detected;
|
||||
uint32_t current_nof_total;
|
||||
|
||||
uint32_t current_N_id_2;
|
||||
|
||||
uint32_t *mode_ntimes;
|
||||
char *mode_counted;
|
||||
|
||||
ue_celldetect_result_t *candidates;
|
||||
} ue_celldetect_t;
|
||||
|
||||
|
||||
LIBLTE_API int ue_celldetect_init(ue_celldetect_t *q);
|
||||
|
||||
LIBLTE_API int ue_celldetect_init_max(ue_celldetect_t *q,
|
||||
uint32_t max_frames_total,
|
||||
uint32_t max_frames_detected);
|
||||
|
||||
LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q);
|
||||
|
||||
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
|
||||
|
||||
LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q,
|
||||
cf_t *signal,
|
||||
uint32_t nsamples,
|
||||
ue_celldetect_result_t *found_cell);
|
||||
|
||||
LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q,
|
||||
uint32_t nof_frames);
|
||||
|
||||
LIBLTE_API int ue_celldetect_set_nof_frames_detected(ue_celldetect_t *q,
|
||||
uint32_t nof_frames);
|
||||
|
||||
LIBLTE_API void ue_celldetect_set_threshold(ue_celldetect_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -0,0 +1,99 @@
|
||||
/**
|
||||
*
|
||||
* \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 UEDL_H
|
||||
#define UEDL_H
|
||||
|
||||
/*******************************************************
|
||||
*
|
||||
* This module is a frontend to all the data and control channels processing
|
||||
* modules.
|
||||
********************************************************/
|
||||
|
||||
|
||||
|
||||
#include "liblte/phy/ch_estimation/chest.h"
|
||||
#include "liblte/phy/common/fft.h"
|
||||
#include "liblte/phy/common/phy_common.h"
|
||||
|
||||
#include "liblte/phy/phch/dci.h"
|
||||
#include "liblte/phy/phch/pbch.h"
|
||||
#include "liblte/phy/phch/pcfich.h"
|
||||
#include "liblte/phy/phch/pdcch.h"
|
||||
#include "liblte/phy/phch/pdsch.h"
|
||||
#include "liblte/phy/phch/phich.h"
|
||||
#include "liblte/phy/phch/ra.h"
|
||||
#include "liblte/phy/phch/regs.h"
|
||||
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
#include "liblte/config.h"
|
||||
|
||||
#define NOF_HARQ_PROCESSES 8
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
pbch_t pbch;
|
||||
pcfich_t pcfich;
|
||||
pdcch_t pdcch;
|
||||
pdsch_t pdsch;
|
||||
pdsch_harq_t harq_process[NOF_HARQ_PROCESSES];
|
||||
regs_t regs;
|
||||
lte_fft_t fft;
|
||||
chest_t chest;
|
||||
|
||||
lte_cell_t cell;
|
||||
|
||||
cf_t *sf_symbols;
|
||||
cf_t *ce[MAX_PORTS];
|
||||
|
||||
uint64_t pkt_errors;
|
||||
uint64_t pkts_total;
|
||||
uint64_t nof_trials;
|
||||
|
||||
uint32_t sfn;
|
||||
bool pbch_decoded;
|
||||
|
||||
uint16_t user_rnti;
|
||||
}ue_dl_t;
|
||||
|
||||
/* This function shall be called just after the initial synchronization */
|
||||
LIBLTE_API int ue_dl_init(ue_dl_t *q,
|
||||
lte_cell_t cell,
|
||||
phich_resources_t phich_resources,
|
||||
phich_length_t phich_length,
|
||||
uint16_t user_rnti);
|
||||
|
||||
LIBLTE_API void ue_dl_free(ue_dl_t *q);
|
||||
|
||||
LIBLTE_API int ue_dl_decode(ue_dl_t *q,
|
||||
cf_t *sf_buffer,
|
||||
char *data,
|
||||
uint32_t sf_idx,
|
||||
uint16_t rnti);
|
||||
|
||||
#endif
|
@ -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_
|
||||
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
*
|
||||
* \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_SYNC_
|
||||
#define UE_SYNC_
|
||||
|
||||
#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 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 1 when the signal is correctly acquired and the
|
||||
* returned buffer is aligned with the subframe.
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
|
||||
|
||||
#define TRACK_MAX_LOST 10
|
||||
#define MEASURE_EXEC_TIME
|
||||
|
||||
typedef struct LIBLTE_API {
|
||||
sync_t sfind;
|
||||
sync_t strack;
|
||||
|
||||
void *stream;
|
||||
int (*recv_callback)(void*, void*, uint32_t);
|
||||
|
||||
ue_sync_state_t state;
|
||||
|
||||
cf_t *input_buffer;
|
||||
|
||||
/* These count half frames (5ms) */
|
||||
uint64_t frame_ok_cnt;
|
||||
uint32_t frame_no_cnt;
|
||||
uint32_t frame_total_cnt;
|
||||
|
||||
/* this is the system frame number (SFN) */
|
||||
uint32_t frame_number;
|
||||
|
||||
lte_cell_t cell;
|
||||
uint32_t sf_idx;
|
||||
|
||||
cfo_t cfocorr;
|
||||
float cur_cfo;
|
||||
|
||||
bool decode_sss_on_track;
|
||||
|
||||
uint32_t peak_idx;
|
||||
int time_offset;
|
||||
float mean_time_offset;
|
||||
#ifdef MEASURE_EXEC_TIME
|
||||
float mean_exec_time;
|
||||
#endif
|
||||
} ue_sync_t;
|
||||
|
||||
|
||||
LIBLTE_API int ue_sync_init(ue_sync_t *q,
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
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_reset(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API void ue_sync_decode_sss_on_track(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 float ue_sync_get_cfo(ue_sync_t *q);
|
||||
|
||||
LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYNC_FRAME_
|
||||
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
*
|
||||
* \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 <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
#include "liblte/phy/agc/agc.h"
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
|
||||
int agc_init (agc_t *q) {
|
||||
bzero(q, sizeof(agc_t));
|
||||
agc_reset(q);
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void agc_free(agc_t *q) {
|
||||
bzero(q, sizeof(agc_t));
|
||||
}
|
||||
|
||||
void agc_reset(agc_t *q) {
|
||||
q->bandwidth = AGC_DEFAULT_BW;
|
||||
q->lock = false;
|
||||
q->gain = 1.0;
|
||||
q->y_out = 1.0;
|
||||
q->isfirst = true;
|
||||
}
|
||||
|
||||
void agc_set_bandwidth(agc_t *q, float bandwidth) {
|
||||
q->bandwidth = bandwidth;
|
||||
}
|
||||
|
||||
float agc_get_rssi(agc_t *q) {
|
||||
return 1.0/q->gain;
|
||||
}
|
||||
|
||||
float agc_get_output_level(agc_t *q) {
|
||||
return q->y_out;
|
||||
}
|
||||
|
||||
float agc_get_gain(agc_t *q) {
|
||||
return q->gain;
|
||||
}
|
||||
|
||||
|
||||
void agc_lock(agc_t *q, bool enable) {
|
||||
q->lock = enable;
|
||||
}
|
||||
|
||||
void agc_process(agc_t *q, cf_t *input, cf_t *output, uint32_t len) {
|
||||
|
||||
// Apply current gain to input signal
|
||||
vec_sc_prod_cfc(input, q->gain, output, len);
|
||||
|
||||
// compute output energy estimate
|
||||
float y = sqrtf(crealf(vec_dot_prod_conj_ccc(output, output, len))/len);
|
||||
|
||||
if (q->isfirst) {
|
||||
q->y_out = y;
|
||||
q->gain = 1/y;
|
||||
q->isfirst = false;
|
||||
} else {
|
||||
q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y;
|
||||
if (!q->lock) {
|
||||
q->gain *= expf(-0.5*q->bandwidth*logf(q->y_out));
|
||||
}
|
||||
}
|
||||
DEBUG("AGC gain: %.3f y_out=%.3f, y=%.3f\n", q->gain, q->y_out, y);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue