Improved PCFICH detection using soft bit correlation.

master
ismagom 10 years ago
parent 10ce33d47d
commit 5e6abc7186

@ -68,7 +68,7 @@ bool cuhd_rx_wait_lo_locked(void *h)
{ {
double report = 0.0; double report = 0.0;
while (isLocked(h) && report < 3.0) { while (isLocked(h) && report < 3000.0) {
report += 0.1; report += 0.1;
usleep(1000); usleep(1000);
} }
@ -139,7 +139,7 @@ int cuhd_open(char *args, void **h)
int cuhd_close(void *h) int cuhd_close(void *h)
{ {
cuhd_stop_rx_stream(h); cuhd_stop_rx_stream(h);
/** Something else to close the USRP?? */ /** Something else to close the USRP?? */
return 0; return 0;
} }
@ -147,15 +147,17 @@ int cuhd_close(void *h)
double cuhd_set_rx_srate(void *h, double freq) double cuhd_set_rx_srate(void *h, double freq)
{ {
cuhd_handler *handler = static_cast < cuhd_handler * >(h); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
printf("Changing sampling freq now to %.2f MHz\n", freq/1000000);
handler->usrp->set_rx_rate(freq); handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate(); printf("Done\n");
/*
if ((int) ret != (int) freq) { if ((int) ret != (int) freq) {
printf("Got %f!=%f. setting master clock rate to %f\n",ret, freq, freq); printf("Got %f!=%f. setting master clock rate to %f\n",ret, freq, freq);
handler->usrp->set_master_clock_rate(freq); handler->usrp->set_master_clock_rate(freq);
handler->usrp->set_rx_rate(freq); handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate();
} }
return ret; */
return freq;
} }
double cuhd_set_rx_gain(void *h, double gain) double cuhd_set_rx_gain(void *h, double gain)
@ -168,8 +170,10 @@ double cuhd_set_rx_gain(void *h, double gain)
double cuhd_set_rx_freq(void *h, double freq) double cuhd_set_rx_freq(void *h, double freq)
{ {
cuhd_handler *handler = static_cast < cuhd_handler * >(h); cuhd_handler *handler = static_cast < cuhd_handler * >(h);
printf("Tunning receiver to %.3f MHz\n", (double ) freq/1000000);
handler->usrp->set_rx_freq(freq); handler->usrp->set_rx_freq(freq);
return handler->usrp->get_rx_freq(); printf("Done\n");
return freq;
} }
double cuhd_set_rx_freq_offset(void *h, double freq, double off) { double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
@ -196,7 +200,7 @@ int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
std::cout << "\nError code: " << md.to_pp_string() << "\n\n"; std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
} }
#endif #endif
} while (n < nsamples); } while (n < nsamples && md.error_code == uhd::rx_metadata_t::ERROR_CODE_NONE);
return nsamples; return nsamples;
} else { } else {
return handler->rx_stream->recv(data, nsamples, md, 0.0); return handler->rx_stream->recv(data, nsamples, md, 0.0);

@ -92,5 +92,3 @@ IF(${CUHD_FIND} GREATER -1)
ELSE(${CUHD_FIND} GREATER -1) ELSE(${CUHD_FIND} GREATER -1)
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
ENDIF(${CUHD_FIND} GREATER -1) ENDIF(${CUHD_FIND} GREATER -1)
add_subdirectory(cell_scanner)

@ -1,28 +0,0 @@
#
# Copyright 2012-2013 The libLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# 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/.
#
#################################################################
# CELL SCANNER TEST
#################################################################
add_executable(cell_scanner_test cell_scanner_test.c cell_scanner.c ../cuhd_utils.c)
target_link_libraries(cell_scanner_test lte_phy lte_rrc cuhd)

@ -1,283 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "../cuhd_utils.h"
#include "cell_scanner.h"
#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
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
int cell_scanner_init(cell_scanner_t *q, cell_scanner_config_t *config)
{
bzero(q, sizeof(cell_scanner_t));
memcpy(&q->config, config, sizeof(cell_scanner_config_t));
printf("Opening UHD device...\n");
if (cuhd_open(q->config.uhd_args, &q->uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
/* Set receiver gain */
cuhd_set_rx_gain(q->uhd, B210_DEFAULT_GAIN);
return 0;
}
void cell_scanner_close(cell_scanner_t *q) {
cuhd_close(q->uhd);
}
int cell_scanner_all_cells(cell_scanner_t *q, float frequency, cell_scanner_result_t *result)
{
return cell_scanner_cell(q, frequency, -1, result);
}
#define MAX_SINFO 10
int cell_scanner_cell(cell_scanner_t *q, float frequency, int N_id_2, cell_scanner_result_t *result)
{
int ret;
cf_t *sf_buffer;
lte_cell_t cell;
int64_t sf_cnt;
ue_sync_t ue_sync;
ue_mib_t ue_mib;
ue_dl_t ue_dl;
lte_fft_t fft;
chest_dl_t chest;
uint32_t nframes_measure=0;
uint32_t nof_trials = 0;
uint32_t sfn = 0; // system frame number
int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset;
uint8_t data[1024];
uint8_t data_unpacked[1024];
bzero(result, sizeof(cell_scanner_result_t));
/* set receiver frequency */
cuhd_set_rx_freq(q->uhd, (double) frequency);
cuhd_rx_wait_lo_locked(q->uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) frequency/1000000);
cell_search_cfg_t cfg;
cfg.max_frames_pss = q->config.pss_max_frames;
cfg.max_frames_pbch = q->config.pbch_max_frames;
cfg.threshold = q->config.cell_detect_early_stop_threshold;
ret = cuhd_search_and_decode_mib(q->uhd, &cfg, N_id_2, &cell);
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
} else if (ret == 0) {
printf("Cell not found\n");
exit(0);
}
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(q->uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
return LIBLTE_ERROR;
}
INFO("Stopping UHD and flushing buffer...\n",0);
cuhd_stop_rx_stream(q->uhd);
cuhd_flush_buffer(q->uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, q->uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
if (ue_dl_init(&ue_dl, cell, 1234)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
if (ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1);
}
/* 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;
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
return -1;
}
if (chest_dl_init(&chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
return -1;
}
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
cf_t *ce[MAX_PORTS];
for (int i=0;i<MAX_PORTS;i++) {
ce[i] = vec_malloc(sizeof(cf_t) * sf_re);
}
cuhd_start_rx_stream(q->uhd);
memcpy(&result->phy_cell, &cell, sizeof(lte_cell_t));
chest_dl_t *chest_ptr = &ue_dl.chest;
bool mib_decoded = false;
bool sib_decoded = false;
/* Main loop */
while (sf_cnt < q->config.measure_avg_nof_frames) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
if (!mib_decoded) {
if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode(&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;
mib_decoded = true;
}
}
}
/* We are looking for SI Blocks, search only in appropiate places */
if (mib_decoded && !sib_decoded &&
(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);
} else if (n == 0) {
nof_trials++;
} else {
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("Decoded SIB1. Cell ID: 0x%x\n", cell_info.cell_id);
result->cell_id = cell_info.cell_id;
bcch_dlsch_fprint(dlsch_msg, stdout);
sib_decoded = true;
}
}
} else {
chest_ptr = &chest;
/* Run FFT for all subframe data */
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
chest_dl_estimate(&chest, sf_symbols, ce, ue_sync_get_sfidx(&ue_sync));
}
result->rssi = VEC_CMA(vec_avg_power_cf(sf_buffer,SF_LEN(lte_symbol_sz(cell.nof_prb))),
result->rssi,nframes_measure);
result->rsrq = VEC_EMA(chest_dl_get_rsrq(chest_ptr),result->rsrq,0.01);
result->rsrp = VEC_CMA(chest_dl_get_rsrp(chest_ptr),result->rsrp,nframes_measure);
result->snr = VEC_EMA(chest_dl_get_snr(chest_ptr),result->snr,0.01);
nframes_measure++;
// Plot and Printf
if ((nframes_measure%10) == 0) {
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %5.1f dBm, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(result->rssi*1000)-B210_DEFAULT_GAIN_CORREC,
10*log10(result->rsrp*1000)-B210_DEFAULT_GAIN_CORREC,
10*log10(result->rsrq), 10*log10(result->snr));
if (verbose != VERBOSE_NONE) {
printf("\n");
}
}
if (ue_sync_get_sfidx(&ue_sync) == 9) {
sfn++;
if (sfn == 1024) {
sfn = 0;
}
}
} 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
// Correct RSRP and RSSI measurements
result->rssi /= pow(10, 8);
result->rsrp /= pow(10, 8);
ue_sync_free(&ue_sync);
return 0;
}

