Added SIB4. Improved CP detection.

master
ismagom 10 years ago
parent 28ab43c6e9
commit ecbd3dda2c

@ -47,9 +47,8 @@
float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_detect_cfg_t cell_detect_config = {
500, // nof_frames_total
50, // nof_frames_detected
0.4 // threshold
100, // nof_frames_total
3.0 // early-stops cell detection if mean PSR is above this value
};
/**********************************************************************
@ -126,7 +125,10 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
extern float mean_exec_time;
enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
enum receiver_state { DECODE_MIB, DECODE_SIB, DECODE_SIB4, MEASURE} state;
#define MAX_SINFO 10
#define MAX_NEIGHBOUR_CELLS 128
int main(int argc, char **argv) {
int ret;
@ -148,6 +150,11 @@ int main(int argc, char **argv) {
uint32_t sfn_offset;
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
cf_t *nullce[MAX_PORTS];
uint32_t si_window_length;
scheduling_info_t sinfo[MAX_SINFO];
scheduling_info_t *sinfo_sib4 = NULL;
uint32_t neighbour_cell_ids[MAX_NEIGHBOUR_CELLS];
for (int i=0;i<MAX_PORTS;i++) {
nullce[i] = NULL;
@ -173,7 +180,9 @@ int main(int argc, char **argv) {
exit(-1);
}
cuhd_start_rx_stream(uhd);
INFO("Stopping UHD and flushing buffer...\n",0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
@ -187,7 +196,9 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1);
}
pdsch_set_rnti(&ue_dl.pdsch, SIRNTI);
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
ue_dl_set_rnti(&ue_dl, SIRNTI);
/* Initialize subframe counter */
sf_cnt = 0;
@ -205,6 +216,11 @@ int main(int argc, char **argv) {
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
cuhd_start_rx_stream(uhd);
bool sib4_window_start = false;
uint32_t sib4_window_cnt = 0;
/* Main loop */
while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) {
@ -229,17 +245,17 @@ int main(int argc, char **argv) {
} else if (n == MIB_FOUND) {
bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn);
printf("MIB found SFN: %d, offset: %d\n", sfn, sfn_offset);
sfn = (sfn<<2) + sfn_offset;
printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
sfn = (sfn + sfn_offset)%1024;
state = DECODE_SIB;
}
}
break;
case DECODE_SIB:
sfn=0; // FIXME: Use correct SFN!!
/* We are looking for SI Blocks, search only in appropiate places */
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = ue_dl_decode(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), sfn, SIRNTI);
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync),
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
exit(-1);
@ -250,17 +266,74 @@ int main(int argc, char **argv) {
(float) ue_dl.nof_pdcch_detected/nof_trials);
nof_trials++;
} else {
printf("\n\nDecoded SIB1 Message Len %d: ",n);
bit_unpack_vector(data, data_unpacked, n);
void *dlsch_msg = bcch_dlsch_unpack(data_unpacked, n);
if (dlsch_msg) {
printf("\n");fflush(stdout);
cell_access_info_t cell_info;
bcch_dlsch_sib1_get_cell_access_info(dlsch_msg, &cell_info);
printf("Cell ID: 0x%x\n", cell_info.cell_id);
printf("Decoded SIB1. Cell ID: 0x%x\n", cell_info.cell_id);
bcch_dlsch_fprint(dlsch_msg, stdout);
/* Get SIB4 scheduling */
int nsinfo = bcch_dlsch_sib1_get_scheduling_info(dlsch_msg, &si_window_length, sinfo, MAX_SINFO);
/* find SIB4 */
for (int i=0;i<nsinfo && !sinfo_sib4;i++) {
if (sinfo[i].type == SIB4) {
sinfo_sib4 = &sinfo[i];
}
}
ue_dl.nof_pdcch_detected = nof_trials = 0;
sib4_window_start = false;
bzero(data, sizeof(data));
ue_dl_reset(&ue_dl);
}
if (sinfo_sib4) {
state = DECODE_SIB4;
} else {
state = MEASURE;
}
}
}
break;
case DECODE_SIB4:
if (!sib4_window_start &&
((sfn%sinfo_sib4->period) == sinfo_sib4->n*si_window_length/10) &&
ue_sync_get_sfidx(&ue_sync) == (sinfo_sib4->n*si_window_length%10)) {
sib4_window_start = true;
sib4_window_cnt = 0;
}
/* We are looking for SI Blocks, search only in appropiate places */
if (sib4_window_start && !(ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0))
{
/* printf("[%d/%d]: Trying SIB4 in SF: %d, SFN: %d\n", sib4_window_cnt, si_window_length,
ue_sync_get_sfidx(&ue_sync), sfn);
*/ n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync),
((int) ceilf((float)3*sib4_window_cnt/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
exit(-1);
} else if (n == 0) {
nof_trials++;
} else {
bit_unpack_vector(data, data_unpacked, n);
void *dlsch_msg = bcch_dlsch_unpack(data_unpacked, n);
int nof_cell = bcch_dlsch_sib4_get_neighbour_cells(dlsch_msg, neighbour_cell_ids, MAX_NEIGHBOUR_CELLS);
printf("Decoded SIB4. Neighbour cell list (PhyIDs): ");
for (int i=0;i<nof_cell;i++) {
printf("%d, ", neighbour_cell_ids[i]);
}
printf("\n");
state = MEASURE;
}
sib4_window_cnt++;
if (sib4_window_cnt == si_window_length) {
sib4_window_start = false;
exit(-1);
}
}
break;
case MEASURE:
@ -269,7 +342,6 @@ int main(int argc, char **argv) {
chest_dl_estimate(&chest, sf_symbols, nullce, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(vec_avg_power_cf(sf_buffer,SF_LEN(lte_symbol_sz(cell.nof_prb))),rssi,nframes);
rssi_utra = VEC_CMA(chest_dl_get_rssi(&chest),rssi_utra,nframes);
rsrq = VEC_EMA(chest_dl_get_rsrq(&chest),rsrq,0.001);
@ -289,7 +361,7 @@ int main(int argc, char **argv) {
}
break;
}
if (ue_sync_get_sfidx(&ue_sync) == 0) {
if (ue_sync_get_sfidx(&ue_sync) == 9) {
sfn++;
if (sfn == 1024) {
sfn = 0;

@ -55,7 +55,7 @@
int band = -1;
int earfcn_start=-1, earfcn_end = -1;
cell_detect_cfg_t config = {50, 10, CS_FIND_THRESHOLD};
cell_detect_cfg_t config = {50, 1.1};
float uhd_gain = 60.0;
@ -68,7 +68,6 @@ void usage(char *prog) {
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",config.threshold);
printf("\t-v [set verbose to debug, default none]\n");
}
@ -92,9 +91,6 @@ void parse_args(int argc, char **argv) {
case 'n':
config.nof_frames_total = atoi(argv[optind]);
break;
case 'd':
config.nof_frames_detected = atoi(argv[optind]);
break;
case 't':
config.threshold = atof(argv[optind]);
break;

@ -118,7 +118,7 @@ int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *fo
int ret = LIBLTE_ERROR;
ue_celldetect_t cd;
cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000);
cf_t *buffer = vec_malloc(sizeof(cf_t) * CS_FLEN);
if (!buffer) {
perror("malloc");
goto free_and_exit;
@ -129,9 +129,6 @@ int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *fo
goto free_and_exit;
}
if (config->nof_frames_detected) {
ue_celldetect_set_nof_frames_detected(&cd, config->nof_frames_detected);
}
if (config->nof_frames_total) {
ue_celldetect_set_nof_frames_total(&cd, config->nof_frames_total);
}
@ -139,12 +136,12 @@ int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *fo
ue_celldetect_set_threshold(&cd, config->threshold);
}
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
cuhd_set_rx_srate(uhd, 960000.0);
INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000);
cuhd_set_rx_srate(uhd, CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
uint32_t flen = 4800;
uint32_t flen = CS_FLEN;
int n;
bzero(found_cell, sizeof(ue_celldetect_result_t));
@ -171,11 +168,10 @@ int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *fo
case CS_CELL_DETECTED:
ue_celldetect_get_cell(&cd, found_cell);
if (found_cell->peak > 0) {
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %.0f%%\n",
found_cell->cell_id,
lte_cp_string(found_cell->cp),
found_cell->peak, found_cell->mode,
cd.nof_frames_detected);
found_cell->peak, found_cell->mode*100);
}
ret = 1;
@ -183,7 +179,7 @@ int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *fo
break;
case CS_CELL_NOT_DETECTED:
ret = 0;
DEBUG("No cell found at N_id_2=%d\n",N_id_2);
printf("No cell found at N_id_2=%d. Mean PSR: %.2f\n",N_id_2, sync_get_peak_value(&cd.sfind));
break;
case LIBLTE_ERROR:
case LIBLTE_ERROR_INVALID_INPUTS:
@ -271,8 +267,6 @@ int detect_and_decode_cell(cell_detect_cfg_t *config, void *uhd, int force_N_id_
cell->nof_ports = nof_tx_ports;
bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN);
printf("nof_bits: %d\n", BCH_PAYLOAD_LEN);
vec_fprint_hex(stdout, bch_payload, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL);
/* set sampling frequency */

@ -29,9 +29,8 @@
#include "liblte/phy/phy.h"
typedef struct LIBLTE_API {
uint32_t nof_frames_total;
uint32_t nof_frames_detected;
float threshold;
uint32_t nof_frames_total; // maximum number of 5ms frames to capture
float threshold; // early-stops cell detection if mean PSR is above this value
}cell_detect_cfg_t;
int decode_pbch(void *uhd,

@ -47,10 +47,15 @@ void do_plots(ue_dl_t *q, uint32_t sf_idx);
#endif
#define B210_DEFAULT_GAIN 40.0
#define B210_DEFAULT_GAIN_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40
float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_detect_cfg_t cell_detect_config = {
500, // nof_frames_total
50, // nof_frames_detected
CS_FIND_THRESHOLD // threshold
100, // nof_frames_total
4.0 // threshold
};
/**********************************************************************
@ -150,6 +155,9 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
extern float mean_exec_time;
enum receiver_state { DECODE_MIB, DECODE_SIB} state;
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
@ -165,7 +173,6 @@ int main(int argc, char **argv) {
int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset;
float snr = 0;
parse_args(&prog_args, argc, argv);
#ifndef DISABLE_GRAPHICS
@ -192,7 +199,9 @@ int main(int argc, char **argv) {
exit(-1);
}
cuhd_start_rx_stream(uhd);
INFO("Stopping UHD and flushing buffer...\r",0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
@ -207,7 +216,8 @@ int main(int argc, char **argv) {
exit(-1);
}
pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti);
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
ue_dl_set_rnti(&ue_dl, prog_args.rnti);
/* Initialize subframe counter */
sf_cnt = 0;
@ -215,21 +225,24 @@ int main(int argc, char **argv) {
// Register Ctrl+C handler
signal(SIGINT, sig_int_handler);
bool pbch_decoded = false;
cuhd_start_rx_stream(uhd);
// Variables for measurements
uint32_t nframes=0;
float rsrp=0, rsrq=0, snr=0;
/* Main loop */
while (go_exit == false &&
(sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1))
{
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
go_exit=true;
}
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
switch (state) {
case DECODE_MIB:
if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode_aligned_frame(&ue_mib,
@ -237,49 +250,63 @@ int main(int argc, char **argv) {
NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
go_exit=true;
exit(-1);
} else if (n == MIB_FOUND) {
bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn);
printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
sfn = (sfn + sfn_offset)%1024;
pbch_decoded = true;
state = DECODE_SIB;
}
}
if (pbch_decoded) {
break;
case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = ue_dl_decode(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), sfn, prog_args.rnti);
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync),
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
exit(-1);
}
nof_trials++;
snr = VEC_CMA(chest_dl_get_snr(&ue_dl.chest), snr, nof_trials);
}
rsrq = VEC_EMA(chest_dl_get_rsrq(&ue_dl.chest),rsrq,0.001);
rsrp = VEC_CMA(chest_dl_get_rsrp(&ue_dl.chest),rsrp,nframes);
snr = VEC_CMA(chest_dl_get_snr(&ue_dl.chest),snr,nframes);
nframes++;
// Plot and Printf
if (ue_sync_get_sfidx(&ue_sync) == 0) {
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%% (%d blocks)\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rsrp*1000)-gain_offset,
10*log10(rsrq), 10*log10(snr),
100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials),
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,nof_trials, ue_dl.pkts_total);
}
break;
}
if (ue_sync_get_sfidx(&ue_sync) == 9) {
if (pbch_decoded) {
sfn++;
if (sfn == 1024) {
sfn = 0;
}
}
}
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots && ue_sync_get_sfidx(&ue_sync) == 5) {
do_plots(&ue_dl, 5);
}
#endif
if ((sf_cnt%10)==0) {
printf("CFO: %+6.2f KHz, SFO: %+6.2f Khz, SNR: %5.1f dB, NOI: %.2f, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%% (%d blocks)\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10f(snr), pdsch_average_noi(&ue_dl.pdsch),
100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials),
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,nof_trials, ue_dl.pkts_total);
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop

