SDR - srsLTE Example - Pdsch_enodeb Home : www.sharetechnote.com |
srsLTE - Example - Pdsch_enodeb
This example is implemented by the source srsLTE\examples\Pdsch_enodeb.c. The functionality of this example is to generate I/Q data for LTE downlink radio frame into a file. This would be a very good example of understanding the overall process of generating a various downlink sigan (e.g, PSS, SSS, Reference Signal) and channels (PBCH, PDCCH, PDSCH) and combining all those signals and channels into a radio frame.
By setting a simple flag, you can let this function to generate the data into a file (meaning you don't need any RF hardware).
Since my main purpose is to understand the details of the code, not building a working hardware. I chose to look into the details of the code that generate various signals and channels into a file. I simplied the code which is directly related to this process and removing all error handling parts just leaving the parts that is directly related to the decoding process.
I hope this summary and additional comments help you to undertand the original source code in the project.
Now this page is still under progress and it will take a couple of weeks for me to complete the comments for the pages. However, just read through the function names and procedure in the code without any comments would give you some big picture of the process.
Case 1 : Generating eNB frame into a file
/** * * \section COPYRIGHT * * Copyright 2013-2015 Software Radio Systems Limited * * \section LICENSE * * This file is part of the srsLTE library. * * srsLTE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsLTE 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 Affero General Public License for more details. * * A copy of the GNU Affero 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/. * */ ....
// As you see, UE_CRNTI is hardcoded in this example. #define UE_CRNTI 0x1234
// You can define the basic Cell Proprties (e.g, Number of PRBs, Antenna Configuration, System BW, Cell ID etc) srslte_cell_t cell = { 25, // nof_prb 1, // nof_ports 0, // bw idx 0, // cell_id SRSLTE_CP_NORM, // cyclic prefix SRSLTE_PHICH_R_1, // PHICH resources SRSLTE_PHICH_NORM // PHICH length };
// Define CFI value and MCS idex uint32_t cfi=3; uint32_t mcs_idx = 1, last_mcs_idx = 1;
....
void usage(char *prog) { .... }
void parse_args(int argc, char **argv) { .... }
// Initialize all of the resourced that are required to generate and store physical layer signal data void base_init() {
// Create a buffer(array) that will store all the resource elements in the specified number of subframes sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
// Create a buffer(array) that will store all the OFDM symbol data in the specified number of subframes output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
// Open a file to store the generated I/Q data if (output_file_name) { if (strcmp(output_file_name, "NULL")) { if (srslte_filesink_init(&fsink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN)) { ... } null_file_sink = false; } else { null_file_sink = true; } } else { . .. }
....
// Initialize the array to store OFDM data if (srslte_ofdm_tx_init(&ifft, SRSLTE_CP_NORM, cell.nof_prb)) { .... } srslte_ofdm_set_normalize(&ifft, true);
// Initialize the array to store PBCH data if (srslte_pbch_init(&pbch, cell)) { .... }
// Initialize the array to store REG data if (srslte_regs_init(®s, cell)) { ... }
// Initialize the array to store PCFICH data if (srslte_pcfich_init(&pcfich, ®s, cell)) { .... }
// Initialize the array to REGs assigned for CFI if (srslte_regs_set_cfi(®s, cfi)) { .... }
// Initialize the array to store PDCCH data if (srslte_pdcch_init(&pdcch, ®s, cell)) { .... }
// Initialize the array to store PDSCH data if (srslte_pdsch_init(&pdsch, cell)) { .... }
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { .... } }
void base_free() { .... }
bool go_exit = false; void sig_int_handler(int signo) { ... }
uint32_t prbset_to_bitmask() { uint32_t mask=0; int nb = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); for (int i=0;i<nb;i++) { if (i >= prbset_orig && i < prbset_orig + prbset_num) { mask = mask | (0x1<<i); } } return reverse(mask)>>(32-nb); }
// Configure and initialize all the parameters and arrays that is necessary for RACH process int update_radl() {
bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); ra_dl.harq_process = 0; ra_dl.mcs_idx = mcs_idx; ra_dl.ndi = 0; ra_dl.rv_idx = 0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask();
srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); srslte_ra_dl_grant_t dummy_grant; srslte_ra_nbits_t dummy_nbits; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, true, &dummy_grant); srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits); srslte_ra_dl_grant_fprint(stdout, &dummy_grant); printf("Type new MCS index and press Enter: "); fflush(stdout);
return 0; }
/* Read new MCS from stdin */ int update_control() { char input[128];
fd_set set; FD_ZERO(&set); FD_SET(0, &set);
struct timeval to; to.tv_sec = 0; to.tv_usec = 0;
int n = select(1, &set, NULL, NULL, &to); if (n == 1) { // stdin ready if (fgets(input, sizeof(input), stdin)) { if(input[0] == 27) { switch(input[2]) { case RIGHT_KEY: if (prbset_orig + prbset_num < (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb))) prbset_orig++; break; case LEFT_KEY: if (prbset_orig > 0) prbset_orig--; break; case UP_KEY: if (prbset_num < (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb))) prbset_num++; break; case DOWN_KEY: last_prbset_num = prbset_num; if (prbset_num > 0) prbset_num--; break; } } else { last_mcs_idx = mcs_idx; mcs_idx = atoi(input); } bzero(input,sizeof(input)); if (update_radl()) { printf("Trying with last known MCS index\n"); mcs_idx = last_mcs_idx; prbset_num = last_prbset_num; return update_radl(); } } return 0; } else if (n < 0) { // error perror("select"); return -1; } else { return 0; } }
int main(int argc, char **argv) {
int nf=0, sf_idx=0, N_id_2=0;
// Create cf_t (complex number) array with the size of SRSLTE_PSS_LEN. This is to store the PSS (Primary Sync // Signal) data. Since PSS is made up of 62 data points, the size of this array (SRSLTE_PSS_LEN) is 62. cf_t pss_signal[SRSLTE_PSS_LEN];
// Create a float array with the size of SRSLTE_SSS_LEN. This is to store SSS (Secondary Sync Signal) transmitted // on subframe 0. Since PSS is made up of 62 data points, the size of this array (SRSLTE_SSS_LEN) is 62. // Since SSS does not have any imaginary part, it is generated as real number array. float sss_signal0[SRSLTE_SSS_LEN]; // for subframe 0
// Create a float array with the size of SRSLTE_SSS_LEN. This is to store SSS (Secondary Sync Signal) transmitted // on subframe 5. Since PSS is made up of 62 data points, the size of this array (SRSLTE_SSS_LEN) is 62. // Since SSS does not have any imaginary part, it is generated as real number array. float sss_signal5[SRSLTE_SSS_LEN]; // for subframe 5
// Create an array with the size of SRSLTE_BCH_PAYLOAD_LEN. This is to store the binary data of BCH. // Since this is BCH data before encoding process, the size of this array(SRSLTE_BCH_PAYLOAD_LEN) is 24. uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
int i;
// Create cf_t (complex number) pointer arrays with the size of SRSLTE_MAX_PORTS. This is to store the subframe // symbols. SRSLTE_MAX_PORTS is 4 as of now. cf_t *sf_symbols[SRSLTE_MAX_PORTS]; cf_t *slot1_symbols[SRSLTE_MAX_PORTS]; srslte_dci_msg_t dci_msg; srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30]; uint32_t sfn; srslte_chest_dl_t est;
parse_args(argc, argv);
// Calculate Cell Number (One of the three PSS sequence type) from cell ID N_id_2 = cell.id % 3;
// Calculate the total number of REs that is in the PRB region of one subframe. This include RE for all PHY channel // and signals (i.e, CRS, PDCCH, PDSCH etc). // SRSLTE_CP_NORM_NSYMB = 7 symbols (the number of OFDM symbole in one slot) // SRSLTE_NRE = 12 (the number of subcarriers in one RB) // cell.nof_prb = Number of PRBs that is specified by user sf_n_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE;
// TBD sf_n_samples = 2 * SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb));
// Set PHICH Parameters // SRSLTE_PHICH_NORM = 0 // SRSLTE_PHICH_R_1 = 2 cell.phich_length = SRSLTE_PHICH_NORM; cell.phich_resources = SRSLTE_PHICH_R_1; sfn = 0;
// Calculate the number of RBG(Resource Block Group) for the specified number of PRBs. // RBG varies depending on System BW and used for RA Type 0 prbset_num = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); last_prbset_num = prbset_num;
/* this *must* be called after setting slot_len_* */ // Create resources (e.g, arrays) for storing each physical channel data and OFDM signal
// Generate PSS for N_id_2 and store the result into the array pss_signal srslte_pss_generate(pss_signal, N_id_2);
// Generate SSS for subframe 0 and 5 for cell.id and store the result into the arrays sss_signal0 and sss_signal5 srslte_sss_generate(sss_signal0, sss_signal5, cell.id);
// Generate the Cell Specific Reference Signal using parameter set in the structure "cell" and store the result in // the array "est" if (srslte_chest_dl_init(&est, cell)) { .... }
// Create subframe buffer for each antenna port for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port // Copy the pointer of sf_buffer to sf_symbols[port]. // sf_buffer is created in base_init() sf_symbols[i] = sf_buffer;
// Get the pointer to the start of slot1 symbol and assign it to slot1_symbols[port] // SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp) would gives RE number of the start of Slot1 slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; }
#ifndef DISABLE_RF // I am removing this part, because I am not using UART hardware in this example #endif
// Configure and initialize all the parameters and arrays that is necessary for RACH process if (update_radl(sf_idx)) { exit(-1); }
if (net_port > 0) { // I am removing this part because I am interested only in PHY layer }
/* Initiate valid DCI locations */ for (i=0;i<SRSLTE_NSUBFRAMES_X_FRAME;i++) { srslte_pdcch_ue_locations(&pdcch, locations[i], 30, i, cfi, UE_CRNTI);
}
nf = 0;
bool send_data = false; srslte_softbuffer_tx_reset(&softbuffer);
#ifndef DISABLE_RF bool start_of_burst = true; #endif
while ((nf < nof_frames || nof_frames == -1) && !go_exit) { for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
if (sf_idx == 0 || sf_idx == 5) { srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); }
srslte_refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer);
srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { srslte_pbch_encode(&pbch, bch_payload, slot1_symbols); }
srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
/* Update DL resource allocation from control port */ if (update_control(sf_idx)) { fprintf(stderr, "Error updating parameters from control port\n"); }
/* Transmit PDCCH + PDSCH only when there is data to send */ if (net_port > 0) { send_data = net_packet_ready; if (net_packet_ready) { INFO("Transmitting packet\n",0); } } else { INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs.tbs); for (i=0;i<pdsch_cfg.grant.mcs.tbs/8;i++) { data[i] = rand()%256; } /* Uncomment this to transmit on sf 0 and 5 only */ if (sf_idx != 0 && sf_idx != 5) { send_data = true; } else { send_data = false; } }
if (send_data) {
/* Encode PDCCH */ srslte_dci_msg_pack_pdsch(&ra_dl, &dci_msg, SRSLTE_DCI_FORMAT1, cell.nof_prb, false); INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { fprintf(stderr, "Error encoding DCI message\n"); exit(-1); }
/* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, true, &grant); if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); }
/* Encode PDSCH */ if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, sf_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); exit(-1); } if (net_port > 0 && net_packet_ready) { if (null_file_sink) { srslte_bit_pack_vector(data, data_tmp, pdsch_cfg.grant.mcs.tbs); if (srslte_netsink_write(&net_sink, data_tmp, 1+(pdsch_cfg.grant.mcs.tbs-1)/8) < 0) { fprintf(stderr, "Error sending data through UDP socket\n"); } } net_packet_ready = false; sem_post(&net_sem); } }
/* Transform to OFDM symbols */ srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer);
/* send to file or usrp */ if (output_file_name) { if (!null_file_sink) { srslte_filesink_write(&fsink, output_buffer, sf_n_samples); } usleep(1000); } else { #ifndef DISABLE_RF // FIXME float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); srslte_vec_sc_prod_cfc(output_buffer, rf_amp*norm_factor, output_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); srslte_rf_send2(&rf, output_buffer, sf_n_samples, true, start_of_burst, false); start_of_burst=false; #endif } } nf++; sfn = (sfn + 1) % 1024; }
base_free();
printf("Done\n"); exit(0); }
Result :-------------------------------------------------------------------------------------
Now let's generate a downlink frames as below. You can put the option values as you like. With the following command, a downlink frame with the length of 10 radio frames (100 subframes) and MCS = 9
# ~/srsLTE/build/srslte/examples$ ./pdsch_enodeb -o "pdsch.out" -n 10 -m 9
linux; GNU C++ version 5.3.1 20160413; Boost_105800; UHD_003.009.004-release
- Resource Allocation Type: Type 0 + Resource Block Group Size: 2 + RBG Bitmap: 0x1fff - Modulation and coding scheme index: 9 - HARQ process: 0 - New data indicator: No - Redundancy version: 0 - TPC command for PUCCH: -- - PRB Bitmap Assignment 0st slot: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - PRB Bitmap Assignment 1st slot: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - Number of PRBs: 25 - Modulation type: QPSK - Transport block size: 4008 Type new MCS index and press Enter: Done root@root-VirtualBox:~/srsLTE/build/srslte/examples$ ./pdsch_ue -i "pdsch.out" -n 10 -r 1234 linux; GNU C++ version 5.3.1 20160413; Boost_105800; UHD_003.009.004-release
- Cell ID: 0 - Nof ports: 1 - CP: Normal - PRB: 25 - PHICH Length: Normal - PHICH Resources: 1 - SFN: 0 Decoded MIB. SFN: 0, offset: 0 CFO: +0.00 kHz, SNR: 139.3 dB, PDCCH-Miss: 20.00%, PDSCH-BLER: 0.00% Bye
|