@ -1,64 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "liblte/phy/phy.h"
typedef struct {
int pss_max_frames;
int pbch_max_frames;
float cell_detect_early_stop_threshold;
int measure_avg_nof_frames;
char *uhd_args;
} cell_scanner_config_t;
typedef struct {
lte_cell_t phy_cell;
uint32_t cell_id;
float rsrp;
float rsrq;
float rssi;
float snr;
} cell_scanner_result_t;
typedef struct {
cell_scanner_config_t config;
void *uhd;
} cell_scanner_t;
int cell_scanner_init(cell_scanner_t *q,
cell_scanner_config_t *config);
void cell_scanner_close(cell_scanner_t *q);
int cell_scanner_all_cells(cell_scanner_t *q,
float frequency,
cell_scanner_result_t *result);
int cell_scanner_cell(cell_scanner_t *q,
float frequency,
int N_id_2,
cell_scanner_result_t *result);

@ -1,143 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cell_scanner.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
int force_N_id_2;
char *uhd_args;
float uhd_freq;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [alnv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "alnvf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
int main(int argc, char **argv) {
prog_args_t prog_args;
cell_scanner_result_t result;
cell_scanner_config_t cfg;
cell_scanner_t cs;
parse_args(&prog_args, argc, argv);
// Peak-to-sidelobe ratio (PSR) threshold for cell detection early stopping.
cfg.cell_detect_early_stop_threshold = 20.0; // This is a normal value.
// maximum 5 ms frames that will be scanned maximum in the case the threshold is not exceed
// ie for bad cells
cfg.pss_max_frames = 50; // this is 250 ms
// maximum 5 ms frames that will be received to decode the PBCH
// ie for bad cells
cfg.pbch_max_frames = 500; // this is 2500 ms
// Number of 1 ms subframes that will be used to compute rsrp, rsrq, snr, etc average
cfg.measure_avg_nof_frames = 1000; // 1 sec
cfg.uhd_args = prog_args.uhd_args;
// Init USRP
if (cell_scanner_init(&cs, &cfg)) {
fprintf(stderr, "Error initiating cell scanner\n");
exit(-1);
}
// Scan for a frequency
if (prog_args.force_N_id_2 < 0) {
// We have 2 options, either we scan for the three possible N_id_2 root sequences...
cell_scanner_all_cells(&cs, prog_args.uhd_freq, &result);
} else {
// or we scan for a single one.
cell_scanner_cell(&cs, prog_args.uhd_freq, prog_args.force_N_id_2, &result);
}
printf("\nResult: CellID: %d, PHYID: %d, RSRP: %.1f dBm, RSRQ: %.1f dB, SNR: %.1f dB\n",
result.cell_id, result.phy_cell.id,
10*log10(result.rsrp*1000), 10*log10(result.rsrq), 10*log10(result.snr));
}

@ -33,13 +33,12 @@
#include "liblte/phy/mimo/precoding.h" #include "liblte/phy/mimo/precoding.h"
#include "liblte/phy/mimo/layermap.h" #include "liblte/phy/mimo/layermap.h"
#include "liblte/phy/modem/mod.h" #include "liblte/phy/modem/mod.h"
#include "liblte/phy/modem/demod_hard.h" #include "liblte/phy/modem/demod_soft.h"
#include "liblte/phy/scrambling/scrambling.h" #include "liblte/phy/scrambling/scrambling.h"
#include "liblte/phy/phch/regs.h" #include "liblte/phy/phch/regs.h"
#define PCFICH_CFI_LEN 32 #define PCFICH_CFI_LEN 32
#define PCFICH_RE PCFICH_CFI_LEN/2 #define PCFICH_RE PCFICH_CFI_LEN/2
#define PCFICH_MAX_DISTANCE 5
typedef _Complex float cf_t; typedef _Complex float cf_t;
@ -57,12 +56,18 @@ typedef struct LIBLTE_API {
cf_t pcfich_x[MAX_PORTS][PCFICH_RE]; cf_t pcfich_x[MAX_PORTS][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE]; cf_t pcfich_d[PCFICH_RE];
// cfi table in floats
float cfi_table_float[3][PCFICH_CFI_LEN];
/* bit message */ /* bit message */
uint8_t data[PCFICH_CFI_LEN]; uint8_t data[PCFICH_CFI_LEN];
/* received soft bits */
float data_f[PCFICH_CFI_LEN];
/* tx & rx objects */ /* tx & rx objects */
modem_table_t mod; modem_table_t mod;
demod_hard_t demod; demod_soft_t demod;
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME]; sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
precoding_t precoding; precoding_t precoding;
@ -80,7 +85,7 @@ LIBLTE_API int pcfich_decode(pcfich_t *q,
float noise_estimate, float noise_estimate,
uint32_t subframe, uint32_t subframe,
uint32_t *cfi, uint32_t *cfi,
uint32_t *distance); float *corr_result);
LIBLTE_API int pcfich_encode(pcfich_t *q, LIBLTE_API int pcfich_encode(pcfich_t *q,
uint32_t cfi, uint32_t cfi,

@ -148,6 +148,7 @@ int pbch_init(pbch_t *q, lte_cell_t cell) {
demod_soft_init(&q->demod); demod_soft_init(&q->demod);
demod_soft_table_set(&q->demod, &q->mod); demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX); demod_soft_alg_set(&q->demod, APPROX);
if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) { if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) {
goto clean; goto clean;
} }