@ -32,6 +32,8 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "liblte/config.h"
#define NSUBFRAMES_X_FRAME 10
@ -79,7 +81,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define CP_ISEXT(cp) (cp==CPEXT)
#define CP_NSYMB(cp) (CP_ISNORM(cp)?CPNORM_NSYMB:CPEXT_NSYMB)
#define CP(symbol_sz, c) ((c*symbol_sz)/2048)
#define CP(symbol_sz, c) ((int) ceil((((float) (c)*(symbol_sz))/2048)))
#define CP_NORM(symbol, symbol_sz) ((symbol==0)?CP((symbol_sz),CPNORM_0_LEN):CP((symbol_sz),CPNORM_LEN))
#define CP_EXT(symbol_sz) (CP((symbol_sz),CPEXT_LEN))

@ -115,6 +115,8 @@ LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p,
ra_mcs_t mcs,
ra_prb_t *prb_alloc);
LIBLTE_API void pdsch_harq_reset(pdsch_harq_t *p);
LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p);
LIBLTE_API int pdsch_encode(pdsch_t *q,

@ -48,7 +48,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* PSS processing options */
//#define PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to pss_synch_find_pss
#define PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to pss_synch_find_pss
#define PSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only
@ -83,9 +83,8 @@ typedef struct LIBLTE_API {
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
cf_t *tmp_input;
cf_t *conv_output;
#ifdef PSS_ACCUMULATE_ABS
float *conv_output_abs;
#endif
float ema_alpha;
float *conv_output_avg;
}pss_synch_t;
@ -111,6 +110,9 @@ LIBLTE_API void pss_put_slot(cf_t *pss_signal,
uint32_t nof_prb,
lte_cp_t cp);
LIBLTE_API void pss_synch_set_ema_alpha(pss_synch_t *q,
float alpha);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
uint32_t N_id_2);

@ -35,6 +35,7 @@
#include "liblte/config.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sss.h"
#include "liblte/phy/sync/cfo.h"
#define FFT_SIZE_MIN 64
#define FFT_SIZE_MAX 2048
@ -51,11 +52,12 @@
* functions sync_pss_det_absolute() and sync_pss_det_peakmean().
*/
typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t;
typedef struct LIBLTE_API {
pss_synch_t pss;
sss_synch_t sss;
float threshold;
float mean_energy;
float peak_value;
float mean_peak_value;
uint32_t N_id_2;
@ -63,16 +65,20 @@ typedef struct LIBLTE_API {
uint32_t sf_idx;
uint32_t fft_size;
uint32_t frame_size;
uint64_t frame_cnt;
float cfo;
float mean_cfo;
cfo_t cfocorr;
sss_alg_t sss_alg;
bool detect_cp;
bool sss_en;
bool normalize_en;
bool correct_cfo;
lte_cp_t cp;
uint32_t m0;
uint32_t m1;
float m0_value;
float m1_value;
float M_norm_avg;
float M_ext_avg;
}sync_t;
@ -90,6 +96,11 @@ LIBLTE_API int sync_find(sync_t *q,
uint32_t find_offset,
uint32_t *peak_position);
/* Estimates the CP length */
LIBLTE_API lte_cp_t sync_detect_cp(sync_t *q,
cf_t *input,
uint32_t peak_pos);
/* Sets the threshold for peak comparison */
LIBLTE_API void sync_set_threshold(sync_t *q,
float threshold);
@ -103,8 +114,13 @@ LIBLTE_API float sync_get_last_peak_value(sync_t *q);
/* Gets the mean peak value */
LIBLTE_API float sync_get_peak_value(sync_t *q);
/* Gets the last input signal energy estimation value */
LIBLTE_API float sync_get_input_energy(sync_t *q);
/* Choose SSS detection algorithm */
LIBLTE_API void sync_set_sss_algorithm(sync_t *q,
sss_alg_t alg);
/* Sets PSS exponential averaging alpha weight */
LIBLTE_API void sync_set_em_alpha(sync_t *q,
float alpha);
/* Sets the N_id_2 to search for */
LIBLTE_API int sync_set_N_id_2(sync_t *q,
@ -122,19 +138,20 @@ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Sets the CP length estimation (must do it if disabled) */
LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);
/* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled);
LIBLTE_API bool sync_sss_detected(sync_t *q);
LIBLTE_API bool sync_sss_is_en(sync_t *q);
/* Enables/Disables CP detection */
LIBLTE_API void sync_cp_en(sync_t *q,
bool enabled);
LIBLTE_API void sync_correct_cfo(sync_t *q,
bool enabled);
#endif // SYNC_

@ -63,26 +63,28 @@
#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
#define CS_FFTSIZE 128
#define CS_SAMP_FREQ (960000*(CS_FFTSIZE/64))
#define CS_FLEN (4800*(CS_FFTSIZE/64))
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
uint32_t mode;
float 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 nof_frames_total; // number of 5 ms frames to scan
float detect_threshold; // early-stops scan if mean PSR above this threshold
uint32_t current_nof_detected;
uint32_t current_nof_total;
@ -97,8 +99,7 @@ typedef struct LIBLTE_API {
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);
uint32_t max_frames_total);
LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q);
@ -117,9 +118,6 @@ LIBLTE_API void ue_celldetect_get_cell(ue_celldetect_t * q,
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);

