mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
418 lines
9.8 KiB
C
418 lines
9.8 KiB
C
/**
|
|
*
|
|
* \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>
|
|
|
|
#ifndef DISABLE_UHD
|
|
#include "cuhd.h"
|
|
#endif
|
|
|
|
#include "lte.h"
|
|
#include "plot.h"
|
|
|
|
#define MHZ 1000000
|
|
#define SAMP_FREQ 1920000
|
|
#define FLEN 9600
|
|
#define FLEN_PERIOD 0.005
|
|
|
|
#define NOF_PORTS 2
|
|
|
|
float freq = 2680000000.0;
|
|
float find_threshold = 40.0, track_threshold = 8.0;
|
|
int max_track_lost = 9, nof_frames = -1;
|
|
int track_len=300;
|
|
char *input_file_name = NULL;
|
|
int disable_plots = 0;
|
|
|
|
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;
|
|
|
|
plot_real_t poutfft;
|
|
plot_complex_t pce;
|
|
plot_scatter_t pscatrecv, pscatequal;
|
|
|
|
void *uhd;
|
|
float gain = 30.0;
|
|
|
|
enum sync_state {FIND, TRACK};
|
|
|
|
void usage(char *prog) {
|
|
printf("Usage: %s [ifgv]\n", prog);
|
|
printf("\t-i input_file [Default use USRP]\n");
|
|
printf("\t-n nof_frames [Default %d]\n", nof_frames);
|
|
printf("\t-d disable plots [Default enabled]\n");
|
|
printf("\t-f freq [Default %.1f MHz]\n", freq/MHZ);
|
|
printf("\t-g gain [Default %.2f dB]\n", 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, "ifdgv")) != -1) {
|
|
switch(opt) {
|
|
case 'i':
|
|
input_file_name = argv[optind];
|
|
break;
|
|
case 'f':
|
|
freq = atof(argv[optind]);
|
|
break;
|
|
case 'g':
|
|
gain = atof(argv[optind]);
|
|
break;
|
|
case 'd':
|
|
disable_plots = 1;
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
default:
|
|
usage(argv[0]);
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
int base_init(int frame_length) {
|
|
int i;
|
|
|
|
if (!disable_plots) {
|
|
init_plots();
|
|
}
|
|
|
|
if (input_file_name) {
|
|
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
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 (lte_fft_init(&fft, CPNORM, 6)) {
|
|
fprintf(stderr, "Error initializing FFT\n");
|
|
return -1;
|
|
}
|
|
|
|
/* open UHD device */
|
|
#ifndef DISABLE_UHD
|
|
printf("Opening UHD device...\n");
|
|
if (cuhd_open("addr=192.168.10.2",&uhd)) {
|
|
fprintf(stderr, "Error opening uhd\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void base_free() {
|
|
int i;
|
|
|
|
#ifndef DISABLE_UHD
|
|
cuhd_close(&uhd);
|
|
#endif
|
|
|
|
if (input_file_name) {
|
|
filesource_free(&fsrc);
|
|
}
|
|
|
|
sync_free(&sfind);
|
|
sync_free(&strack);
|
|
lte_fft_free(&fft);
|
|
chest_free(&chest);
|
|
|
|
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, 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);
|
|
float tmp[72*7];
|
|
|
|
/* 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, 6, 1, mib);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
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 nof_found_mib = 0;
|
|
|
|
parse_args(argc,argv);
|
|
|
|
if (base_init(FLEN)) {
|
|
fprintf(stderr, "Error initializing memory\n");
|
|
exit(-1);
|
|
}
|
|
|
|
sync_pss_det_peakmean(&sfind);
|
|
sync_pss_det_peakmean(&strack);
|
|
|
|
#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, gain);
|
|
#endif
|
|
|
|
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);
|
|
|
|
#ifndef DISABLE_UHD
|
|
/* set freq */
|
|
cuhd_set_rx_freq(uhd, (double) freq);
|
|
cuhd_rx_wait_lo_locked(uhd);
|
|
DEBUG("Set freq to %.3f MHz\n", (double) freq);
|
|
|
|
DEBUG("Starting receiver...\n",0);
|
|
cuhd_start_rx_stream(uhd);
|
|
#endif
|
|
|
|
while(frame_cnt < nof_frames || nof_frames==-1) {
|
|
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
|
|
#ifndef DISABLE_UHD
|
|
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
|
#else
|
|
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 {
|
|
fprintf(stderr, "UHD is DISABLED but input file name not specified\n");
|
|
usage(argv[0]);
|
|
exit(-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 */
|
|
frame_cnt = -1;
|
|
last_found = 0;
|
|
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);
|
|
mib_decoder_init(cell_id);
|
|
nslot = sync_get_slot_id(&sfind);
|
|
nslot=(nslot+10)%20;
|
|
cfo = 0;
|
|
printf("\n");
|
|
state = TRACK;
|
|
}
|
|
if (verbose == VERBOSE_NONE) {
|
|
printf("Tracking... 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);
|
|
last_found = frame_cnt;
|
|
find_idx += track_idx - track_len;
|
|
if (nslot != sync_get_slot_id(&strack)) {
|
|
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
|
|
state = TRACK;
|
|
}
|
|
}
|
|
|
|
/* if we missed too many PSS go back to track */
|
|
if (frame_cnt - last_found > max_track_lost) {
|
|
INFO("%d frames lost. Going back to TRACK\n", frame_cnt - last_found);
|
|
}
|
|
|
|
// Correct CFO
|
|
INFO("Correcting CFO=%.4f\n", cfo);
|
|
nco_cexp_f_direct(input_buffer, (-cfo)/128, FLEN);
|
|
|
|
if (nslot == 0) {
|
|
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);
|
|
last_found = frame_cnt;
|
|
if (verbose == VERBOSE_NONE) {
|
|
if (!nof_found_mib) {
|
|
pbch_mib_fprint(stdout, &mib);
|
|
}
|
|
}
|
|
nof_found_mib++;
|
|
} else {
|
|
INFO("MIB not found attempt %d\n",frame_cnt);
|
|
}
|
|
if (frame_cnt) {
|
|
printf("SFN: %4d\tCFO: %+.4f KHz\tTimeOffset: %4d\tErrors: %4d/%4d\tErrorRate: %.1e\r", mib.sfn,
|
|
cfo*15, 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("\n\nDone\n");
|
|
exit(0);
|
|
}
|
|
|