Fixed PRACH example

This commit is contained in:
ismagom 2015-03-02 11:11:44 +01:00
parent d5a0be5e92
commit 99df252279
14 changed files with 454 additions and 251 deletions

View File

@ -65,17 +65,9 @@ LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
double freq,
double off);
LIBLTE_API int cuhd_recv(void *h,
void *data,
uint32_t nsamples,
bool blocking);
LIBLTE_API int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
LIBLTE_API void cuhd_get_time(void *h,
time_t *secs,
double *frac_secs);
LIBLTE_API double cuhd_set_tx_srate(void *h,
double freq);
@ -93,6 +85,32 @@ LIBLTE_API double cuhd_set_tx_freq_offset(void *h,
double freq,
double off);
LIBLTE_API int cuhd_recv(void *h,
void *data,
uint32_t nsamples,
bool blocking);
LIBLTE_API int cuhd_recv_with_time(void *h,
void *data,
uint32_t nsamples,
time_t *secs,
double *frac_secs);
LIBLTE_API int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
time_t secs,
double frac_secs);
LIBLTE_API int cuhd_recv_timed2(void *h,
void *data,
uint32_t nsamples,
time_t secs,
double frac_secs,
bool is_start_of_burst,
bool is_end_of_burst);
LIBLTE_API int cuhd_send(void *h,
void *data,
uint32_t nsamples,
@ -102,10 +120,18 @@ LIBLTE_API int cuhd_send(void *h,
LIBLTE_API int cuhd_send_timed(void *h,
void *data,
int nsamples,
int blocking,
time_t secs,
double frac_secs);
LIBLTE_API int cuhd_send_timed2(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool is_start_of_burst,
bool is_end_of_burst);
#ifdef __cplusplus
}
#endif

View File

@ -156,11 +156,12 @@ double cuhd_set_rx_srate(void *h, double freq)
handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate();
/*
if ((int) ret != (int) freq) {
handler->usrp->set_master_clock_rate(freq);
handler->usrp->set_rx_rate(freq);
}
*/
return freq;
}
@ -213,39 +214,56 @@ int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
}
}
int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs)
int cuhd_recv_with_time(void *h,
void *data,
uint32_t nsamples,
time_t *secs,
double *frac_secs)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::rx_metadata_t md;
*secs = -1;
*frac_secs = -1;
int p;
if (blocking) {
int n=0;
complex_t *data_c = (complex_t*) data;
do {
p=handler->rx_stream->recv(&data_c[n], nsamples-n, md);
if (p == -1) {
return -1;
}
if(*secs < 0){
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
}
n+=p;
} while(n<nsamples);
return n;
} else {
p = handler->rx_stream->recv(data, nsamples, md, 0.0);
int p = handler->rx_stream->recv(data, nsamples, md, 0.0);
if (secs && frac_secs) {
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
return p;
*frac_secs = md.time_spec.get_frac_secs();
}
return p;
}
int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
time_t secs,
double frac_secs)
{
return cuhd_recv_timed2(h, data, nsamples, secs, frac_secs, true, true);
}
int cuhd_recv_timed2(void *h,
void *data,
uint32_t nsamples,
time_t secs,
double frac_secs,
bool is_start_of_burst,
bool is_end_of_burst)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::rx_metadata_t md;
md.start_of_burst = is_start_of_burst;
md.end_of_burst = is_end_of_burst;
md.has_time_spec = true;
md.time_spec = uhd::time_spec_t(secs, frac_secs);
return handler->rx_stream->recv(data, nsamples, md);
}
void cuhd_get_time(void *h, time_t *secs, double *frac_secs)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::time_spec_t now = handler->usrp->get_time_now();
*secs = now.get_full_secs();
*frac_secs = now.get_frac_secs();
}
void cuhd_set_tx_antenna(void *h, char *name)
@ -301,32 +319,28 @@ int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
}
}
int cuhd_send_timed(void *h,
void *data,
int nsamples,
int blocking,
time_t secs,
double frac_secs) {
double frac_secs)
{
return cuhd_send_timed2(h, data, nsamples, secs, frac_secs, true, true);
}
int cuhd_send_timed2(void *h,
void *data,
int nsamples,
time_t secs,
double frac_secs,
bool is_start_of_burst,
bool is_end_of_burst)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst = true;
md.start_of_burst = is_start_of_burst;
md.end_of_burst = is_end_of_burst;
md.has_time_spec = true;
md.time_spec = uhd::time_spec_t(secs, frac_secs);
if (blocking) {
int n=0,p;
complex_t *data_c = (complex_t*) data;
do {
p=handler->tx_stream->send(&data_c[n], nsamples-n, md);
md.has_time_spec = false;
if (p == -1) {
return -1;
}
n+=p;
} while(n<nsamples);
return nsamples;
} else {
return handler->tx_stream->send(data, nsamples, md, 0.0);
}
return handler->tx_stream->send(data, nsamples, md);
}