@ -76,6 +76,7 @@ typedef struct LIBLTE_API {
uint64_t nof_pdcch_detected;
uint16_t user_rnti;
uint16_t current_rnti;
}ue_dl_t;
/* This function shall be called just after the initial synchronization */
@ -85,11 +86,20 @@ LIBLTE_API int ue_dl_init(ue_dl_t *q,
LIBLTE_API void ue_dl_free(ue_dl_t *q);
LIBLTE_API int ue_dl_decode(ue_dl_t *q,
cf_t *sf_buffer,
LIBLTE_API int ue_dl_decode(ue_dl_t * q,
cf_t *input,
uint8_t *data,
uint32_t sf_idx);
LIBLTE_API int ue_dl_decode_sib(ue_dl_t * q,
cf_t *input,
uint8_t * data,
uint32_t sf_idx,
uint32_t sfn,
uint32_t rvidx);
LIBLTE_API void ue_dl_reset(ue_dl_t *q);
LIBLTE_API void ue_dl_set_rnti(ue_dl_t *q,
uint16_t rnti);
#endif

@ -77,9 +77,6 @@ typedef struct LIBLTE_API {
lte_cell_t cell;
uint32_t sf_idx;
cfo_t cfocorr;
float cur_cfo;
bool decode_sss_on_track;
uint32_t peak_idx;

@ -35,6 +35,9 @@
typedef _Complex float cf_t;
#define MAX(a,b) ((a)>(b)?(a):(b))
// Cumulative moving average
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1))

@ -278,7 +278,7 @@ int pbch_decode_frame(pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
uint32_t nof_bits, uint32_t nof_ports) {
int j;
INFO("Trying to decode PBCH %d bits, %d ports, src: %d, dst: %d, n=%d\n", nof_bits, nof_ports, src, dst, n);
DEBUG("Trying to decode PBCH %d bits, %d ports, src: %d, dst: %d, n=%d\n", nof_bits, nof_ports, src, dst, n);
memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits],
n * nof_bits * sizeof(float));
@ -382,6 +382,10 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], float
demod_soft_demodulate(&q->demod, q->pbch_d,
&q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols);
if (nant == 2) {
vec_save_file("d",q->pbch_d, q->nof_symbols*sizeof(cf_t));
}
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered.