@ -42,11 +42,15 @@
#include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/debug.h"
// Table 5.3.4-1 // Table 5.3.4-1
static uint8_t cfi_table[4][PCFICH_CFI_LEN] = { { 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, static uint8_t cfi_table[4][PCFICH_CFI_LEN] = {
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 }, { 1, 0, 1, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 },
{ 1, 0, 1,
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
0, 1, 1, 0 }, { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 },
0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // reserved 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // reserved
}; };
@ -74,12 +78,13 @@ int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) {
fprintf(stderr, "Error initializing precoding\n"); fprintf(stderr, "Error initializing precoding\n");
} }
if (modem_table_lte(&q->mod, LTE_QPSK, false)) { if (modem_table_lte(&q->mod, LTE_QPSK, true)) {
goto clean; goto clean;
} }
demod_hard_init(&q->demod); demod_soft_init(&q->demod);
demod_hard_table_set(&q->demod, LTE_QPSK); demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX);
for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) {
if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) { if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) {
@ -87,6 +92,13 @@ int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) {
} }
} }
/* convert cfi bit tables to floats for demodulation */
for (int i=0;i<3;i++) {
for (int j=0;j<PCFICH_CFI_LEN;j++) {
q->cfi_table_float[i][j] = (float) 2.0*cfi_table[i][j]-1.0;
}
}
q->nof_symbols = PCFICH_RE; q->nof_symbols = PCFICH_RE;
ret = LIBLTE_SUCCESS; ret = LIBLTE_SUCCESS;
@ -112,26 +124,22 @@ void pcfich_free(pcfich_t *q) {
/** Finds the CFI with minimum distance with the vector of received 32 bits. /** Finds the CFI with minimum distance with the vector of received 32 bits.
* Saves the CFI value in the cfi pointer and returns the distance. * Saves the CFI value in the cfi pointer and returns the distance.
*/ */
int pcfich_cfi_decode(uint8_t bits[PCFICH_CFI_LEN], uint32_t *cfi) { float pcfich_cfi_decode(pcfich_t *q, uint32_t *cfi) {
int i, j; int i;
int distance, index = -1; int index = 0;
int min = 32; float max_corr = 0;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
distance = 0; float corr = vec_dot_prod_fff(q->cfi_table_float[i], q->data_f, PCFICH_CFI_LEN);
for (j = 0; j < PCFICH_CFI_LEN; j++) { if (corr > max_corr) {
distance += (bits[j] ^ cfi_table[i][j]); max_corr = corr;
}
DEBUG("CFI=%d, distance:%d\n", i, distance);
if (distance < min) {
min = distance;
index = i; index = i;
} }
} }
if (cfi) { if (cfi) {
*cfi = index + 1; *cfi = index + 1;
} }
return min; return max_corr;
} }
/** Encodes the CFI producing a vector of 32 bits. /** Encodes the CFI producing a vector of 32 bits.
@ -151,8 +159,8 @@ int pcfich_cfi_encode(int cfi, uint8_t bits[PCFICH_CFI_LEN]) {
* Returns 1 if successfully decoded the CFI, 0 if not and -1 on error * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error
*/ */
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float noise_estimate, int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float noise_estimate,
uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) { uint32_t nsubframe, uint32_t *cfi, float *corr_result)
int dist; {
/* Set pointers for layermapping & precoding */ /* Set pointers for layermapping & precoding */
int i; int i;
@ -200,21 +208,18 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float no
} }
/* demodulate symbols */ /* demodulate symbols */
demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); demod_soft_sigma_set(&q->demod, 1.0);
demod_soft_demodulate(&q->demod, q->pcfich_d, q->data_f, q->nof_symbols);
/* Scramble with the sequence for slot nslot */ /* Scramble with the sequence for slot nslot */
scrambling_b(&q->seq_pcfich[nsubframe], q->data); scrambling_f(&q->seq_pcfich[nsubframe], q->data_f);
/* decode CFI */ /* decode CFI */
dist = pcfich_cfi_decode(q->data, cfi); float corr = pcfich_cfi_decode(q, cfi);
if (distance) { if (corr_result) {
*distance = dist; *corr_result = corr;
}
if (dist < PCFICH_MAX_DISTANCE) {
return 1;
} else {
return 0;
} }
return 1;
} else { } else {
return LIBLTE_ERROR_INVALID_INPUTS; return LIBLTE_ERROR_INVALID_INPUTS;
} }