View File

@ -261,7 +261,7 @@ int main(int argc, char **argv) {
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),
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), SIRNTI,
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);

View File

@ -394,7 +394,7 @@ int main(int argc, char **argv) {
if (prog_args.rnti != SIRNTI) {
n = ue_dl_decode(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync));
} else {
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync),
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data_packed, ue_sync_get_sfidx(&ue_sync), SIRNTI,
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
}
if (n < 0) {

View File

@ -151,7 +151,7 @@ void sig_int_handler(int signo)
int cuhd_recv_wrapper_timed(void *h, void *data, uint32_t nsamples, timestamp_t *uhd_time) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv_timed(h, data, nsamples, 1, &uhd_time->full_secs, &uhd_time->frac_secs);
return cuhd_recv_with_time(h, data, nsamples, &uhd_time->full_secs, &uhd_time->frac_secs);
}
extern float mean_exec_time;
@ -291,7 +291,7 @@ int rar_to_ra_pusch(rar_msg_t *rar, ra_pusch_t *ra, uint32_t nof_prb) {
}
ra->type2_alloc.riv = riv;
ra->mcs_idx = rar->mcs;
printf("b: %d, RIV: %d\n", b, riv);
ra_type2_from_riv(riv, &ra->type2_alloc.L_crb, &ra->type2_alloc.RB_start,
nof_prb, nof_prb);
@ -315,7 +315,8 @@ int main(int argc, char **argv) {
timestamp_t uhd_time;
timestamp_t next_tx_time;
const uint8_t conn_request_msg[] = {0x20, 0x06, 0x1F, 0x5C, 0x2C, 0x04, 0xB2, 0xAC, 0xF6};
uint8_t data[100];
parse_args(&prog_args, argc, argv);
printf("Opening UHD device...\n");
@ -383,8 +384,9 @@ int main(int argc, char **argv) {
refsignal_ul_t drms;
refsignal_drms_pusch_cfg_t pusch_cfg;
pusch_cfg.nof_prb = 3;
bzero(&pusch_cfg, sizeof(refsignal_drms_pusch_cfg_t));
pusch_cfg.nof_prb = 3;
pusch_cfg.beta_pusch = 1.0;
if (refsignal_ul_init(&drms, cell)) {
fprintf(stderr, "Error initiating refsignal_ul\n");
exit(-1);
@ -395,7 +397,9 @@ int main(int argc, char **argv) {
exit(-1);
}
for (uint32_t i=0;i<2;i++) {
refsignal_dmrs_pusch_gen(&drms, &pusch_cfg, 2*4+i, &drms_signal[i*RE_X_RB*pusch_cfg.nof_prb]);
if (refsignal_dmrs_pusch_gen(&drms, &pusch_cfg, 2*4+i, &drms_signal[i*RE_X_RB*pusch_cfg.nof_prb])) {
fprintf(stderr, "Error generating PUSCH DRMS signals\n");
}
}
if (pusch_init(&pusch, cell)) {
@ -420,7 +424,7 @@ int main(int argc, char **argv) {
exit(-1);
}
bzero(ul_signal, sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
cf_t *sf_symbols = vec_malloc(sizeof(cf_t) * SF_LEN_PRB(cell.nof_prb));
if (!sf_symbols) {
perror("malloc");
@ -444,10 +448,11 @@ int main(int argc, char **argv) {
// Register Ctrl+C handler
signal(SIGINT, sig_int_handler);
cuhd_start_rx_stream(uhd);
struct timeval tdata[3];
uint16_t ra_rnti;
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
@ -485,11 +490,10 @@ int main(int argc, char **argv) {
timestamp_add(&next_tx_time, 0, 0.01); // send next frame (10 ms)
printf("Send prach sfn: %d. Last frame time = %.6f, send prach time = %.6f\n",
sfn, timestamp_real(&uhd_time), timestamp_real(&next_tx_time));
cuhd_send_timed(uhd, prach_buffers[7], prach_buffer_len, 1,
cuhd_send_timed(uhd, prach_buffers[7], prach_buffer_len,
next_tx_time.full_secs, next_tx_time.frac_secs);
uint16_t ra_rnti = 2;
ue_dl_set_rnti(&ue_dl, ra_rnti);
ra_rnti = 2;
rar_window_start = sfn+1;
rar_window_stop = sfn+3;
state = RECV_RAR;
@ -499,29 +503,32 @@ int main(int argc, char **argv) {
if ((sfn == rar_window_start && ue_sync_get_sfidx(&ue_sync) > 3) || sfn > rar_window_start) {
gettimeofday(&tdata[1], NULL);
printf("Looking for RAR in sfn: %d sf_idx: %d\n", sfn, ue_sync_get_sfidx(&ue_sync));
n = ue_dl_decode(&ue_dl, sf_buffer, data_rx, ue_sync_get_sfidx(&ue_sync));
n = ue_dl_decode_rnti(&ue_dl, sf_buffer, data_rx, ra_rnti, ue_sync_get_sfidx(&ue_sync));
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
} else if (n > 0) {
printf("RAR received %d bits: ", n);
vec_fprint_hex(stdout, data_rx, n);
gettimeofday(&tdata[2], NULL);
get_time_interval(tdata);
printf("time exec DL: %d\n",tdata[0].tv_usec);
gettimeofday(&tdata[1], NULL);
rar_unpack(data_rx, &rar_msg);
rar_msg_fprint(stdout, &rar_msg);
pusch_set_rnti(&pusch, rar_msg.temp_c_rnti);
rar_to_ra_pusch(&rar_msg, &ra_pusch, cell.nof_prb);
ra_pusch_fprint(stdout, &ra_pusch, cell.nof_prb);
ra_ul_alloc(&prb_alloc, &ra_pusch, 0, cell.nof_prb);
printf("Sending ConnectionRequest in sfn: %d sf_idx: %d\n", sfn, ue_sync_get_sfidx(&ue_sync));
verbose=VERBOSE_INFO;
if (harq_setup_ul(&pusch_harq, ra_pusch.mcs, 0, (ue_sync_get_sfidx(&ue_sync)+6)%10, &prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
exit(-1);;
}
if (pusch_encode(&pusch, &pusch_harq, (uint8_t*) conn_request_msg, sf_symbols)) {
bit_pack_vector((uint8_t*) conn_request_msg, data, ra_pusch.mcs.tbs);
if (pusch_encode_rnti(&pusch, &pusch_harq, data, rar_msg.temp_c_rnti, sf_symbols)) {
fprintf(stderr, "Error encoding TB\n");
exit(-1);
}
@ -531,16 +538,32 @@ int main(int argc, char **argv) {
lte_ifft_run_sf(&fft, sf_symbols, ul_signal);
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
timestamp_copy(&next_tx_time, &uhd_time);
timestamp_add(&next_tx_time, 0, 0.006); // send after 6 sub-frames (6 ms)
printf("Send PUSCH sfn: %d. Last frame time = %.6f, send PUSCH time = %.6f\n",
sfn, timestamp_real(&uhd_time), timestamp_real(&next_tx_time));
gettimeofday(&tdata[2], NULL);
get_time_interval(tdata);
printf("time exec: %d\n",tdata[0].tv_usec);
cuhd_send_timed(uhd, ul_signal, SF_LEN_PRB(cell.nof_prb), 1,
next_tx_time.full_secs, next_tx_time.frac_secs);
printf("time exec UL: %d\n",tdata[0].tv_usec);
gettimeofday(&tdata[1], NULL);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
gettimeofday(&tdata[2], NULL);
get_time_interval(tdata);
printf("time to stop RX: %d\n",tdata[0].tv_usec);
ue_sync_get_last_timestamp(&ue_sync, &uhd_time);
float time_adv_sec = ((float) rar_msg.timing_adv_cmd - 31 - 25) * 16 /(15000*2048);
vec_sc_prod_cfc(ul_signal, 2, ul_signal, SF_LEN_PRB(cell.nof_prb));
vec_fprint_c(stdout, sf_symbols, 300);
timestamp_copy(&next_tx_time, &uhd_time);
timestamp_add(&next_tx_time, 0, 0.006 + time_adv_sec); // send after 6 sub-frames (6 ms)
printf("Send %d samples PUSCH sfn: %d. Last frame time = %.6f, send PUSCH time = %.6f TA: %f\n",
SF_LEN_PRB(cell.nof_prb), sfn, timestamp_real(&uhd_time), timestamp_real(&next_tx_time), time_adv_sec);
cuhd_send_timed(uhd, ul_signal, SF_LEN_PRB(cell.nof_prb),
next_tx_time.full_secs, next_tx_time.frac_secs);
go_exit = 1;
}
if (sfn >= rar_window_stop) {

View File

@ -84,6 +84,12 @@ LIBLTE_API int pdsch_encode(pdsch_t *q,
uint8_t *data,
cf_t *sf_symbols[MAX_PORTS]);
LIBLTE_API int pdsch_encode_rnti(pdsch_t *q,
harq_t *harq_process,
uint8_t *data,
uint16_t rnti,
cf_t *sf_symbols[MAX_PORTS]);
LIBLTE_API int pdsch_decode(pdsch_t *q,
harq_t *harq_process,
cf_t *sf_symbols,
@ -91,6 +97,14 @@ LIBLTE_API int pdsch_decode(pdsch_t *q,
float noise_estimate,
uint8_t *data);
LIBLTE_API int pdsch_decode_rnti(pdsch_t *q,
harq_t *harq_process,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
float noise_estimate,
uint16_t rnti,
uint8_t *data);
LIBLTE_API float pdsch_average_noi(pdsch_t *q);
LIBLTE_API uint32_t pdsch_last_noi(pdsch_t *q);

View File

@ -92,12 +92,25 @@ LIBLTE_API int pusch_encode(pusch_t *q,
uint8_t *data,
cf_t *sf_symbols);
LIBLTE_API int pusch_encode_rnti(pusch_t *q,
harq_t *harq_process,
uint8_t *data,
uint16_t rnti,
cf_t *sf_symbols);
LIBLTE_API int pusch_uci_encode(pusch_t *q,
harq_t *harq_process,
uint8_t *data,
uci_data_t uci_data,
cf_t *sf_symbols);
LIBLTE_API int pusch_uci_encode_rnti(pusch_t *q,
harq_t *harq,
uint8_t *data,
uci_data_t uci_data,
uint16_t rnti,
cf_t *sf_symbols);
LIBLTE_API int pusch_decode(pusch_t *q,
harq_t *harq_process,
cf_t *sf_symbols,

View File

@ -89,10 +89,17 @@ LIBLTE_API int ue_dl_decode(ue_dl_t * q,
uint8_t *data,
uint32_t sf_idx);
LIBLTE_API int ue_dl_decode_rnti(ue_dl_t * q,
cf_t *input,
uint8_t *data,
uint16_t rnti,
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,
uint16_t rnti,
uint32_t rvidx);
LIBLTE_API void ue_dl_reset(ue_dl_t *q);

View File

@ -284,13 +284,10 @@ int refsignal_dmrs_pusch_gen(refsignal_ul_t *q, refsignal_drms_pusch_cfg_t *cfg,
u, v, alpha, N_sz, get_q(u,v,N_sz));
}
vec_fprint_f(stdout, q->tmp_arg, RE_X_RB*cfg->nof_prb);
// Do complex exponential and adjust amplitude
for (int i=0;i<RE_X_RB*cfg->nof_prb;i++) {
r_pusch[i] = cfg->beta_pusch * cexpf(I*(q->tmp_arg[i] + alpha*i));
}
vec_fprint_c(stdout, r_pusch, RE_X_RB*cfg->nof_prb);
ret = 0;
}
return ret;

View File

@ -302,6 +302,10 @@ void pdsch_free(pdsch_t *q) {
}
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions
*/
int pdsch_set_rnti(pdsch_t *q, uint16_t rnti) {
uint32_t i;
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
@ -315,10 +319,27 @@ int pdsch_set_rnti(pdsch_t *q, uint16_t rnti) {
return LIBLTE_SUCCESS;
}
int pdsch_decode(pdsch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate, uint8_t *data) {
if (q != NULL &&
sf_symbols != NULL &&
data != NULL &&
harq != NULL)
{
if (q->rnti_is_set) {
return pdsch_decode_rnti(q, harq, sf_symbols, ce, noise_estimate, q->rnti, data);
} else {
fprintf(stderr, "Must call pdsch_set_rnti() before calling pdsch_decode()\n");
return LIBLTE_ERROR;
}
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/** Decodes the PDSCH from the received symbols
*/
int pdsch_decode(pdsch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_estimate, uint8_t *data)
int pdsch_decode_rnti(pdsch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
float noise_estimate, uint16_t rnti, uint8_t *data)
{
/* Set pointers for layermapping & precoding */
@ -331,71 +352,90 @@ int pdsch_decode(pdsch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce[MAX_PORTS]
harq != NULL)
{
if (q->rnti_is_set) {
INFO("Decoding PDSCH SF: %d, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
INFO("Decoding PDSCH SF: %d, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
/* extract symbols */
n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], &harq->dl_alloc, harq->sf_idx);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
/* extract symbols */
n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], &harq->dl_alloc, harq->sf_idx);
if (n != harq->nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", harq->nof_re, n);
return LIBLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = pdsch_get(q, ce[i], q->ce[i], &harq->dl_alloc, harq->sf_idx);
if (n != harq->nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", harq->nof_re, n);
return LIBLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = pdsch_get(q, ce[i], q->ce[i], &harq->dl_alloc, harq->sf_idx);
if (n != harq->nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", harq->nof_re, n);
return LIBLTE_ERROR;
}
}
/* TODO: only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
predecoding_single(&q->precoding, q->pdsch_symbols[0], q->ce[0], q->pdsch_d,
harq->nof_re, noise_estimate);
} else {
predecoding_diversity(&q->precoding, q->pdsch_symbols[0], q->ce, x, q->cell.nof_ports,
harq->nof_re, noise_estimate);
layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports,
harq->nof_re / q->cell.nof_ports);
}
/* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization
*/
demod_soft_sigma_set(&q->demod, sqrt(0.5));
demod_soft_table_set(&q->demod, &q->mod[harq->mcs.mod]);
demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, harq->nof_re);
/* descramble */
scrambling_f_offset(&q->seq_pdsch[harq->sf_idx], q->pdsch_e, 0, harq->nof_bits);
return dlsch_decode(&q->dl_sch, harq, q->pdsch_e, data);
} else {
fprintf(stderr, "Must call pdsch_set_rnti() before calling pdsch_decode()\n");
return LIBLTE_ERROR;
}
/* TODO: only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
predecoding_single(&q->precoding, q->pdsch_symbols[0], q->ce[0], q->pdsch_d,
harq->nof_re, noise_estimate);
} else {
predecoding_diversity(&q->precoding, q->pdsch_symbols[0], q->ce, x, q->cell.nof_ports,
harq->nof_re, noise_estimate);
layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports,
harq->nof_re / q->cell.nof_ports);
}
/* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization
*/
demod_soft_sigma_set(&q->demod, sqrt(0.5));
demod_soft_table_set(&q->demod, &q->mod[harq->mcs.mod]);
demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, harq->nof_re);
/* descramble */
if (rnti != q->rnti) {
sequence_t seq;
if (sequence_pdsch(&seq, rnti, 0, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
return LIBLTE_ERROR;
}
scrambling_f_offset(&seq, q->pdsch_e, 0, harq->nof_bits);
sequence_free(&seq);
} else {
scrambling_f_offset(&q->seq_pdsch[harq->sf_idx], q->pdsch_e, 0, harq->nof_bits);
}
return dlsch_decode(&q->dl_sch, harq, q->pdsch_e, data);
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
int pdsch_encode(pdsch_t *q, harq_t *harq, uint8_t *data, cf_t *sf_symbols[MAX_PORTS])
{
if (q != NULL &&
data != NULL &&
harq != NULL)
{
if (q->rnti_is_set) {
return pdsch_encode_rnti(q, harq, data, q->rnti, sf_symbols);
} else {
fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n");
return LIBLTE_ERROR;
}
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission
*/
int pdsch_encode(pdsch_t *q, harq_t *harq, uint8_t *data, cf_t *sf_symbols[MAX_PORTS])
int pdsch_encode_rnti(pdsch_t *q, harq_t *harq, uint8_t *data, uint16_t rnti, cf_t *sf_symbols[MAX_PORTS])
{
int i;
/* Set pointers for layermapping & precoding */
@ -407,64 +447,69 @@ int pdsch_encode(pdsch_t *q, harq_t *harq, uint8_t *data, cf_t *sf_symbols[MAX_P
harq != NULL)
{
if (q->rnti_is_set) {
for (i=0;i<q->cell.nof_ports;i++) {
if (sf_symbols[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
if (harq->mcs.tbs == 0) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->mcs.tbs > harq->nof_bits) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) harq->mcs.tbs / harq->nof_bits);
for (i=0;i<q->cell.nof_ports;i++) {
if (sf_symbols[i] == NULL) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->nof_re > q->max_re) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
harq->nof_re, q->max_re, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
if (dlsch_encode(&q->dl_sch, harq, data, q->pdsch_e)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
scrambling_b_offset(&q->seq_pdsch[harq->sf_idx], (uint8_t*) q->pdsch_e, 0, harq->nof_bits);
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pdsch_e, q->pdsch_d, harq->nof_bits);
/* TODO: only diversity supported */
if (q->cell.nof_ports > 1) {
layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, harq->nof_re);
precoding_diversity(&q->precoding, x, q->pdsch_symbols, q->cell.nof_ports,
harq->nof_re / q->cell.nof_ports);
} else {
memcpy(q->pdsch_symbols[0], q->pdsch_d, harq->nof_re * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq->dl_alloc, harq->sf_idx);
}
ret = LIBLTE_SUCCESS;
} else {
fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n");
}
if (harq->mcs.tbs == 0) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->mcs.tbs > harq->nof_bits) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) harq->mcs.tbs / harq->nof_bits);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->nof_re > q->max_re) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
harq->nof_re, q->max_re, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
if (dlsch_encode(&q->dl_sch, harq, data, q->pdsch_e)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
if (rnti != q->rnti) {
sequence_t seq;
if (sequence_pdsch(&seq, rnti, 0, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
return LIBLTE_ERROR;
}
scrambling_b_offset(&seq, (uint8_t*) q->pdsch_e, 0, harq->nof_bits);
sequence_free(&seq);
} else {
scrambling_b_offset(&q->seq_pdsch[harq->sf_idx], (uint8_t*) q->pdsch_e, 0, harq->nof_bits);
}
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pdsch_e, q->pdsch_d, harq->nof_bits);
/* TODO: only diversity supported */
if (q->cell.nof_ports > 1) {
layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, harq->nof_re);
precoding_diversity(&q->precoding, x, q->pdsch_symbols, q->cell.nof_ports,
harq->nof_re / q->cell.nof_ports);
} else {
memcpy(q->pdsch_symbols[0], q->pdsch_d, harq->nof_re * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq->dl_alloc, harq->sf_idx);
}
ret = LIBLTE_SUCCESS;
}
return ret;
}

View File

@ -278,6 +278,9 @@ void pusch_free(pusch_t *q) {
}
/* Precalculate the PUSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions */
int pusch_set_rnti(pusch_t *q, uint16_t rnti) {
uint32_t i;
@ -292,7 +295,6 @@ int pusch_set_rnti(pusch_t *q, uint16_t rnti) {
return LIBLTE_SUCCESS;
}
/** Decodes the PUSCH from the received symbols
*/
int pusch_decode(pusch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce, float noise_estimate, uint8_t *data)
@ -351,16 +353,38 @@ int pusch_decode(pusch_t *q, harq_t *harq, cf_t *sf_symbols, cf_t *ce, float noi
}
}
int pusch_encode(pusch_t *q, harq_t *harq_process, uint8_t *data, cf_t *sf_symbols)
int pusch_encode_rnti(pusch_t *q, harq_t *harq_process, uint8_t *data, uint16_t rnti, cf_t *sf_symbols)
{
uci_data_t uci_data;
bzero(&uci_data, sizeof(uci_data_t));
return pusch_uci_encode(q, harq_process, data, uci_data, sf_symbols);
return pusch_uci_encode_rnti(q, harq_process, data, uci_data, rnti, sf_symbols);
}
int pusch_encode(pusch_t *q, harq_t *harq_process, uint8_t *data, cf_t *sf_symbols)
{
if (q->rnti_is_set) {
uci_data_t uci_data;
bzero(&uci_data, sizeof(uci_data_t));
return pusch_uci_encode_rnti(q, harq_process, data, uci_data, q->rnti, sf_symbols);
} else {
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
return LIBLTE_ERROR;
}
}
int pusch_uci_encode(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, cf_t *sf_symbols)
{
if (q->rnti_is_set) {
return pusch_uci_encode_rnti(q, harq, data, uci_data, q->rnti, sf_symbols);
} else {
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
return LIBLTE_ERROR;
}
}
/** Converts the PUSCH data bits to symbols mapped to the slot ready for transmission
*/
int pusch_uci_encode(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, cf_t *sf_symbols)
int pusch_uci_encode_rnti(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_data, uint16_t rnti, cf_t *sf_symbols)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
@ -368,41 +392,52 @@ int pusch_uci_encode(pusch_t *q, harq_t *harq, uint8_t *data, uci_data_t uci_dat
data != NULL &&
harq != NULL)
{
if (q->rnti_is_set) {
if (harq->mcs.tbs > harq->nof_bits) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) harq->mcs.tbs / harq->nof_bits);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->nof_re > q->max_re) {
fprintf(stderr, "Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n",
harq->nof_re, q->max_re, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PUSCH SF: %d, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
if (ulsch_uci_encode(&q->dl_sch, harq, data, uci_data, q->pusch_g, q->pusch_q)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
scrambling_b_offset_pusch(&q->seq_pusch[harq->sf_idx], (uint8_t*) q->pusch_q, 0, harq->nof_bits);
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pusch_q, q->pusch_d, harq->nof_bits);
dft_precoding(&q->dft_precoding, q->pusch_d, q->pusch_z,
harq->ul_alloc.L_prb, harq->nof_symb);
/* mapping to resource elements */
pusch_put(q, harq, q->pusch_z, sf_symbols);
ret = LIBLTE_SUCCESS;
} else {
fprintf(stderr, "Must call pusch_set_rnti() to set the encoder/decoder RNTI\n");
if (harq->mcs.tbs > harq->nof_bits) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) harq->mcs.tbs / harq->nof_bits);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq->nof_re > q->max_re) {
fprintf(stderr, "Error too many RE per subframe (%d). PUSCH configured for %d RE (%d PRB)\n",
harq->nof_re, q->max_re, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PUSCH SF: %d, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
harq->sf_idx, lte_mod_string(harq->mcs.mod), harq->mcs.tbs, harq->nof_re, harq->nof_bits, harq->rv);
bzero(q->pusch_q, harq->nof_bits);
if (ulsch_uci_encode(&q->dl_sch, harq, data, uci_data, q->pusch_g, q->pusch_q)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
printf("before scram: ");
vec_fprint_b(stdout, q->pusch_q, harq->nof_bits);
if (rnti != q->rnti) {
sequence_t seq;
if (sequence_pusch(&seq, rnti, 2 * harq->sf_idx, q->cell.id, harq->nof_bits)) {
return LIBLTE_ERROR;
}
scrambling_b_offset_pusch(&seq, (uint8_t*) q->pusch_q, 0, harq->nof_bits);
sequence_free(&seq);
} else {
scrambling_b_offset_pusch(&q->seq_pusch[harq->sf_idx], (uint8_t*) q->pusch_q, 0, harq->nof_bits);
}
printf("after scram: ");
vec_fprint_b(stdout, q->pusch_q, harq->nof_bits);
mod_modulate(&q->mod[harq->mcs.mod], (uint8_t*) q->pusch_q, q->pusch_d, harq->nof_bits);
dft_precoding(&q->dft_precoding, q->pusch_d, q->pusch_z,
harq->ul_alloc.L_prb, harq->nof_symb);
/* mapping to resource elements */
pusch_put(q, harq, q->pusch_z, sf_symbols);
ret = LIBLTE_SUCCESS;
}
return ret;
}

View File

@ -194,7 +194,6 @@ int main(int argc, char **argv) {
frame_cnt = 0;
last_peak = 0;
mean_peak = 0;
int peak_offset = 0;
float cfo;
float mean_cfo = 0;
uint32_t m0, m1;
@ -205,12 +204,27 @@ int main(int argc, char **argv) {
bzero(&ssync, sizeof(sync_t));
ssync.fft_size = fft_size;
timestamp_t cur_time;
cuhd_get_time(uhd, &cur_time.full_secs, &cur_time.frac_secs);
// wait 1 sec to start
timestamp_add(&cur_time, 1, 0);
double period = 0.005; // 5 ms
double period_diff = 0;
double nsamples_offset_x_sf;
int last_peak_idx = 0;
bool is_first = true;
while(frame_cnt < nof_frames || nof_frames == -1) {
n = cuhd_recv(uhd, buffer, flen - peak_offset, 1);
timestamp_add(&cur_time, 0, period + period_diff);
n = cuhd_recv_timed2(uhd, buffer, flen, cur_time.full_secs, cur_time.frac_secs, is_first, false);
if (n < 0) {
fprintf(stderr, "Error receiving samples\n");
exit(-1);
}
is_first = false;
peak_idx = pss_synch_find_pss(&pss, buffer, &peak_value);
if (peak_idx < 0) {
@ -222,7 +236,13 @@ int main(int argc, char **argv) {
if (peak_value >= threshold) {
nof_det++;
if (last_peak_idx) {
nsamples_offset_x_sf = VEC_CMA(((double) peak_idx - (double) last_peak_idx ), nsamples_offset_x_sf, frame_cnt);
period_diff += nsamples_offset_x_sf / (flen*2*100);
}
last_peak_idx = peak_idx;
if (peak_idx >= fft_size) {
// Estimate CFO
@ -288,10 +308,10 @@ int main(int argc, char **argv) {
frame_cnt++;
printf("[%5d]: Pos: %5d, PSR: %4.1f (~%4.1f) Pdet: %4.2f, "
printf("[%5d]: Pos: %5d (%f), 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_idx, period_diff*1000000,
peak_value, mean_peak,
(float) nof_det/frame_cnt,
(float) nof_nopeakdet/frame_cnt, mean_cfo*15,

View File

@ -142,6 +142,10 @@ void ue_dl_free(ue_dl_t *q) {
}
}
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
* For the connection procedure, use pusch_encode_rnti() or pusch_decode_rnti() functions
*/
void ue_dl_set_rnti(ue_dl_t *q, uint16_t rnti) {
q->current_rnti = rnti;
pdsch_set_rnti(&q->pdsch, rnti);
@ -167,10 +171,14 @@ const uint32_t nof_common_formats = 2;
* - 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);
return ue_dl_decode_sib(q, input, data, sf_idx, q->current_rnti, 0);
}
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_rnti(ue_dl_t *q, cf_t *input, uint8_t *data, uint16_t rnti, uint32_t sf_idx) {
return ue_dl_decode_sib(q, input, data, sf_idx, rnti, 0);
}
int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx)
{
uint32_t cfi, i;
float cfi_corr;
@ -207,12 +215,12 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
}
/* Generate PDCCH candidates */
if (q->current_rnti == SIRNTI) {
if (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->current_rnti);
nof_locations = pdcch_ue_locations(&q->pdcch, locations, MAX_CANDIDATES, sf_idx, cfi, rnti);
formats = ue_formats;
nof_formats = nof_ue_formats;
}
@ -233,16 +241,16 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
}
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
if (crc_rem == q->current_rnti) {
if (crc_rem == rnti) {
found_dci++;
q->nof_pdcch_detected++;
if (dci_msg_to_ra_dl(&dci_msg, q->current_rnti, q->cell, cfi, &ra_dl)) {
if (dci_msg_to_ra_dl(&dci_msg, rnti, q->cell, cfi, &ra_dl)) {
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
return LIBLTE_ERROR;
}
if (q->current_rnti != SIRNTI) {
if (rnti != SIRNTI) {
rvidx = ra_dl.rv_idx;
}
if (harq_setup_dl(&q->harq_process[0], ra_dl.mcs, rvidx, sf_idx, &ra_dl.prb_alloc)) {
@ -250,9 +258,9 @@ int ue_dl_decode_sib(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, ui
return LIBLTE_ERROR;
}
if (q->harq_process[0].mcs.mod > 0 && q->harq_process[0].mcs.tbs >= 0) {
ret = pdsch_decode(&q->pdsch, &q->harq_process[0], q->sf_symbols,
q->ce, chest_dl_get_noise_estimate(&q->chest),
data);
ret = pdsch_decode_rnti(&q->pdsch, &q->harq_process[0], q->sf_symbols,
q->ce, chest_dl_get_noise_estimate(&q->chest),
rnti, data);
if (ret == LIBLTE_ERROR) {
q->pkt_errors++;
} else if (ret == LIBLTE_ERROR_INVALID_INPUTS) {

View File

@ -35,6 +35,7 @@ for prb=3
if (error(k) > 10^-3)
k=1;
end
read_real
k=k+1;
end
end