Added SIB4. Improved CP detection.
This commit is contained in:
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;
|
||||
|
@ -204,7 +215,12 @@ int main(int argc, char **argv) {
|
|||
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
|
||||
|
||||
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:
|
||||
|
@ -268,8 +341,7 @@ int main(int argc, char **argv) {
|
|||
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
|
||||
|
||||
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
|
||||
|
@ -191,8 +198,10 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Cell not found\n");
|
||||
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,74 +225,91 @@ 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) {
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 0) {
|
||||
pbch_decode_reset(&ue_mib.pbch);
|
||||
n = ue_mib_decode_aligned_frame(&ue_mib,
|
||||
sf_buffer, bch_payload_unpacked,
|
||||
NULL, &sfn_offset);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE MIB\n");
|
||||
go_exit=true;
|
||||
} 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);
|
||||
sfn = (sfn + sfn_offset)%1024;
|
||||
pbch_decoded = true;
|
||||
}
|
||||
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,
|
||||
sf_buffer, bch_payload_unpacked,
|
||||
NULL, &sfn_offset);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE MIB\n");
|
||||
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;
|
||||
state = DECODE_SIB;
|
||||
}
|
||||
}
|
||||
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_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++;
|
||||
}
|
||||
|
||||
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 (pbch_decoded) {
|
||||
/* 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);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
|
||||
}
|
||||
nof_trials++;
|
||||
snr = VEC_CMA(chest_dl_get_snr(&ue_dl.chest), snr, nof_trials);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 9) {
|
||||
if (pbch_decoded) {
|
||||
if (ue_sync_get_sfidx(&ue_sync) == 9) {
|
||||
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
|
||||
} 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);
|
||||
}
|
||||
#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);
|
||||
|
||||
}
|
||||
|
||||
sf_cnt++;
|
||||
} // Main loop
|
||||
|
||||
|
||||
ue_dl_free(&ue_dl);
|
||||
ue_mib_free(&ue_mib);
|
||||
ue_sync_free(&ue_sync);
|
||||
|
|
|
@ -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,12 +114,17 @@ 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,
|
||||
uint32_t N_id_2);
|
||||
uint32_t N_id_2);
|
||||
|
||||
/* Gets the Physical CellId from the last call to synch_run() */
|
||||
LIBLTE_API int sync_get_cell_id(sync_t *q);
|
||||
|
@ -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,
|
||||
uint8_t *data,
|
||||
uint32_t sf_idx,
|
||||
uint32_t sfn,
|
||||
uint16_t rnti);
|
||||
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 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
|
|
@ -76,10 +76,7 @@ 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));
|
||||
|
@ -381,7 +381,11 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], float
|
|||
demod_soft_sigma_set(&q->demod, 1.0);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ int sss_synch_m0m1_partial(sss_synch_t *q, cf_t *input, uint32_t M, cf_t ce[2*N_
|
|||
|
||||
extract_pair_sss(q, input, ce, y);
|
||||
|
||||
corr_all_sz_partial(y[0], q->fc_tables[q->N_id_2].s, M, q->corr_output_m0);
|
||||
corr_all_sz_partial(y[0], q->fc_tables[q->N_id_2].s, M, q->corr_output_m0);
|
||||
*m0 = vec_max_fi(q->corr_output_m0, N_SSS);
|
||||
if (m0_value) {
|
||||
*m0_value = q->corr_output_m0[*m0];
|
||||
|
|
|
@ -67,7 +67,7 @@ int pss_synch_init_N_id_2(cf_t *pss_signal_time, cf_t *pss_signal_freq, uint32_t
|
|||
vec_sc_prod_cfc(pss_signal_freq, 1.0/PSS_LEN, pss_signal_freq, fft_size);
|
||||
|
||||
dft_plan_free(&plan);
|
||||
|
||||
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
return ret;
|
||||
|
@ -95,7 +95,8 @@ 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;
|
||||
float M_norm=0, M_ext=0;
|
||||
|
||||
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;
|
||||
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)];
|
||||
|
||||
if (M_norm > M_ext) {
|
||||
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;
|
||||
}
|
||||
|
||||
sss_synch_m0m1_diff(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value);
|
||||
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);
|
||||
|
@ -197,7 +211,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error finding PSS peak\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
mean_peak = VEC_CMA(peak_value, mean_peak, frame_cnt);
|
||||
|
||||
if (peak_value >= threshold) {
|
||||
|
@ -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;
|
||||
ret = CS_CELL_NOT_DETECTED;
|
||||
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,59 +225,59 @@ 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 == q->current_rnti) {
|
||||
found_dci++;
|
||||
q->nof_pdcch_detected++;
|
||||
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;
|
||||
}
|
||||
|
||||
if (q->current_rnti != SIRNTI) {
|
||||
rvidx = ra_dl.rv_idx;
|
||||
}
|
||||
if (rvidx == 0) {
|
||||
if (pdsch_harq_setup(&q->harq_process[0], ra_dl.mcs, &ra_dl.prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
if (q->harq_process[0].mcs.mod > 0) {
|
||||
ret = pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), data, sf_idx,
|
||||
&q->harq_process[0], rvidx);
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
q->pkt_errors++;
|
||||
} else if (ret == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling pdsch_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
} else if (ret == LIBLTE_SUCCESS) {
|
||||
if (VERBOSE_ISINFO()) {
|
||||
INFO("Decoded Message: ", 0);
|
||||
vec_fprint_hex(stdout, data, ra_dl.mcs.tbs);
|
||||
}
|
||||
}
|
||||
q->pkts_total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crc_rem == rnti) {
|
||||
q->nof_pdcch_detected++;
|
||||
if (dci_msg_to_ra_dl(&dci_msg, 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 {
|
||||
rvidx = ra_dl.rv_idx;
|
||||
}
|
||||
if (rvidx == 0) {
|
||||
if (pdsch_harq_setup(&q->harq_process[0], ra_dl.mcs, &ra_dl.prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
}
|
||||
if (q->harq_process[0].mcs.mod > 0) {
|
||||
ret = pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, chest_dl_get_noise_estimate(&q->chest), data, sf_idx,
|
||||
&q->harq_process[0], rvidx);
|
||||
if (ret == LIBLTE_ERROR) {
|
||||
q->pkt_errors++;
|
||||
} else if (ret == LIBLTE_ERROR_INVALID_INPUTS) {
|
||||
fprintf(stderr, "Error calling pdsch_decode()\n");
|
||||
return LIBLTE_ERROR;
|
||||
} else if (ret == LIBLTE_SUCCESS) {
|
||||
if (VERBOSE_ISINFO()) {
|
||||
INFO("Decoded Message: ", 0);
|
||||
vec_fprint_hex(stdout, data, ra_dl.mcs.tbs);
|
||||
}
|
||||
}
|
||||
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,23 +85,23 @@ 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) {
|
||||
perror("malloc");
|
||||
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) {
|
||||
INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n",
|
||||
q->sf_idx, sync_get_sf_idx(&q->strack),
|
||||
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;
|
||||
q->sf_idx = sync_get_sf_idx(&q->strack);
|
||||
}
|
||||
} 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
si_sched->window_length_ms = get_window(sib1->si_WindowLength);
|
||||
if (si_window_length) {
|
||||
*si_window_length = 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…
Reference in New Issue