@ -190,7 +190,8 @@ void base_free() {
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t cfi, distance; uint32_t cfi;
float cfi_corr;
int n; int n;
if (argc < 3) { if (argc < 3) {
@ -226,8 +227,9 @@ int main(int argc, char **argv) {
INFO("Decoding PCFICH\n", 0); INFO("Decoding PCFICH\n", 0);
n = pcfich_decode(&pcfich, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), 0, &cfi, &distance);
printf("cfi: %d, distance: %d\n", cfi, distance); n = pcfich_decode(&pcfich, fft_buffer, ce, chest_dl_get_noise_estimate(&chest), 0, &cfi, &cfi_corr);
printf("cfi: %d, distance: %f\n", cfi, cfi_corr);
base_free(); base_free();
@ -238,7 +240,7 @@ int main(int argc, char **argv) {
printf("Could not decode PCFICH\n"); printf("Could not decode PCFICH\n");
exit(-1); exit(-1);
} else { } else {
if (distance < 4 && cfi == 1) { if (cfi_corr > 4 && cfi == 1) {
exit(0); exit(0);
} else { } else {
exit(-1); exit(-1);

@ -82,8 +82,9 @@ int main(int argc, char **argv) {
cf_t *ce[MAX_PORTS]; cf_t *ce[MAX_PORTS];
int nof_re; int nof_re;
cf_t *slot_symbols[MAX_PORTS]; cf_t *slot_symbols[MAX_PORTS];
uint32_t cfi, cfi_rx, nsf, distance; uint32_t cfi, cfi_rx, nsf;
int cid, max_cid; int cid, max_cid;
float corr_res;
parse_args(argc,argv); parse_args(argc,argv);
@ -139,16 +140,11 @@ int main(int argc, char **argv) {
slot_symbols[0][j] += slot_symbols[i][j]; slot_symbols[0][j] += slot_symbols[i][j];
} }
} }
if (pcfich_decode(&pcfich, slot_symbols[0], ce, 0, nsf, &cfi_rx, &distance)<0) { if (pcfich_decode(&pcfich, slot_symbols[0], ce, 0, nsf, &cfi_rx, &corr_res)<0) {
exit(-1);
}
INFO("cfi_tx: %d, cfi_rx: %d, ns: %d, distance: %d\n",
cfi, cfi_rx, nsf, distance);
if (distance) {
printf("Error\n");
exit(-1); exit(-1);
} }
INFO("cfi_tx: %d, cfi_rx: %d, ns: %d, distance: %f\n",
cfi, cfi_rx, nsf, corr_res);
} }
} }
pcfich_free(&pcfich); pcfich_free(&pcfich);

