int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bool put) { int i; cf_t *ptr; assert(cell_id >= 0); if (put) { ptr = input; output += nof_prb * RE_X_RB / 2 - 36; } else { ptr = output; input += nof_prb * RE_X_RB / 2 - 36; } /* symbol 0 & 1 */ for (i = 0; i < 2; i++) { prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); } /* symbols 2 & 3 */ if (CP_ISNORM(cp)) { for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); } } else { prb_cp(&input, &output, 6); prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); } if (put) { return input - ptr; } else { return output - ptr; } }
/** * Returns the number of REGs in a PRB * 36.211 Section 6.2.4 */ int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, lte_cp_t cp) { switch (symbol) { case 0: return 2; case 1: switch (nof_port) { case 1: case 2: return 3; case 4: return 2; default: return LIBLTE_ERROR; } break; case 2: return 3; case 3: if (CP_ISNORM(cp)) { return 3; } else { return 2; } default: return LIBLTE_ERROR; } }
/* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space * to correlate */ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, lte_cp_t cp) { int sss_idx, ret; sss_synch_set_N_id_2(&q->sss, q->N_id_2); /* Make sure we have enough room to find SSS sequence */ 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; } DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos); 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); if (ret >= 0) { q->N_id_1 = (uint32_t) ret; DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", q->N_id_1, q->sf_idx, CP_ISNORM(q->cp)?"Normal":"Extended"); return 1; } else { q->N_id_1 = 1000; return LIBLTE_SUCCESS; } }
int pbch_cp(cf_t *input, cf_t *output, lte_cell_t cell, bool put) { int i; cf_t *ptr; if (put) { ptr = input; output += cell.nof_prb * RE_X_RB / 2 - 36; } else { ptr = output; input += cell.nof_prb * RE_X_RB / 2 - 36; } /* symbol 0 & 1 */ for (i = 0; i < 2; i++) { prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); if (put) { output += cell.nof_prb * RE_X_RB - 2*36; } else { input += cell.nof_prb * RE_X_RB - 2*36; } } /* symbols 2 & 3 */ if (CP_ISNORM(cell.cp)) { for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); if (put) { output += cell.nof_prb * RE_X_RB - 2*36; } else { input += cell.nof_prb * RE_X_RB - 2*36; } } } else { prb_cp(&input, &output, 6); if (put) { output += cell.nof_prb * RE_X_RB - 2*36; } else { input += cell.nof_prb * RE_X_RB - 2*36; } prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); } if (put) { return input - ptr; } else { return output - ptr; } }
/** Initializes the PBCH transmitter and receiver. * At the receiver, the field nof_ports in the cell structure indicates the * maximum number of BS transmitter ports to look for. */ int pbch_init(pbch_t *q, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && lte_cell_isvalid(&cell)) { ret = LIBLTE_ERROR; bzero(q, sizeof(pbch_t)); q->cell = cell; if (modem_table_lte(&q->mod, LTE_QPSK, true)) { goto clean; } demod_soft_init(&q->demod); demod_soft_table_set(&q->demod, &q->mod); demod_soft_alg_set(&q->demod, APPROX); if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) { goto clean; } uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { goto clean; } if (crc_init(&q->crc, LTE_CRC16, 16)) { goto clean; } q->encoder.K = 7; q->encoder.R = 3; q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); q->nof_symbols = (CP_ISNORM(q->cell.cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_d) { goto clean; } int i; for (i = 0; i < q->cell.nof_ports; i++) { q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; } q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_x[i]) { goto clean; } q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_symbols[i]) { goto clean; } } q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->pbch_llr) { goto clean; } q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->temp) { goto clean; } q->pbch_rm_f = malloc(sizeof(float) * 120); if (!q->pbch_rm_f) { goto clean; } q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->pbch_rm_b) { goto clean; } q->data = malloc(sizeof(char) * 40); if (!q->data) { goto clean; } q->data_enc = malloc(sizeof(char) * 120); if (!q->data_enc) { goto clean; } ret = LIBLTE_SUCCESS; } clean: if (ret == LIBLTE_ERROR) { pbch_free(q); } return ret; }
int main(int argc, char **argv) { int N_id_2, ns, find_ns; cf_t *buffer, *fft_buffer; cf_t pss_signal[PSS_LEN]; float sss_signal0[SSS_LEN]; // for subframe 0 float sss_signal5[SSS_LEN]; // for subframe 5 int cid, max_cid; uint32_t find_idx; sync_t sync; lte_fft_t ifft; parse_args(argc, argv); buffer = malloc(sizeof(cf_t) * FLEN); if (!buffer) { perror("malloc"); exit(-1); } fft_buffer = malloc(sizeof(cf_t) * 2 * FLEN); if (!fft_buffer) { perror("malloc"); exit(-1); } if (lte_ifft_init(&ifft, cp, 6)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } if (sync_init(&sync, FLEN, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } sync_set_threshold(&sync, 1, 1); if (cell_id == -1) { cid = 0; max_cid = 49; } else { cid = cell_id; max_cid = cell_id; } while(cid <= max_cid) { N_id_2 = cid%3; /* Generate PSS/SSS signals */ pss_generate(pss_signal, N_id_2); sss_generate(sss_signal0, sss_signal5, cid); for (ns=0;ns<2;ns++) { memset(buffer, 0, sizeof(cf_t) * FLEN); pss_put_slot(pss_signal, buffer, 6, cp); sss_put_slot(ns?sss_signal5:sss_signal0, buffer, 6, cp); /* Transform to OFDM symbols */ memset(fft_buffer, 0, sizeof(cf_t) * 2 * FLEN); lte_ifft_run_slot(&ifft, buffer, &fft_buffer[offset]); sync_find(&sync, fft_buffer, &find_idx); find_ns = sync_get_slot_id(&sync); printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset, ns, find_ns); if (find_idx != offset + 960) { printf("offset != find_offset: %d != %d\n", find_idx, offset + 960); exit(-1); } if (ns*10 != find_ns) { printf("ns != find_ns\n", 10 * ns, find_ns); exit(-1); } if (sync_get_cp(&sync) != cp) { printf("Detected CP should be %s\n", CP_ISNORM(cp)?"Normal":"Extended"); exit(-1); } } cid++; } free(fft_buffer); free(buffer); sync_free(&sync); lte_ifft_free(&ifft); printf("Ok\n"); exit(0); }
/** * Initializes REGs structure. * Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs * Returns 0 if OK, -1 on error */ int regs_init(regs_t *h, phich_resources_t phich_res, phich_length_t phich_len, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; uint32_t i, k; uint32_t j[4], jmax, prb; uint32_t n[4], vo; uint32_t max_ctrl_symbols; if (h != NULL && lte_cell_isvalid(&cell)) { bzero(h, sizeof(regs_t)); ret = LIBLTE_ERROR; max_ctrl_symbols = cell.nof_prb<10?4:3; vo = cell.id % 3; h->cell = cell; h->max_ctrl_symbols = max_ctrl_symbols; h->cfi_initiated = false; h->phich_res = phich_res; h->phich_len = phich_len; h->nof_regs = 0; for (i = 0; i < max_ctrl_symbols; i++) { n[i] = regs_num_x_symbol(i, h->cell.nof_ports, h->cell.cp); if (n[i] == -1) { return -1; } h->nof_regs += h->cell.nof_prb * n[i]; } INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell.id, h->cell.nof_prb, CP_ISNORM(h->cell.cp)?"Normal":"Extended"); h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); if (!h->regs) { perror("malloc"); goto clean_and_exit; } /* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */ bzero(j, sizeof(int) * 4); k = i = prb = jmax = 0; while (k < h->nof_regs) { if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) { fprintf(stderr, "Error initializing REGs\n"); goto clean_and_exit; } /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], h->regs[k].k0); */ j[i]++; k++; } i++; if (i == max_ctrl_symbols) { i = 0; jmax++; } if (jmax == 3) { prb++; bzero(j, sizeof(int) * 4); jmax = 0; } } if (regs_pcfich_init(h)) { fprintf(stderr, "Error initializing PCFICH REGs\n"); goto clean_and_exit; } if (regs_phich_init(h)) { fprintf(stderr, "Error initializing PHICH REGs\n"); goto clean_and_exit; } if (regs_pdcch_init(h)) { fprintf(stderr, "Error initializing PDCCH REGs\n"); goto clean_and_exit; } ret = LIBLTE_SUCCESS; } clean_and_exit: if (ret == LIBLTE_ERROR) { regs_free(h); } return ret; }
int main(int argc, char **argv) { phich_t phich; regs_t regs; int i, j; cf_t *ce[MAX_PORTS_CTRL]; int nof_re; cf_t *slot_symbols[MAX_PORTS_CTRL]; char ack[50][PHICH_NORM_NSEQUENCES], ack_rx; int nsf, distance; int cid, max_cid; int ngroup, nseq, max_nseq; parse_args(argc,argv); max_nseq = CP_ISNORM(cp)?PHICH_NORM_NSEQUENCES:PHICH_EXT_NSEQUENCES; nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; /* init memory */ for (i=0;i<MAX_PORTS_CTRL;i++) { ce[i] = malloc(sizeof(cf_t) * nof_re); if (!ce[i]) { perror("malloc"); exit(-1); } for (j=0;j<nof_re;j++) { ce[i][j] = 1; } slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); if (!slot_symbols[i]) { perror("malloc"); exit(-1); } } if (cell_id == -1) { cid = 0; max_cid = 503; } else { cid = cell_id; max_cid = cell_id; } while(cid <= max_cid) { printf("Testing CellID=%d...\n", cid); if (regs_init(®s, cid, nof_prb, nof_ports, phich_res, phich_length, cp)) { fprintf(stderr, "Error initiating regs\n"); exit(-1); } if (phich_init(&phich, ®s, cid, nof_prb, nof_ports, cp)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } for (nsf=0;nsf<10;nsf++) { phich_reset(&phich, slot_symbols); /* Transmit all PHICH groups and sequence numbers */ for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) { for (nseq=0;nseq<max_nseq;nseq++) { ack[ngroup][nseq] = rand()%2; phich_encode(&phich, ack[ngroup][nseq], ngroup, nseq, nsf, slot_symbols); } } /* combine outputs */ for (i=1;i<nof_ports;i++) { for (j=0;j<nof_re;j++) { slot_symbols[0][j] += slot_symbols[i][j]; } } /* Receive all PHICH groups and sequence numbers */ for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) { for (nseq=0;nseq<max_nseq;nseq++) { if (phich_decode(&phich, slot_symbols[0], ce, ngroup, nseq, nsf, &ack_rx, &distance)<0) { printf("Error decoding ACK\n"); exit(-1); } INFO("%d/%d, ack_tx: %d, ack_rx: %d, ns: %d, distance: %d\n", ngroup, nseq, ack[ngroup][nseq], ack_rx, nsf, distance); if (ack[ngroup][nseq] != ack_rx) { printf("Invalid received ACK: %d!=%d\n", ack[ngroup][nseq], ack_rx); exit(-1); } if (distance) { printf("Error\n"); exit(-1); } } } } phich_free(&phich); regs_free(®s); cid++; } for (i=0;i<MAX_PORTS_CTRL;i++) { free(ce[i]); free(slot_symbols[i]); } printf("OK\n"); exit(0); }
int main(int argc, char **argv) { int distance; int i, n; int ngroup, nseq, max_nseq; char ack_rx; if (argc < 3) { usage(argv[0]); exit(-1); } parse_args(argc,argv); max_nseq = CP_ISNORM(cp)?PHICH_NORM_NSEQUENCES:PHICH_EXT_NSEQUENCES; if (base_init()) { fprintf(stderr, "Error initializing memory\n"); exit(-1); } n = filesource_read(&fsrc, input_buffer, flen); lte_fft_run(&fft, input_buffer, fft_buffer); if (fmatlab) { fprintf(fmatlab, "infft="); vec_fprint_c(fmatlab, input_buffer, flen); fprintf(fmatlab, ";\n"); fprintf(fmatlab, "outfft="); vec_fprint_c(fmatlab, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB); fprintf(fmatlab, ";\n"); } /* Get channel estimates for each port */ for (i=0;i<nof_ports;i++) { chest_ce_slot_port(&chest, fft_buffer, ce[i], 0, i); if (fmatlab) { chest_fprint(&chest, fmatlab, 0, i); } } INFO("Decoding PHICH\n", 0); /* Receive all PHICH groups and sequence numbers */ for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) { for (nseq=0;nseq<max_nseq;nseq++) { if (phich_decode(&phich, fft_buffer, ce, ngroup, nseq, numsubframe, &ack_rx, &distance)<0) { printf("Error decoding ACK\n"); exit(-1); } INFO("%d/%d, ack_rx: %d, ns: %d, distance: %d\n", ngroup, nseq, ack_rx, numsubframe, distance); } } base_free(); fftwf_cleanup(); if (n < 0) { fprintf(stderr, "Error decoding phich\n"); exit(-1); } else if (n == 0) { printf("Could not decode phich\n"); exit(-1); } else { exit(0); } }
/** Initializes the PBCH transmitter and receiver */ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { int ret = -1; if (cell_id < 0) { return -1; } bzero(q, sizeof(pbch_t)); q->cell_id = cell_id; q->cp = cp; q->nof_prb = nof_prb; if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; } demod_soft_init(&q->demod); demod_soft_table_set(&q->demod, &q->mod); demod_soft_alg_set(&q->demod, APPROX); if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) { goto clean; } int poly[3] = { 0x6D, 0x4F, 0x57 }; if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { goto clean; } if (crc_init(&q->crc, LTE_CRC16, 16)) { goto clean; } q->encoder.K = 7; q->encoder.R = 3; q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_d) { goto clean; } int i; for (i = 0; i < MAX_PORTS_CTRL; i++) { q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; } q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_x[i]) { goto clean; } q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_symbols[i]) { goto clean; } } q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->pbch_llr) { goto clean; } q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->temp) { goto clean; } q->pbch_rm_f = malloc(sizeof(float) * 120); if (!q->pbch_rm_f) { goto clean; } q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); if (!q->pbch_rm_b) { goto clean; } q->data = malloc(sizeof(char) * 40); if (!q->data) { goto clean; } q->data_enc = malloc(sizeof(char) * 120); if (!q->data_enc) { goto clean; } ret = 0; clean: if (ret == -1) { pbch_free(q); } return ret; }
int sync_run(sync_t *q, cf_t *input) { int N_id_2, peak_pos[3], sss_idx_n, sss_idx_e; int m0, m1; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; float peak_value[3]; float mean_value[3]; float max=-999; int i; int peak_detected; if (q->force_N_id_2 == -1) { for (N_id_2=0;N_id_2<3;N_id_2++) { peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); } for (i=0;i<3;i++) { if (peak_value[i] > max) { max = peak_value[i]; N_id_2 = i; } } } else { N_id_2 = q->force_N_id_2; peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); } q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); /* If peak detected */ peak_detected = 0; if (peak_pos[N_id_2] - 128 >= 0) { if (q->pss_mode == ABSOLUTE) { if (peak_value[N_id_2] > q->threshold) { peak_detected = 1; } } else { if (q->peak_to_avg > q->threshold) { peak_detected = 1; } } } if (peak_detected) { q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[peak_pos[N_id_2]-128]); INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); if (q->sss_en) { /* Make sure we have enough room to find SSS sequence */ sss_idx_n = peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN)); sss_idx_e = peak_pos[N_id_2]-2*(128+CP(128,CPEXT_LEN)); if (q->detect_cp) { if (sss_idx_n < 0 || sss_idx_e < 0) { INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); return -1; } } else { if (CP_ISNORM(q->cp)) { if (sss_idx_n < 0) { INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); return -1; } } else { if (sss_idx_e < 0) { INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); return -1; } } } N_id_1_e = -1; N_id_1_n = -1; slot_id_e = -1; slot_id_n = -1; /* try Normal CP length */ if (q->detect_cp || CP_ISNORM(q->cp)) { sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n); slot_id_n = 2 * sss_synch_subframe(m0, m1); N_id_1_n = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); } if (q->detect_cp || CP_ISEXT(q->cp)) { /* Now try Extended CP length */ sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e); slot_id_e = 2 * sss_synch_subframe(m0, m1); N_id_1_e = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); } /* Correlation with extended CP hypoteshis is greater than with normal? */ if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) || CP_ISEXT(q->cp)) { q->cp = CPEXT; q->slot_id = slot_id_e; q->N_id_1 = N_id_1_e; /* then is normal CP */ } else { q->cp = CPNORM; q->slot_id = slot_id_n; q->N_id_1 = N_id_1_n; } q->N_id_2 = N_id_2; INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); } return peak_pos[N_id_2]; } else { return -1; } }