@ -399,12 +399,12 @@ int pdsch_harq_init(pdsch_harq_t *p, pdsch_t *pdsch) {
// FIXME: Use HARQ buffer limitation based on UE category
p->w_buff_size = p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp) * 6 * 2 / p->max_cb;
for (i=0;i<p->max_cb;i++) {
p->pdsch_w_buff_f[i] = malloc(sizeof(float) * p->w_buff_size);
p->pdsch_w_buff_f[i] = vec_malloc(sizeof(float) * p->w_buff_size);
if (!p->pdsch_w_buff_f[i]) {
perror("malloc");
return LIBLTE_ERROR;
}
p->pdsch_w_buff_c[i] = malloc(sizeof(uint8_t) * p->w_buff_size);
p->pdsch_w_buff_c[i] = vec_malloc(sizeof(uint8_t) * p->w_buff_size);
if (!p->pdsch_w_buff_c[i]) {
perror("malloc");
return LIBLTE_ERROR;
@ -439,6 +439,27 @@ void pdsch_harq_free(pdsch_harq_t *p) {
}
}
void pdsch_harq_reset(pdsch_harq_t *p) {
int i;
if (p->pdsch_w_buff_f) {
for (i=0;i<p->max_cb;i++) {
if (p->pdsch_w_buff_f[i]) {
bzero(p->pdsch_w_buff_f[i], sizeof(float) * p->w_buff_size);
}
}
}
if (p->pdsch_w_buff_c) {
for (i=0;i<p->max_cb;i++) {
if (p->pdsch_w_buff_c[i]) {
bzero(p->pdsch_w_buff_c[i], sizeof(uint8_t) * p->w_buff_size);
}
}
}
bzero(&p->mcs, sizeof(ra_mcs_t));
bzero(&p->cb_segm, sizeof(struct cb_segm));
bzero(&p->prb_alloc, sizeof(ra_prb_t));
}
int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;

@ -72,8 +72,7 @@ static void corr_all_sz_partial(cf_t z[N_SSS], float s[N_SSS][N_SSS], uint32_t M
static void extract_pair_sss(sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][N_SSS]) {
cf_t input_fft[SYMBOL_SZ_MAX];
dft_run_c(&q->dftp_input, &input[CP_NORM(5, q->fft_size)], input_fft);
dft_run_c(&q->dftp_input, input, input_fft);
if (ce) {
vec_prod_conj_ccc(&input_fft[q->fft_size/2-N_SSS], ce, &input_fft[q->fft_size/2-N_SSS], 2*N_SSS);
@ -90,7 +89,8 @@ static void extract_pair_sss(sss_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][N_
}
int sss_synch_m0m1_diff(sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value,
uint32_t *m1, float *m1_value) {
uint32_t *m1, float *m1_value)
{
return sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value);
}

@ -95,6 +95,7 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) {
q->N_id_2 = 10;
q->fft_size = fft_size;
q->frame_size = frame_size;
q->ema_alpha = 0.1;
buffer_size = fft_size + frame_size + 1;
@ -105,6 +106,7 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) {
}
dft_plan_set_mirror(&q->dftp_input, true);
dft_plan_set_dc(&q->dftp_input, true);
dft_plan_set_norm(&q->dftp_input, true);
q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->tmp_input) {
@ -183,11 +185,9 @@ void pss_synch_free(pss_synch_t *q) {
if (q->conv_output) {
free(q->conv_output);
}
#ifdef PSS_ACCUMULATE_ABS
if (q->conv_output_abs) {
free(q->conv_output_abs);
}
#endif
if (q->conv_output_avg) {
free(q->conv_output_avg);
}
@ -197,11 +197,8 @@ void pss_synch_free(pss_synch_t *q) {
}
void pss_synch_reset(pss_synch_t *q) {
#ifdef PSS_ACCUMULATE_ABS
uint32_t buffer_size = q->fft_size + q->frame_size + 1;
bzero(q->conv_output_avg, sizeof(cf_t) * buffer_size);
#endif
bzero(q->conv_output_avg, sizeof(float) * buffer_size);
}
/**
@ -261,6 +258,12 @@ int pss_synch_set_N_id_2(pss_synch_t *q, uint32_t N_id_2) {
}
}
/* Sets the weight factor alpha for the exponential moving average of the PSS correlation output
*/
void pss_synch_set_ema_alpha(pss_synch_t *q, float alpha) {
q->ema_alpha = alpha;
}
/** Performs time-domain PSS correlation.
* Returns the index of the PSS correlation peak in a subframe.
* The frame starts at corr_peak_pos-subframe_size/2.
@ -295,40 +298,39 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value)
#endif
#ifdef PSS_ACCUMULATE_ABS
#ifdef PSS_ABS_SQUARE
vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1);
#else
vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1);
#endif
/* Find maximum of the absolute value of the correlation */
corr_peak_pos = vec_max_fi(q->conv_output_abs, conv_output_len-1);
// Normalize correlation output
vec_sc_prod_fff(q->conv_output_abs, 1/q->conv_output_abs[corr_peak_pos], q->conv_output_abs, conv_output_len-1);
vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1);
vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1);
vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1);
#else
#ifdef PSS_ABS_SQUARE
vec_abs_square_cf(q->conv_output, q->conv_output_avg, conv_output_len-1);
#else
vec_abs_cf(q->conv_output, q->conv_output_avg, conv_output_len-1);
#endif
#endif
/* Find maximum of the absolute value of the correlation */
corr_peak_pos = vec_max_fi(q->conv_output_avg, conv_output_len-1);
#ifdef PSS_RETURN_PSR
// Find second side lobe
float tmp = q->conv_output_avg[corr_peak_pos];
q->conv_output_avg[corr_peak_pos] = 0;
int side_lobe_pos = vec_max_fi(q->conv_output_avg, conv_output_len-1);
q->conv_output_avg[corr_peak_pos] = tmp;
// Find end of peak lobe to the right
int pl_ub = corr_peak_pos+1;
while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) {
pl_ub ++;
}
// Find end of peak lobe to the left
int pl_lb = corr_peak_pos-1;
while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) {
pl_lb --;
}
int sl_right = pl_ub+vec_max_fi(&q->conv_output_avg[pl_ub], conv_output_len-1 - pl_ub);
int sl_left = vec_max_fi(q->conv_output_avg, pl_lb);
float side_lobe_value = MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]);
if (corr_peak_value) {
*corr_peak_value = tmp/q->conv_output_avg[side_lobe_pos];
*corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value;
}
#else
if (corr_peak_value) {
@ -366,7 +368,7 @@ int pss_synch_chest(pss_synch_t *q, cf_t *input, cf_t ce[PSS_LEN]) {
dft_run_c(&q->dftp_input, input, input_fft);
/* Compute channel estimate taking the PSS sequence as reference */
vec_prod_conj_ccc(q->pss_signal_time[q->N_id_2], &input_fft[(q->fft_size-PSS_LEN)/2], ce, PSS_LEN);
vec_prod_conj_ccc(&input_fft[(q->fft_size-PSS_LEN)/2], q->pss_signal_time[q->N_id_2], ce, PSS_LEN);
ret = LIBLTE_SUCCESS;
}

@ -33,10 +33,11 @@
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/sync/cfo.h"
#define MEANENERGY_EMA_ALPHA 0.5
#define MEANPEAK_EMA_ALPHA 0.2
#define CFO_EMA_ALPHA 0.01
#define CP_EMA_ALPHA 0.2
static bool fft_size_isvalid(uint32_t fft_size) {
if (fft_size >= FFT_SIZE_MIN && fft_size <= FFT_SIZE_MAX && (fft_size%64) == 0) {
@ -55,24 +56,31 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
frame_size <= 307200 &&
fft_size_isvalid(fft_size))
{
ret = LIBLTE_ERROR;
bzero(q, sizeof(sync_t));
q->detect_cp = true;
q->normalize_en = true;
q->mean_energy = 0.0;
q->mean_peak_value = 0.0;
q->sss_en = true;
q->correct_cfo = true;
q->N_id_2 = 1000;
q->N_id_1 = 1000;
q->fft_size = fft_size;
q->frame_size = frame_size;
q->sss_alg = SSS_PARTIAL_3;
if (pss_synch_init_fft(&q->pss, frame_size, fft_size)) {
fprintf(stderr, "Error initializing PSS object\n");
return LIBLTE_ERROR;
goto clean_exit;
}
if (sss_synch_init(&q->sss, fft_size)) {
fprintf(stderr, "Error initializing SSS object\n");
return LIBLTE_ERROR;
goto clean_exit;
}
if (cfo_init(&q->cfocorr, frame_size)) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size);
@ -81,6 +89,11 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
} else {
fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size);
}
clean_exit:
if (ret == LIBLTE_ERROR) {
sync_free(q);
}
return ret;
}
@ -88,6 +101,7 @@ void sync_free(sync_t *q) {
if (q) {
pss_synch_free(&q->pss);
sss_synch_free(&q->sss);
cfo_free(&q->cfocorr);
}
}
@ -99,10 +113,6 @@ void sync_sss_en(sync_t *q, bool enabled) {
q->sss_en = enabled;
}
void sync_normalize_en(sync_t *q, bool enable) {
q->normalize_en = enable;
}
bool sync_sss_detected(sync_t *q) {
return lte_N_id_1_isvalid(q->N_id_1);
}
@ -131,7 +141,7 @@ uint32_t sync_get_sf_idx(sync_t *q) {
}
float sync_get_cfo(sync_t *q) {
return q->cfo;
return q->mean_cfo;
}
float sync_get_last_peak_value(sync_t *q) {
@ -142,10 +152,22 @@ float sync_get_peak_value(sync_t *q) {
return q->mean_peak_value;
}
void sync_correct_cfo(sync_t *q, bool enabled) {
q->correct_cfo = enabled;
}
void sync_cp_en(sync_t *q, bool enabled) {
q->detect_cp = enabled;
}
bool sync_sss_is_en(sync_t *q) {
return q->sss_en;
}
void sync_set_em_alpha(sync_t *q, float alpha) {
pss_synch_set_ema_alpha(&q->pss, alpha);
}
lte_cp_t sync_get_cp(sync_t *q) {
return q->cp;
}
@ -153,33 +175,46 @@ void sync_set_cp(sync_t *q, lte_cp_t cp) {
q->cp = cp;
}
void sync_set_sss_algorithm(sync_t *q, sss_alg_t alg) {
q->sss_alg = alg;
}
/* CP detection algorithm taken from:
* "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
* by Jung-In Kim et al.
*/
static lte_cp_t detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos)
{
float R_norm, R_ext, C_norm, C_ext;
float M_norm, M_ext;
R_norm = crealf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)],
&input[peak_pos-CP_NORM(7, q->fft_size)],
CP_NORM(7, q->fft_size)));
C_norm = cabsf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)],
&input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)],
CP_NORM(7, q->fft_size)));
R_ext = crealf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_EXT(q->fft_size)],
&input[peak_pos-CP_EXT(q->fft_size)],
CP_EXT(q->fft_size)));
C_ext = cabsf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_EXT(q->fft_size)],
&input[peak_pos-q->fft_size-CP_EXT(q->fft_size)],
CP_EXT(q->fft_size)));
M_norm = R_norm/C_norm;
M_ext = R_ext/C_ext;
if (M_norm > M_ext) {
float M_norm=0, M_ext=0;
uint32_t cp_norm_len = CP_NORM(7, q->fft_size);
uint32_t cp_ext_len = CP_EXT(q->fft_size);
cf_t *input_cp_norm = &input[peak_pos-2*(q->fft_size+cp_norm_len)];
cf_t *input_cp_ext = &input[peak_pos-2*(q->fft_size+cp_ext_len)];
for (int i=0;i<2;i++) {
R_norm = crealf(vec_dot_prod_conj_ccc(&input_cp_norm[q->fft_size], input_cp_norm, cp_norm_len));
C_norm = cp_norm_len * vec_avg_power_cf(input_cp_norm, cp_norm_len);
input_cp_norm += q->fft_size+cp_norm_len;
M_norm += R_norm/C_norm;
}
q->M_norm_avg = VEC_EMA(M_norm, q->M_norm_avg, CP_EMA_ALPHA);
for (int i=0;i<2;i++) {
R_ext = crealf(vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len));
C_ext = cp_ext_len * vec_avg_power_cf(input_cp_ext, cp_ext_len);
input_cp_ext += q->fft_size+cp_ext_len;
M_ext += R_ext/C_ext;
}
q->M_ext_avg = VEC_EMA(M_ext, q->M_ext_avg, CP_EMA_ALPHA);
if (q->M_norm_avg > q->M_ext_avg) {
return CPNORM;
} else if (M_norm < M_ext) {
} else if (q->M_norm_avg < q->M_ext_avg) {
return CPEXT;
} else {
if (R_norm > R_ext) {
@ -199,8 +234,8 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
sss_synch_set_N_id_2(&q->sss, q->N_id_2);
if (q->detect_cp) {
if (peak_pos >= q->fft_size + CP_EXT(q->fft_size)) {
q->cp = detect_cp(q, input, peak_pos);
if (peak_pos >= 2*(q->fft_size + CP_EXT(q->fft_size))) {
q->cp = sync_detect_cp(q, input, peak_pos);
} else {
INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos);
return LIBLTE_ERROR;
@ -208,13 +243,23 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) {
}
/* Make sure we have enough room to find SSS sequence */
sss_idx = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, q->cp));
sss_idx = (int) peak_pos-2*q->fft_size-CP(q->fft_size, (CP_ISNORM(q->cp)?CPNORM_LEN:CPEXT_LEN));
if (sss_idx < 0) {
INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos);
return LIBLTE_ERROR;
}
switch(q->sss_alg) {
case SSS_DIFF:
sss_synch_m0m1_diff(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
case SSS_PARTIAL_3:
sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
case SSS_FULL:
sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value);
break;
}
q->sf_idx = sss_synch_subframe(q->m0, q->m1);
ret = sss_synch_N_id_1(&q->sss, q->m0, q->m1);
@ -242,8 +287,6 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
int ret = LIBLTE_ERROR_INVALID_INPUTS;
float peak_unnormalized=0, energy=1;
if (q != NULL &&
input != NULL &&
lte_N_id_2_isvalid(q->N_id_2) &&
@ -259,33 +302,12 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
pss_synch_set_N_id_2(&q->pss, q->N_id_2);
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized);
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &q->peak_value);
if (peak_pos < 0) {
fprintf(stderr, "Error calling finding PSS sequence\n");
return LIBLTE_ERROR;
}
if (q->normalize_en &&
peak_pos + find_offset >= q->fft_size )
{
/* Compute the energy of the received PSS sequence to normalize */
energy = sqrtf(vec_avg_power_cf(&input[find_offset+peak_pos-q->fft_size], q->fft_size));
q->mean_energy = VEC_EMA(energy, q->mean_energy, MEANENERGY_EMA_ALPHA);
} else {
if (q->mean_energy == 0.0) {
energy = 1.0;
} else {
energy = q->mean_energy;
}
}
/* Normalize and compute mean peak value */
if (q->mean_energy) {
q->peak_value = peak_unnormalized/q->mean_energy;
} else {
q->peak_value = peak_unnormalized/energy;
}
q->mean_peak_value = VEC_EMA(q->peak_value, q->mean_peak_value, MEANPEAK_EMA_ALPHA);
q->frame_cnt++;
if (peak_position) {
*peak_position = (uint32_t) peak_pos;
@ -294,31 +316,39 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
/* If peak is over threshold, compute CFO and SSS */
if (q->peak_value >= q->threshold) {
// Set an invalid N_id_1 indicating SSS is yet to be detected
q->N_id_1 = 1000;
// Make sure we have enough space to estimate CFO
if (peak_pos + find_offset >= q->fft_size) {
float cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
/* compute cumulative moving average CFO */
q->mean_cfo = VEC_EMA(cfo, q->mean_cfo, CFO_EMA_ALPHA);
} else {
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
}
// Try to detect SSS
if (q->sss_en) {
/* Correct CFO with the averaged CFO estimation */
if (q->mean_cfo && q->correct_cfo) {
cfo_correct(&q->cfocorr, input, input, -q->mean_cfo / q->fft_size);
}
// Set an invalid N_id_1 indicating SSS is yet to be detected
q->N_id_1 = 1000;
if (sync_sss(q, input, find_offset + peak_pos) < 0) {
INFO("No space for SSS processing. Frame starts at %d\n", peak_pos);
}
}
// Make sure we have enough space to estimate CFO
if (peak_pos + find_offset >= q->fft_size) {
q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]);
} else {
INFO("No space for CFO computation. Frame starts at \n",peak_pos);
}
// Return 1 (peak detected) even if we couldn't estimate CFO and SSS
ret = 1;
} else {
ret = 0;
}
INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f mean_energy=%.2f"
"threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n",
ret, q->N_id_2, peak_pos, peak_unnormalized*1000,energy*1000,q->peak_value, q->mean_energy*1000,
q->threshold, q->sf_idx, 15*q->cfo);
INFO("SYNC ret=%d N_id_2=%d frame_size=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n",
ret, q->N_id_2, q->frame_size, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo);
} else if (lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Must call sync_set_N_id_2() first!\n");
@ -328,6 +358,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
}
void sync_reset(sync_t *q) {
q->frame_cnt = 0;
q->M_ext_avg = 0;
q->M_norm_avg = 0;
pss_synch_reset(&q->pss);
}