@ -70,12 +70,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
if (chest_dl_init(&chest, cell)) { if (chest_dl_init(&chest, cell)) {
fprintf(stderr, "Error initializing equalizer\n"); mexErrMsgTxt("Error initializing equalizer\n");
return; return;
} }
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) { if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initializing FFT\n"); mexErrMsgTxt("Error initializing FFT\n");
return; return;
} }
@ -85,7 +85,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
if (pcfich_init(&pcfich, &regs, cell)) { if (pcfich_init(&pcfich, &regs, cell)) {
fprintf(stderr, "Error creating PBCH object\n"); mexErrMsgTxt("Error creating PBCH object\n");
return; return;
} }
@ -124,8 +124,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
uint32_t cfi, distance; uint32_t cfi;
int n = pcfich_decode(&pcfich, input_fft, ce, noise_power, sf_idx, &cfi, &distance); float corr_res;
int n = pcfich_decode(&pcfich, input_fft, ce, noise_power, sf_idx, &cfi, &corr_res);
if (nlhs >= 1) { if (nlhs >= 1) {
if (n < 0) { if (n < 0) {

@ -174,7 +174,8 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx) {
int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32_t rvidx) 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; uint32_t cfi, i;
float cfi_corr;
ra_pdsch_t ra_dl; ra_pdsch_t ra_dl;
dci_location_t locations[MAX_CANDIDATES]; dci_location_t locations[MAX_CANDIDATES];
dci_msg_t dci_msg; dci_msg_t dci_msg;
@ -195,12 +196,12 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
/* First decode PCFICH and obtain CFI */ /* First decode PCFICH and obtain CFI */
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce,
chest_dl_get_noise_estimate(&q->chest), sf_idx, &cfi, &cfi_distance)<0) { chest_dl_get_noise_estimate(&q->chest), sf_idx, &cfi, &cfi_corr)<0) {
fprintf(stderr, "Error decoding PCFICH\n"); fprintf(stderr, "Error decoding PCFICH\n");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); INFO("Decoded CFI=%d with correlation %.2f\n", cfi, cfi_corr);
if (regs_set_cfi(&q->regs, cfi)) { if (regs_set_cfi(&q->regs, cfi)) {
fprintf(stderr, "Error setting CFI\n"); fprintf(stderr, "Error setting CFI\n");

@ -201,7 +201,7 @@ int ue_mib_sync_decode(ue_mib_sync_t * q,
int ret = LIBLTE_ERROR_INVALID_INPUTS; int ret = LIBLTE_ERROR_INVALID_INPUTS;
cf_t *sf_buffer = NULL; cf_t *sf_buffer = NULL;
uint32_t nof_frames = 0; uint32_t nof_frames = 0;
int mib_ret; int mib_ret = MIB_NOTFOUND;
if (q != NULL) if (q != NULL)
{ {

@ -272,7 +272,7 @@ int track_peak_no(ue_sync_t *q) {
/* if we missed too many PSS go back to FIND */ /* if we missed too many PSS go back to FIND */
q->frame_no_cnt++; q->frame_no_cnt++;
if (q->frame_no_cnt >= TRACK_MAX_LOST) { if (q->frame_no_cnt >= TRACK_MAX_LOST) {
printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); INFO("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt);
q->state = SF_FIND; q->state = SF_FIND;
} else { } else {
INFO("Tracking peak not found. Peak %.3f, %d lost\n", INFO("Tracking peak not found. Peak %.3f, %d lost\n",

Loading…
Cancel
Save