@ -53,12 +53,14 @@ float uhd_gain=40.0, uhd_freq=-1.0;
int nof_frames = -1;
uint32_t fft_size=64;
float threshold = 0.4;
int N_id_2_sync = -1;
void usage(char *prog) {
printf("Usage: %s [adgtvnp] -f rx_frequency_hz -i cell_id\n", prog);
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD Gain [Default %.2f dB]\n", uhd_gain);
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-l N_id_2 to sync [Default use cell_id]\n");
printf("\t-s symbol_sz [Default %d]\n", fft_size);
printf("\t-t threshold [Default %.2f]\n", threshold);
#ifndef DISABLE_GRAPHICS
@ -71,7 +73,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "adgtvsfi")) != -1) {
while ((opt = getopt(argc, argv, "adgtvsfil")) != -1) {
switch (opt) {
case 'a':
uhd_args = argv[optind];
@ -88,6 +90,9 @@ void parse_args(int argc, char **argv) {
case 'i':
cell_id = atoi(argv[optind]);
break;
case 'l':
N_id_2_sync = atoi(argv[optind]);
break;
case 's':
fft_size = atoi(argv[optind]);
break;
@ -117,7 +122,7 @@ int main(int argc, char **argv) {
int frame_cnt, n;
void *uhd;
pss_synch_t pss;
cfo_t cfocorr;
cfo_t cfocorr, cfocorr64;
sss_synch_t sss;
int32_t flen;
int peak_idx, last_peak;
@ -128,6 +133,9 @@ int main(int argc, char **argv) {
parse_args(argc, argv);
if (N_id_2_sync == -1) {
N_id_2_sync = cell_id%3;
}
uint32_t N_id_2 = cell_id%3;
uint32_t N_id_1 = cell_id/3;
@ -146,12 +154,13 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating PSS\n");
exit(-1);
}
if (pss_synch_set_N_id_2(&pss, N_id_2)) {
fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2);
if (pss_synch_set_N_id_2(&pss, N_id_2_sync)) {
fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2_sync);
exit(-1);
}
cfo_init(&cfocorr, flen);
cfo_init(&cfocorr64, flen);
if (sss_synch_init(&sss, fft_size)) {
fprintf(stderr, "Error initializing SSS object\n");
@ -184,6 +193,11 @@ int main(int argc, char **argv) {
float mean_cfo = 0;
uint32_t m0, m1;
uint32_t sss_error1 = 0, sss_error2 = 0, sss_error3 = 0;
uint32_t cp_is_norm = 0;
sync_t ssync;
bzero(&ssync, sizeof(sync_t));
ssync.fft_size = fft_size;
while(frame_cnt < nof_frames || nof_frames == -1) {
n = cuhd_recv(uhd, buffer, flen - peak_offset, 1);
@ -219,22 +233,29 @@ int main(int argc, char **argv) {
}
// Find SSS
int sss_idx = peak_idx-flen/10+SLOT_IDX_CPNORM(5,fft_size);
int sss_idx = peak_idx-2*fft_size-CP(fft_size, CPNORM_LEN);
if (sss_idx >= 0 && sss_idx < flen-fft_size) {
sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++;
}
sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error2++;
}
sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error3++;
}
sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) {
sss_error1++;
}
}
// Estimate CP
if (peak_idx > 2*(fft_size + CP_EXT(fft_size))) {
lte_cp_t cp = sync_detect_cp(&ssync, buffer, peak_idx);
if (CP_ISNORM(cp)) {
cp_is_norm++;
}
}
} else {
INFO("No space for CFO computation. Frame starts at \n",peak_idx);
@ -248,7 +269,7 @@ int main(int argc, char **argv) {
}
if (frame_cnt > 100) {
if (abs(last_peak-peak_idx) > 10) {
if (abs(last_peak-peak_idx) > 4) {
if (peak_value >= threshold) {
nof_nopeakdet++;
}
@ -258,15 +279,15 @@ int main(int argc, char **argv) {
frame_cnt++;
printf("[%5d]: Pos: %5d, PSR: %6.3f MeanPSR: %6.3f, Pdet: %6.3f, Pmiss: %.3f, "
"FP: %d, FPThres: %d, CFO: %+4.1f KHz SSSmiss: %.3f/%.3f/%.3f\r",
printf("[%5d]: Pos: %5d, PSR: %4.1f (~%4.1f) Pdet: %4.2f, "
"FA: %4.2f, CFO: %+4.1f KHz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f\%\r",
frame_cnt,
peak_idx,
peak_value, mean_peak,
(float) nof_det/frame_cnt, (float) nof_nodet/frame_cnt,
nof_nopeak, nof_nopeakdet, mean_cfo*15,
(float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det
);
(float) nof_det/frame_cnt,
(float) nof_nopeakdet/frame_cnt, mean_cfo*15,
(float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det,
(float) cp_is_norm/nof_det * 100);
if (VERBOSE_ISINFO()) {
printf("\n");

@ -36,15 +36,15 @@
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
#define CS_CELL_DETECT_THRESHOLD 1.2
#define FIND_FFTSIZE 64
#define FIND_SFLEN 5*SF_LEN(FIND_FFTSIZE)
#define CS_SFLEN 5*SF_LEN(CS_FFTSIZE)
int ue_celldetect_init(ue_celldetect_t * q) {
return ue_celldetect_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, CS_DEFAULT_MAXFRAMES_DETECTED);
return ue_celldetect_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL);
}
int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total, uint32_t max_frames_detected) {
int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
@ -52,32 +52,32 @@ int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total, uint3
bzero(q, sizeof(ue_celldetect_t));
q->candidates = calloc(sizeof(ue_celldetect_result_t), max_frames_detected);
q->candidates = calloc(sizeof(ue_celldetect_result_t), max_frames_total);
if (!q->candidates) {
perror("malloc");
goto clean_exit;
}
if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) {
if (sync_init(&q->sfind, CS_SFLEN, CS_FFTSIZE)) {
goto clean_exit;
}
q->mode_ntimes = calloc(sizeof(uint32_t), max_frames_detected);
q->mode_ntimes = calloc(sizeof(uint32_t), max_frames_total);
if (!q->mode_ntimes) {
perror("malloc");
goto clean_exit;
}
q->mode_counted = calloc(sizeof(uint8_t), max_frames_detected);
q->mode_counted = calloc(sizeof(uint8_t), max_frames_total);
if (!q->mode_counted) {
perror("malloc");
goto clean_exit;
}
sync_set_threshold(&q->sfind, CS_FIND_THRESHOLD);
/* Accept all peaks because search space is 5 ms and there is always a peak */
sync_set_threshold(&q->sfind, 1.0);
sync_sss_en(&q->sfind, true);
sync_set_sss_algorithm(&q->sfind, SSS_PARTIAL_3);
q->max_frames_total = max_frames_total;
q->max_frames_detected = max_frames_detected;
q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL;
q->nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED;
ue_celldetect_reset(q);
@ -108,7 +108,6 @@ void ue_celldetect_free(ue_celldetect_t * q)
}
void ue_celldetect_reset(ue_celldetect_t * q)
{
q->current_nof_detected = 0;
@ -117,7 +116,7 @@ void ue_celldetect_reset(ue_celldetect_t * q)
void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold)
{
sync_set_threshold(&q->sfind, threshold);
q->detect_threshold = threshold;
}
int ue_celldetect_set_nof_frames_total(ue_celldetect_t * q, uint32_t nof_frames)
@ -130,28 +129,22 @@ int ue_celldetect_set_nof_frames_total(ue_celldetect_t * q, uint32_t nof_frames)
}
}
int ue_celldetect_set_nof_frames_detected(ue_celldetect_t * q, uint32_t nof_frames)
{
if (nof_frames <= q->max_frames_detected) {
q->nof_frames_detected = nof_frames;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR;
}
}
/* Decide the most likely cell based on the mode */
void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell)
{
uint32_t i, j;
bzero(q->mode_counted, q->nof_frames_detected);
bzero(q->mode_ntimes, sizeof(uint32_t) * q->nof_frames_detected);
if (!q->current_nof_detected) {
return;
}
bzero(q->mode_counted, q->current_nof_detected);
bzero(q->mode_ntimes, sizeof(uint32_t) * q->current_nof_detected);
/* First find mode of CELL IDs */
for (i = 0; i < q->nof_frames_detected; i++) {
for (i = 0; i < q->current_nof_detected; i++) {
uint32_t cnt = 1;
for (j=i+1;j<q->nof_frames_detected;j++) {
for (j=i+1;j<q->current_nof_detected;j++) {
if (q->candidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) {
q->mode_counted[j]=1;
cnt++;
@ -160,7 +153,7 @@ void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_c
q->mode_ntimes[i] = cnt;
}
uint32_t max_times=0, mode_pos=0;
for (i=0;i<q->nof_frames_detected;i++) {
for (i=0;i<q->current_nof_detected;i++) {
if (q->mode_ntimes[i] > max_times) {
max_times = q->mode_ntimes[i];
mode_pos = i;
@ -169,15 +162,11 @@ void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_c
found_cell->cell_id = q->candidates[mode_pos].cell_id;
/* Now in all these cell IDs, find most frequent CP */
uint32_t nof_normal = 0;
found_cell->peak = 0;
for (i=0;i<q->nof_frames_detected;i++) {
for (i=0;i<q->current_nof_detected;i++) {
if (q->candidates[i].cell_id == found_cell->cell_id) {
if (CP_ISNORM(q->candidates[i].cp)) {
nof_normal++;
}
if (q->mode_ntimes[mode_pos]) {
found_cell->peak += q->candidates[i].peak/q->mode_ntimes[mode_pos];
}
}
}
if (nof_normal > q->mode_ntimes[mode_pos]/2) {
@ -185,7 +174,8 @@ void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_c
} else {
found_cell->cp = CPEXT;
}
found_cell->mode = q->mode_ntimes[mode_pos];
found_cell->mode = (float) q->mode_ntimes[mode_pos]/q->current_nof_detected;
found_cell->peak = q->candidates[q->current_nof_detected-1].peak;
q->current_nof_detected = q->current_nof_total = 0;
}
@ -204,15 +194,15 @@ int ue_celldetect_scan(ue_celldetect_t * q,
if (q != NULL &&
signal != NULL &&
nsamples >= 4800)
nsamples >= CS_FLEN)
{
ret = LIBLTE_SUCCESS;
if (nsamples % 4800) {
printf("Warning: nsamples must be a multiple of 4800. Some samples will be ignored\n");
nsamples = (nsamples/4800) * 4800;
if (nsamples % CS_FLEN) {
printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", CS_FLEN);
nsamples = (nsamples/CS_FLEN) * CS_FLEN;
}
nof_input_frames = nsamples/4800;
nof_input_frames = nsamples/CS_FLEN;
for (uint32_t nf=0;nf<nof_input_frames;nf++) {
@ -220,7 +210,7 @@ int ue_celldetect_scan(ue_celldetect_t * q,
q->current_nof_detected, q->current_nof_total, q->sfind.N_id_2, nof_input_frames);
/* Find peak and cell id */
ret = sync_find(&q->sfind, &signal[nf*4800], 0, &peak_idx);
ret = sync_find(&q->sfind, &signal[nf*CS_FLEN], 0, &peak_idx);
if (ret < 0) {
fprintf(stderr, "Error finding correlation peak (%d)\n", ret);
return LIBLTE_ERROR;
@ -234,7 +224,7 @@ int ue_celldetect_scan(ue_celldetect_t * q,
/* Save cell id, cp and peak */
q->candidates[q->current_nof_detected].cell_id = (uint32_t) ret;
q->candidates[q->current_nof_detected].cp = sync_get_cp(&q->sfind);
q->candidates[q->current_nof_detected].peak = sync_get_last_peak_value(&q->sfind);
q->candidates[q->current_nof_detected].peak = sync_get_peak_value(&q->sfind);
}
INFO
("[%3d/%3d]: Found peak at %4d, value %.3f, Cell_id: %d CP: %s\n",
@ -250,11 +240,15 @@ int ue_celldetect_scan(ue_celldetect_t * q,
q->current_nof_total++;
/* Decide cell ID and CP if we detected up to nof_frames_detected */
if (q->current_nof_detected == q->nof_frames_detected) {
if (sync_get_peak_value(&q->sfind) > q->detect_threshold) {
ret = CS_CELL_DETECTED;
} else if (q->current_nof_total == q->nof_frames_total) {
q->current_nof_detected = q->current_nof_total = 0;
if (sync_get_peak_value(&q->sfind) > CS_CELL_DETECT_THRESHOLD) {
ret = CS_CELL_DETECTED;
} else {
ret = CS_CELL_NOT_DETECTED;
q->current_nof_detected = q->current_nof_total = 0;
}
} else {
ret = 0;
}

@ -144,6 +144,15 @@ void ue_dl_free(ue_dl_t *q) {
}
}
void ue_dl_set_rnti(ue_dl_t *q, uint16_t rnti) {
q->current_rnti = rnti;
pdsch_set_rnti(&q->pdsch, SIRNTI);
}
void ue_dl_reset(ue_dl_t *q) {
pdsch_harq_reset(&q->harq_process[0]);
}
LIBLTE_API float mean_exec_time=0;
dci_format_t ue_formats[] = {Format1A,Format1}; // Format1B should go here also
@ -152,7 +161,18 @@ const uint32_t nof_ue_formats = 2;
dci_format_t common_formats[] = {Format1A,Format1C};
const uint32_t nof_common_formats = 2;
int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti)
/** Applies the following operations to a subframe of synchronized samples:
* - OFDM demodulation
* - Channel estimation
* - PCFICH decoding
* - PDCCH decoding: Find DCI for RNTI given by previous call to ue_dl_set_rnti()
* - PDSCH decoding: Decode TB scrambling with RNTI given by ue_dl_set_rnti()
*/
int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx) {
return ue_dl_decode_sib(q, input, data, sf_idx, 0);
}
int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32_t rvidx)
{
uint32_t cfi, cfi_distance, i;
ra_pdsch_t ra_dl;
@ -173,8 +193,6 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
/* Get channel estimates for each port */
chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx);
/* First decode PCFICH and obtain CFI */
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,
chest_dl_get_noise_estimate(&q->chest), sf_idx, &cfi, &cfi_distance)<0) {
@ -190,12 +208,12 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
}
/* Generate PDCCH candidates */
if (rnti == SIRNTI) {
if (q->current_rnti == SIRNTI) {
nof_locations = pdcch_common_locations(&q->pdcch, locations, MAX_CANDIDATES, cfi);
formats = common_formats;
nof_formats = nof_common_formats;
} else {
nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, q->user_rnti);
nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, q->current_rnti);
formats = ue_formats;
nof_formats = nof_ue_formats;
}
@ -207,28 +225,24 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
}
/* For all possible locations, try to decode a DCI message */
crc_rem = 0;
for (int f=0;f<nof_formats;f++) {
for (i=0;i<nof_locations && crc_rem != rnti;i++) {
uint32_t found_dci = 0;
for (int f=0;f<nof_formats && !found_dci;f++) {
for (i=0;i<nof_locations && !found_dci;i++) {
if (pdcch_decode_msg(&q->pdcch, &dci_msg, &locations[i], formats[f], &crc_rem)) {
fprintf(stderr, "Error decoding DCI msg\n");
return LIBLTE_ERROR;
}
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
}
}
if (crc_rem == rnti) {
if (crc_rem == q->current_rnti) {
found_dci++;
q->nof_pdcch_detected++;
if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) {
if (dci_msg_to_ra_dl(&dci_msg, q->current_rnti, q->user_rnti, q->cell, cfi, &ra_dl)) {
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
return LIBLTE_ERROR;
}
uint32_t rvidx;
if (rnti == SIRNTI) {
int k = ((sfn)/2)%4;
rvidx = ((int) ceilf((float)3*k/2))%4;
} else {
if (q->current_rnti != SIRNTI) {
rvidx = ra_dl.rv_idx;
}
if (rvidx == 0) {
@ -254,12 +268,16 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32
q->pkts_total++;
}
}
}
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
mean_exec_time = (float) VEC_EMA((float) t[0].tv_usec, mean_exec_time, 0.01);
if (crc_rem == rnti && ret == LIBLTE_SUCCESS) {
if (found_dci > 0 && ret == LIBLTE_SUCCESS) {
return ra_dl.mcs.tbs;
} else {
return 0;

@ -36,8 +36,6 @@
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
#define MIB_FIND_THRESHOLD 0.0
int ue_mib_init_1_92(ue_mib_t * q,
uint32_t cell_id,
lte_cp_t cp)
@ -83,7 +81,7 @@ int ue_mib_init_1_92(ue_mib_t * q,
goto clean_exit;
}
sync_set_threshold(&q->sfind, MIB_FIND_THRESHOLD);
sync_set_threshold(&q->sfind, 1.0); // Because we are capturing 5 ms frames and there is always peak
sync_sss_en(&q->sfind, true);
sync_set_N_id_2(&q->sfind, cell.id % 3);
sync_cp_en(&q->sfind, false);
@ -167,8 +165,6 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input,
if (ret < 0) {
return LIBLTE_ERROR;
}
INFO("Channel estimated for %d ports, Noise: %f\n", q->chest.cell.nof_ports,
chest_dl_get_noise_estimate(&q->chest));
/* Reset decoder if we missed a frame */
if ((q->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) ||
q->frame_cnt > 16)
@ -259,13 +255,6 @@ int ue_mib_sync_and_decode_1_92(ue_mib_t * q,
nf*MIB_FRAME_SIZE_SEARCH + peak_idx > MIB_FRAME_SIZE_SEARCH/10)
{
// PSS and SSS detected and we have space to decode the PBCH.
// Apply CFO correction
INFO("Correcting CFO: %f\n", sync_get_cfo(&q->sfind));
cfo_correct(&q->cfocorr, &signal[nf*MIB_FRAME_SIZE_SEARCH], &signal[nf*MIB_FRAME_SIZE_SEARCH],
-sync_get_cfo(&q->sfind) / MIB_FFT_SIZE);
INFO("Trying to decode PBCH\n",0);
ret = ue_mib_decode_aligned_frame(q,
&signal[nf*MIB_FRAME_SIZE_SEARCH+peak_idx-MIB_FRAME_SIZE_SEARCH/10],

@ -46,12 +46,10 @@ cf_t dummy[MAX_TIME_OFFSET];
#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
#define FIND_THRESHOLD 1.5
#define TRACK_THRESHOLD 0.8
#define FIND_THRESHOLD 4.0
#define TRACK_THRESHOLD 2.0
#define TRACK_MAX_LOST 10
#define CFO_EMA_ALPHA 0.01
int ue_sync_init(ue_sync_t *q,
lte_cell_t cell,
@ -69,9 +67,7 @@ int ue_sync_init(ue_sync_t *q,
bzero(q, sizeof(ue_sync_t));
ue_sync_reset(q);
q->decode_sss_on_track = true;
q->decode_sss_on_track = false;
q->stream = stream_handler;
q->recv_callback = recv_callback;
q->cell = cell;
@ -89,16 +85,14 @@ int ue_sync_init(ue_sync_t *q,
sync_set_threshold(&q->sfind, FIND_THRESHOLD);
q->sfind.cp = cell.cp;
sync_cp_en(&q->sfind, false);
sync_correct_cfo(&q->sfind, true);
sync_set_em_alpha(&q->sfind, 1);
sync_set_N_id_2(&q->strack, cell.id%3);
sync_set_threshold(&q->strack, TRACK_THRESHOLD);
q->strack.cp = cell.cp;
sync_cp_en(&q->strack, false);
if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) {
fprintf(stderr, "Error initiating CFO\n");
goto clean_exit;
}
sync_correct_cfo(&q->strack, false);
q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t));
if (!q->input_buffer) {
@ -106,6 +100,8 @@ int ue_sync_init(ue_sync_t *q,
goto clean_exit;
}
ue_sync_reset(q);
ret = LIBLTE_SUCCESS;
}
@ -124,7 +120,6 @@ void ue_sync_free(ue_sync_t *q) {
if (q->input_buffer) {
free(q->input_buffer);
}
cfo_free(&q->cfocorr);
sync_free(&q->sfind);
sync_free(&q->strack);
@ -143,7 +138,7 @@ uint32_t ue_sync_get_sfidx(ue_sync_t *q) {
}
float ue_sync_get_cfo(ue_sync_t *q) {
return 15000 * q->cur_cfo;
return 15000 * sync_get_cfo(&q->strack);
}
float ue_sync_get_sfo(ue_sync_t *q) {
@ -176,7 +171,7 @@ static int find_peak_ok(ue_sync_t *q) {
q->state = SF_TRACK;
INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n",
q->peak_idx, sync_get_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
q->peak_idx, sync_get_last_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
} else {
INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
@ -188,16 +183,12 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
/* Make sure subframe idx is what we expect */
if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) {
if (sync_get_cell_id(&q->strack) == q->cell.id) {
INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n",
q->sf_idx, sync_get_sf_idx(&q->strack),
q->strack.m0, q->strack.m0_value, q->strack.m1, q->strack.m1_value);
/* FIXME: What should we do in this case?
* If the threshold is high enough, an OK peak means it is likely to be true
* Otherwise, maybe we should not trust the new sf_idx.
*/
q->sf_idx = sync_get_sf_idx(&q->strack);
//q->state = SF_FIND;
}
} else {
q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE);
@ -210,8 +201,6 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
}
}
/* compute cumulative moving average CFO */
q->cur_cfo = VEC_EMA(sync_get_cfo(&q->strack), q->cur_cfo, CFO_EMA_ALPHA);
/* compute cumulative moving average time offset */
q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt);
@ -232,7 +221,7 @@ int track_peak_no(ue_sync_t *q) {
q->state = SF_FIND;
} else {
INFO("Tracking peak not found. Peak %.3f, %d lost\n",
sync_get_peak_value(&q->strack), (int) q->frame_no_cnt);
sync_get_last_peak_value(&q->strack), (int) q->frame_no_cnt);
}
return 1;
@ -301,7 +290,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
case SF_TRACK:
ret = 1;
q->strack.sss_en = q->decode_sss_on_track;
sync_sss_en(&q->strack, q->decode_sss_on_track);
q->sf_idx = (q->sf_idx + 1) % 10;
@ -343,7 +332,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
}
/* Do CFO Correction and deliver the frame */
cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE);
cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / CURRENT_FFTSIZE);
*sf_symbols = q->input_buffer;
break;
@ -354,11 +343,10 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
void ue_sync_reset(ue_sync_t *q) {
q->state = SF_FIND;
sync_reset(&q->strack);
q->frame_ok_cnt = 0;
q->frame_no_cnt = 0;
q->frame_total_cnt = 0;
q->cur_cfo = 0.0;
q->mean_time_offset = 0.0;
q->time_offset = 0;
#ifdef MEASURE_EXEC_TIME

@ -32,6 +32,8 @@
#include <stdbool.h>
#include <stdint.h>
typedef enum {SIB1=1, SIB2=2, SIB3=3, SIB4=4, SIB5=5, SIB6=6, SIB7=7, SIB8=8, SIB9=9, SIB_ERROR=0} sib_type_t;
typedef struct {
uint32_t mcc; // 3 digits in Decimal value
uint32_t mnc; // 2 digits
@ -45,4 +47,10 @@ typedef struct {
bool intraFreqReselection;
} cell_access_info_t;
typedef struct {
sib_type_t type;
uint32_t n; // Order of entry in scheduling info list
uint32_t period;
} scheduling_info_t;
#endif

@ -35,22 +35,6 @@
#include <stdint.h>
#define SI_PERIODS 10
#define SI_X_PERIOD 10
typedef enum {BCCH_DLSCH_SIB1, BCCH_DLSCH_SIB2, BCCH_DLSCH_SIB3, BCCH_DLSCH_SIB6, BCCH_DLSCH_UNKNOWN} bcch_dlsch_sib_type_t;
typedef struct {
bcch_dlsch_sib_type_t type[SI_X_PERIOD];
uint32_t period;
} bcch_si_scheduling_info_t;
typedef struct {
uint32_t window_length_ms;
uint32_t nof_periods;
bcch_si_scheduling_info_t si_period_list[SI_PERIODS];
} bcch_si_scheduling_t;
LIBLTE_API int bcch_bch_pack(lte_cell_t *cell,
uint32_t sfn,
@ -72,8 +56,6 @@ LIBLTE_API int bcch_dlsch_pack(void *bcch_dlsch_msg,
LIBLTE_API void* bcch_dlsch_unpack(uint8_t *buffer,
uint32_t msg_nof_bits);
LIBLTE_API bcch_dlsch_sib_type_t bcch_dlsch_get_type(void *bcch_dlsch_msg);
LIBLTE_API void bcch_dlsch_fprint(void *bcch_dlsch_msg,
FILE *stream);

@ -47,6 +47,11 @@ LIBLTE_API void bcch_dlsch_sib1_get_plmns(void *bcch_dlsch_msg,
LIBLTE_API void bcch_dlsch_sib1_get_cell_access_info(void *bcch_dlsch_msg,
cell_access_info_t *info);
LIBLTE_API int bcch_dlsch_sib1_get_scheduling_info(void *bcch_dlsch_msg,
uint32_t *si_window_length,
scheduling_info_t *info,
uint32_t max_elems);
void bcch_dlsch_sib1(BCCH_DL_SCH_Message_t *sib1,
MCC_MNC_Digit_t mcc_val[3],
MCC_MNC_Digit_t mnc_val[2],

@ -0,0 +1,45 @@
/**
*
* \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 SIB4_
#define SIB4_
#include <stdio.h>
#include <stdlib.h>
#include "liblte/rrc/common/rrc_common.h"
#include "liblte/rrc/messages/bcch.h"
#include "liblte/phy/utils/bit.h"
#include "rrc_asn.h"
LIBLTE_API int bcch_dlsch_sib4_get_neighbour_cells(void *bcch_dlsch_msg,
uint32_t *neighbour_cell_ids,
uint32_t max_elems);
#endif

@ -40,6 +40,7 @@
#include "liblte/rrc/messages/bcch.h"
#include "liblte/rrc/messages/sib1.h"
#include "liblte/rrc/messages/sib4.h"
#include "liblte/rrc/common/rrc_common.h"
#ifdef __cplusplus

@ -31,11 +31,9 @@
#include "liblte/rrc/messages/sib1.h"
#include "liblte/rrc/messages/bcch.h"
#include "liblte/phy/utils/bit.h"
#include "liblte/phy/utils/debug.h"
#include "rrc_asn.h"
int bcch_bch_pack(lte_cell_t *cell, uint32_t sfn, uint8_t *buffer, uint32_t buffer_size_bytes) {
MasterInformationBlock_t req;
@ -201,18 +199,17 @@ void* bcch_dlsch_unpack(uint8_t *buffer, uint32_t msg_nof_bits) {
fprintf(stderr, "Decoding failed.\n");
return NULL;
} else {
bcch_dlsch_fprint(msg, stdout);
return msg;
}
}
bcch_dlsch_sib_type_t bcch_dlsch_get_type(void *bcch_dlsch_msg) {
sib_type_t bcch_dlsch_get_type(void *bcch_dlsch_msg) {
BCCH_DL_SCH_Message_t *msg = (BCCH_DL_SCH_Message_t*) bcch_dlsch_msg;
switch(msg->message.present) {
case BCCH_DL_SCH_MessageType_PR_c1:
switch (msg->message.choice.c1.present) {
case BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1:
return BCCH_DLSCH_SIB1;
return SIB1;
break;
default:
fprintf(stderr, "Message type not supported\n");
@ -224,7 +221,7 @@ bcch_dlsch_sib_type_t bcch_dlsch_get_type(void *bcch_dlsch_msg) {
bcch_dlsch_fprint(bcch_dlsch_msg, stderr);
break;
}
return BCCH_DLSCH_UNKNOWN;
return SIB_ERROR;
}
void bcch_dlsch_fprint(void *bcch_dlsch_msg, FILE *stream) {

@ -74,14 +74,19 @@ void bcch_dlsch_sib1_get_cell_access_info(void *bcch_dlsch_msg, cell_access_info
}
uint32_t get_si_period(long int period) {
return 8<<period;
return 8<<(period);
}
bcch_dlsch_sib_type_t get_si_type(SIB_Type_t *type) {
sib_type_t get_si_type(SIB_Type_t *type) {
switch(*type) {
case SIB_Type_sibType3: return BCCH_DLSCH_SIB3;
case SIB_Type_sibType6: return BCCH_DLSCH_SIB6;
default: return BCCH_DLSCH_UNKNOWN;
case SIB_Type_sibType3: return SIB3;
case SIB_Type_sibType4: return SIB4;
case SIB_Type_sibType5: return SIB5;
case SIB_Type_sibType6: return SIB6;
case SIB_Type_sibType7: return SIB7;
case SIB_Type_sibType8: return SIB8;
case SIB_Type_sibType9: return SIB9;
default: return SIB_ERROR;
}
}
@ -97,21 +102,40 @@ uint32_t get_window(long int window_length) {
default: return 0;
}
}
void bcch_dlsch_sib1_get_si_scheduling(void *bcch_dlsch_msg, bcch_si_scheduling_t *si_sched) {
int bcch_dlsch_sib1_get_scheduling_info(void *bcch_dlsch_msg,
uint32_t *si_window_length,
scheduling_info_t *info,
uint32_t max_elems)
{
BCCH_DL_SCH_Message_t *msg = (BCCH_DL_SCH_Message_t*) bcch_dlsch_msg;
SystemInformationBlockType1_t *sib1 = &(msg->message.choice.c1.choice.systemInformationBlockType1);
si_sched->nof_periods = MIN(SI_PERIODS, sib1->schedulingInfoList.list.count);
for (int i=0;i<si_sched->nof_periods;i++) {
SchedulingInfo_t *s = sib1->schedulingInfoList.list.array[0];
si_sched->si_period_list[i].period = get_si_period(s->si_Periodicity);
int jmax = MIN(SI_X_PERIOD, s->sib_MappingInfo.list.count);
for (int j=0;j<jmax;j++) {
si_sched->si_period_list[i].type[j] = get_si_type(s->sib_MappingInfo.list.array[j]);
uint32_t nelems = 0;
if (max_elems > 0 && info != NULL) {
/* First is always SIB2 */
info[0].type = SIB2;
info[0].n = 0;
info[0].period = get_si_period(sib1->schedulingInfoList.list.array[0]->si_Periodicity);
nelems++;
for (int i=0;i<sib1->schedulingInfoList.list.count;i++) {
SchedulingInfo_t *s = sib1->schedulingInfoList.list.array[i];
for (int j=0;j<s->sib_MappingInfo.list.count;j++) {
if (nelems < max_elems) {
info[nelems].type = get_si_type(s->sib_MappingInfo.list.array[j]);
info[nelems].n = i;
info[nelems].period = get_si_period(s->si_Periodicity);
nelems++;
}
}
}
}
if (si_window_length) {
*si_window_length = get_window(sib1->si_WindowLength);
}
si_sched->window_length_ms = get_window(sib1->si_WindowLength);
return nelems;
}
MCC_MNC_Digit_t *dup_digit(MCC_MNC_Digit_t value) {

@ -0,0 +1,56 @@
/**
*
* \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 "liblte/rrc/common/rrc_common.h"
#include "liblte/rrc/messages/bcch.h"
#include "liblte/rrc/messages/sib4.h"
#include "liblte/phy/utils/bit.h"
#include "rrc_asn.h"
#include <BCCH-DL-SCH-MessageType.h>
int bcch_dlsch_sib4_get_neighbour_cells(void *bcch_dlsch_msg, uint32_t *neighbour_cell_ids, uint32_t max_elems)
{
int i = 0;
BCCH_DL_SCH_Message_t *msg = (BCCH_DL_SCH_Message_t*) bcch_dlsch_msg;
SystemInformationBlockType4_t *sib4 =
&(msg->message.choice.c1.choice.systemInformation.criticalExtensions.choice.systemInformation_r8.sib_TypeAndInfo.list.array[0]->choice.sib4);
if (sib4->intraFreqNeighCellList) {
for (i=0;i<sib4->intraFreqNeighCellList->list.count && i<max_elems;i++) {
IntraFreqNeighCellInfo_t *cellInfo = sib4->intraFreqNeighCellList->list.array[i];
neighbour_cell_ids[i] = cellInfo->physCellId;
}
}
return i;
}

@ -7,15 +7,15 @@ m1=10;
%m0=26;
%m1=21;
recordedWaveform = signal;
recordedWaveform = x;
if (~isempty(recordedWaveform))
Npackets = floor(length(signal)/19200)-1;
Npackets = floor(length(recordedWaveform)/19200)-1;
SNR_values = 0;
end
error = zeros(6,length(SNR_values));
enb = struct('NCellID',196,'NSubframe',0,'NDLRB',6,'CellRefP',1,'CyclicPrefix','Normal','DuplexMode','FDD');
enb = struct('NCellID',2,'NSubframe',0,'NDLRB',6,'CellRefP',1,'CyclicPrefix','Normal','DuplexMode','FDD');
sss=lteSSS(enb);
cfg.Seed = 2; % Random channel seed
@ -68,6 +68,7 @@ for snr_idx=1:length(SNR_values)
end
offset = lteDLFrameOffset(enb,rxWaveform);
offsetVec(i)=offset;
rxWaveform = [rxWaveform(1+offset:end,:); zeros(offset,1)];
subframe_rx = lteOFDMDemodulate(enb,rxWaveform,1);
@ -111,7 +112,7 @@ for snr_idx=1:length(SNR_values)
error(3,snr_idx) = error(3,snr_idx) + ((idx ~= m0 && idx ~= m1));
% libLTE results
[n,sf_idx,lt_corr0,lt_corr1,lt_sss0,lt_sss1]=liblte_sss(enb,rxWaveform,'full');
[n,sf_idx,lt_corr0]=liblte_sss(enb,rxWaveform,'full');
[m, idx]=max(lt_corr0);
error(4,snr_idx) = error(4,snr_idx) + ((idx ~= m0 && idx ~= m1));

Loading…
Cancel
Save